.NET installation instructions

Use the installation instructions below if you're installing Helios in a standard .NET service.

Get your .NET services auto-instrumented with Helios by following the installation instructions provided below.

Configuring a trace provider

The first step when instrumenting your .NET service is configuring a trace provider to send traces to the Helios backend.

Start by installing the OpenTelemetry dependencies.
From your project's root directory run:

dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
dotnet add package OpenTelemetry.Extensions.Hosting --prerelease
dotnet add package OpenTelemetry.Instrumentation.AspNetCore --prerelease

Note that the --prerelease flag is required for all instrumentation packages because they are all pre-release.
This will also install the OpenTelemetry package.

Now you can define the trace provider by using:

public void ConfigureServices(IServiceCollection services)
{
 
    // ...
    
    services.AddOpenTelemetry().WithTracing(
        (builder) => builder
            .SetResourceBuilder(ResourceBuilder.CreateDefault()
                .AddService("<YOUR-SERVICE-NAME-GOES-HERE>")
                .AddAttributes(new Dictionary<string, object>
                {
                    ["deployment.environment"] = "<ENVIRONMENT-NAME>"
                }))
            .AddOtlpExporter(o =>
            {
                o.Endpoint = new Uri("https://collector.gethelios.dev/v1/traces");
                o.Headers = "Authorization=<YOUR HELIOS TOKEN GOES HERE>";
                o.Protocol = OtlpExportProtocol.HttpProtobuf;
            })
            .AddAspNetCoreInstrumentation() // adding instrumentation of incoming web requests
    );
}

For more information about automatic and manual instrumentation with .NET see the Opentelemetry documentation.

Collecting HTTP request & response payloads

In order to collect HTTP payloads, the following options must be added when setting the .AddAspNetCoreInstrumentation() web instrumentation mentioned above:

// add the following imports
using System.Text.Json;
using Microsoft.AspNetCore.Http.Features;

// configure web requests instrumentation as follows:
.AddAspNetCoreInstrumentation(o =>
    {
        o.EnrichWithHttpRequest = async (activity, httpRequest) =>
            {
                // Request payload

                if (!httpRequest.Body.CanSeek)
                {
                    httpRequest.EnableBuffering();
                }

                httpRequest.Body.Position = 0;

                var reader = new StreamReader(httpRequest.Body, System.Text.Encoding.UTF8);

                var requestBody = await reader.ReadToEndAsync().ConfigureAwait(false);

                httpRequest.Body.Position = 0;

                activity.SetTag("http.request.headers", JsonSerializer.Serialize(httpRequest.Headers));
                activity.SetTag("http.request.body", requestBody);

                // Response payload

                var context = httpRequest.HttpContext;

                var bufferedResponseStream = new MemoryStream();

                var streamResponseBodyFeature = new StreamResponseBodyFeature(
                    bufferedResponseStream,
                    context.Features.Get<IHttpResponseBodyFeature>()!);

                context.Features.Set<IHttpResponseBodyFeature>(streamResponseBodyFeature);

                context.Response.OnStarting(async () =>
                {
                    try
                    {
                        if (bufferedResponseStream.TryGetBuffer(out var data))
                        {
                            string responseBody = System.Text.Encoding.UTF8.GetString(data.Array!, 0, data.Count);
                            activity.SetTag("http.response.headers", JsonSerializer.Serialize(context.Response.Headers));
                            activity.SetTag("http.response.body", responseBody);
                        }
                    }
                    finally
                    {
                        var originalStream = streamResponseBodyFeature.PriorFeature?.Stream;
                        if (originalStream != null)
                        {
                            bufferedResponseStream.Position = 0;
                            await bufferedResponseStream.CopyToAsync(originalStream).ConfigureAwait(false);
                        }
                    }
                });
            };
    }
)

Collecting DB queries from Entity Framework

To collect DB queries from Entity Framework, add the following command to your tracerProviderBuilder initialization:

tracerProviderBuilder.AddEntityFrameworkCoreInstrumentation(options => options.SetDbStatementForText = true)

Collecting Kafka message payloads

To collect Kafka message payloads, do the following:

  1. Install the new Helios Kafka instrumentation dependency dotnet install package HeliosOpenTelemetry.Kafka.Confluent (or add it to your .csproj file).
  2. Add the Helios instrumentation in your code: using HeliosOpenTelemetry.Kafka.Confluent .
  3. When defining the tracerProviderBuilder, you should call AddConfluentKafkaInstrumentation.
  4. When defining the Kafka producer, build it with BuildWithInstrumentation() instead of Build():
using var producer =
        new ProducerBuilder<Null, string>(new ProducerConfig(new ClientConfig { BootstrapServers = kafkaServers }))
            .SetKeySerializer(Serializers.Null)
            .SetValueSerializer(Serializers.Utf8)
            .BuildWithInstrumentation();
  1. When working with the Kafka consumer, perform the consumption using one of the 3 overloads of the method ConsumeWithInstrumentation:
consumer.ConsumeWithInstrumentation((result) =>
    {
        Console.WriteLine(result.Message.Value);
    }, 10000);

Using instrumentation libraries

In order to generate telemetry data for a particular instrumented library you can use instrumentation libraries. For example, the instrumentation library for ASP.NET Core will automatically create spans based on the inbound HTTP requests.

Each instrumentation library is a NuGet package, and installing them is typically done like so:

dotnet add package OpenTelemetry.Instrumentation.{library-name-or-type}

You can then register it when creating the TraceProvider:

public void ConfigureServices(IServiceCollection services)
{
 
    // ...
    
    services.AddOpenTelemetryTracing(
        (builder) => builder
            .SetResourceBuilder(...)
            .AddAspNetCoreInstrumentation()
            .AddHttpClientInstrumentation() // Http client instrumentation for outgoing HTTP calls
            .AddOtlpExporter(o => { ... })
   );
}

๐Ÿ‘

All set

After setup is complete and once the service is up and running, it will show up in the Helios application.