Adding Code Tags to Your OpenTelemetry Spans

In this article, I’m going to walk you through adding attributes to your spans in .NET that contain information about the code that generated the span. We’ll also look at ways to do this automatically using a library I’ve created.

What is OpenTelemetry?

OpenTelemetry is an amazing project that provides a standardized way of sending telemetry information between your services, and also to systems that can visualize that information (referred to as Telemetry Analysis tools or Backends).

What are Span Attributes?

One of the reasons that OpenTelemetry is great at doing this is that a lot of the common attributes you may find on a span are given standard names, so the systems receiving the data to visualize them, don’t need to know the specifics of your system. This is really a superpower of OpenTelemetry, as it gives a level playing field for consumers of that information—meaning that you, as a developer, can forget about vendor-specific things.

Some examples of this are when you’re working with a HTTP API. The URL will be http.url, the method will be http.method and the status code will be in http.status_code.

This allows the visualization system to show cool things. It knows more about your system from day one, as you can see from this example of the Honeycomb environment dashboard.

What I’m referring to here, however, are the attributes that specifically relate to the code information. These all sit under the prefix code.* in the trace semantic conventions documentation on

What do the code attributes give us?

On their own, code attributes will give you information about the code that produced the data. This, in and of itself, is useful. The things that are currently defined in the OTel specification are:

  • code.lineno which should point to a line number
  • code.filepath which should point to a file for the file that generated the span
  • code.function which should by the name of the calling function

These are pretty generic and obviously built to be language-agnostic.

How can we add the attributes in .NET?

Within the .NET framework, we have access to a few methods that will provide this information in a managed way. These are part of the Caller Information attributes that the framework gives us.

We can create a single static method that will give us all the information:

public static (string filepath, int lineno, string function)
            [CallerFilePath] string filePath = "",
            [CallerLineNumber] int lineno = -1,
            [CallerMemberName] string function = "")
         => (filePath, lineno, function);

This will provide a Tuple back with the file path, the line number that called the method, and the name of the function.

We can then use this method to extract the attributes and apply them to the span:

using var span = ActivityHelper.Fibonacci.StartActivity("calculation");
    var (filepath, lineno, function) = CodeInfo();
    span?.AddTag("code.function", function);
    span?.AddTag("code.lineno", lineno - 2);
    span?.AddTag("code.filepath", filepath);

Note: the line number is actually reduced by 2 as there is an offset, and we want to represent the line number of the span creation, not the line number of the line where we get the code information.

This will give you some attributes that look like this:

That can be incredibly useful when trying to pinpoint the issues in your code from your tracing.

Adding code attributes automatically

As we’ve established in the above section, code attributes are really useful. Adding the code manually every time you use Activity APIs would be error-prone and noise in the code.

I’ve created a package, using source generators, that will automatically augment your manual instrumentation with those code attributes.

To use this, you install the NuGet package:

dotnet add package ActivitySourceCodeAttributes --prerelease

That’s it. Now, all the spans you create will automatically have those attributes. As an added bonus, the library will introduce a new attribute called code.url which will contain a link to your repository in GitHub (only the GitHub cloud is supported right now).

Specifically, this url will take you directly to the commit that generated the code that generated the span. This provides some powerful capabilities in the observability backend to drill from the spans right into your code.


Code attributes are really useful and powerful. They can be onerous to add, and will likely be seen as noise in the code by the developers—therefore, automating them is key.

There is now a package that you can install, and it will do all the boilerplate actions for you.

If you’d like to try this out in a lightweight environment, you can spin up a free account in Honeycomb and see the data without any other instructure.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Website Built with

Up ↑

%d bloggers like this: