This Quick Start guide shows you how to configure your .net applications to send OpenTelemetry traces to Cloud Observability.
This guide does not provide documentation on application instrumentation. For .net-specific information on instrumentation, please see the .net OpenTelemetry getting started guide.
Sending OpenTelemetry data directly to Cloud Observability without a Collector for most developer setups will suffice. For non-development setups, however, it is highly recommended that you send OpenTelemetry data to Cloud Observability by way of the OpenTelemetry Collector. This can be done with or without a Launcher, as we’ll see below.
The sections below contain code snippets only. For full code listings, please see open-telemetry/opentelemetry-dotnet
and open-telemetry/opentelemetry-dotnet-contrib
in the OpenTelemetry GitHub .NET repos.
Before you get started with sending OpenTelemetry data to Cloud Observability, you will need the following:
In your application code, you will need to install dependencies and import OpenTelemetry packages before you can send data to Cloud Observability.
Start by installing the OpenTelemetry Nuget packages.
Start tabs
Console App
1
2
3
dotnet add package OpenTelemetry --version 1.4.0-alpha.2
dotnet add package OpenTelemetry.Exporter.Console --version 1.4.0-alpha.2
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol --version 1.4.0-alpha.2
.NET Core App
1
2
3
4
5
dotnet add package OpenTelemetry --version 1.4.0-alpha.2
dotnet add package OpenTelemetry.Exporter.Console --version 1.4.0-alpha.2
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol --version 1.4.0-alpha.2
dotnet add package OpenTelemetry.Extensions.Hosting --version 1.0.0-rc9.6
dotnet add package OpenTelemetry.Instrumentation.Http --version 1.0.0-rc9.6
End tabs
Where:
OpenTelemetry
is the OpenTelemetry SDK, a reference implementation of the OpenTelemetry API.OpenTelemetry.Exporter.Console
outputs traces to the console during development.OpenTelemetry.Exporter.OpenTelemetryProtocol
exports traces to Cloud Observability or the OpenTelemetry Collector using the OpenTelemetry Protocol (OTLP).OpenTelemetry.Extensions.Hosting
is used to register the .NET OpenTelemetry provider (.NET Core only)If you are using a .csproj
file, your dependencies would look like this:
Start tabs
Console App
1
2
3
4
5
6
7
8
9
...
<ItemGroup>
...
<PackageReference Include="OpenTelemetry" Version="1.4.0-alpha.2" />
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.4.0-alpha.2" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.4.0-alpha.2" />
...
</ItemGroup>
...
.NET Core App
1
2
3
4
5
6
7
8
9
10
11
...
<ItemGroup>
...
<PackageReference Include="OpenTelemetry" Version="1.4.0-alpha.2" />
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.4.0-alpha.2" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.4.0-alpha.2" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.0.0-rc9.6" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.0.0-rc9.6" />
...
</ItemGroup>
...
End tabs
Before you can start sending OpenTelemetry data to Cloud Observability, you will need to:
Now that you’ve installed the OpenTelemetry packages, you will need to import them in your application code.
Open up your application code, and add the following imports to your .cs
file:
Start tabs
Console App
1
2
3
using OpenTelemetry;
using OpenTelemetry.Trace;
using OpenTelemetry.Resources;
.NET Core App
1
2
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
End tabs
The code snippet below shows how to configure OpenTelemetry for both a Console application and an .NET Core application.
Start tabs
Console App
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
...
// Define some important constants to initialize tracing with
var serviceName = "MyCompany.MyProduct.MyService";
var serviceVersion = "1.0.0";
// Configure important OpenTelemetry settings and the console exporter
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddOtlpExporter(opt =>
{
opt.Endpoint = new Uri("ingest.lightstep.com:443"); //US data center
// opt.Endpoint = new Uri("ingest.eu.lightstep.com:443"); //EU data center
opt.Headers = new Metadata
{
{ "lightstep-access-token", Environment.GetEnvironmentVariable("LS_ACCESS_TOKEN")}
};
opt.Credentials = new SslCredentials();
})
.AddSource(serviceName)
.SetResourceBuilder(
ResourceBuilder.CreateDefault()
.AddService(serviceName: serviceName,serviceVersion: serviceVersion))
.Build();
var MyActivitySource = new ActivitySource(serviceName);
...
.NET Core App
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
...
var serviceName = "MyCompany.MyProduct.MyService";
var serviceVersion = "1.0.0";
var builder = WebApplication.CreateBuilder(args);
// Configure to send data via the OTLP exporter.
// By default, it will send to port 4318, which the collector is listening on.
builder.Services.AddOpenTelemetryTracing(tracerProviderBuilder =>
{
tracerProviderBuilder
.AddOtlpExporter(opt =>
{
opt.Endpoint = new Uri("ingest.lightstep.com:443"); //US data center
// opt.Endpoint = new Uri("ingest.eu.lightstep.com:443"); //EU data center
opt.Headers = new Metadata
{
{ "lightstep-access-token", Environment.GetEnvironmentVariable("LS_ACCESS_TOKEN")}
};
opt.Credentials = new SslCredentials();
})
.AddSource(serviceName)
.SetResourceBuilder(
ResourceBuilder.CreateDefault()
.AddService(serviceName: serviceName, serviceVersion: serviceVersion))
.AddHttpClientInstrumentation()
.AddAspNetCoreInstrumentation();
});
var app = builder.Build();
...
End code tabs
More on OtlpExporter
configuration can be found here
LS_ACCESS_TOKEN
environment variable Cloud Observability access token before running your application: export LS_ACCESS_TOKEN=<LS_ACCESS_TOKEN>
.AddOtlpExporter
sets up OpenTelemetry to send data to Cloud Observability using the OpenTelemetry Protocol (OTLP). I recommend sticking with OTLP in your clients.SetResourceBuilder
creates resources: key-value pairs which describe your service. It’s important to add as many relevant resources as you can, as this improves the quality of your tracing data. See Semantic Conventions for ideas on what to add. The two that are most important to add are service.name
and service.version
. If you don’t name your service, it will get named unknown_service
by default.AddAspNetCoreInstrumentation()
enables .NET Core instrumentation. This does not apply to Console applications.AddHttpClientInstrumentation()
enables instrumentation for HTTP requests. If you want to instrument gRPC requests instead, use AddGrpcClientInstrumentation()
.It is important to add instrumentation for every supported library. You can find all of the available instrumentation here.
To use HTTP instead of gRPC, the AddOtlpExporter
configuration would be altered as follows:
1
2
3
4
5
6
7
8
9
10
.AddOtlpExporter(opt =>
{
opt.Endpoint = new Uri("https://ingest.lightstep.com/traces/otlp/v0.9"); //US data center
// opt.Endpoint = new Uri("https://ingest.eu.lightstep.com/traces/otlp/v0.9"); //EU data center
opt.Headers = new Metadata
{
{ "lightstep-access-token", Environment.GetEnvironmentVariable("LS_ACCESS_TOKEN")}
};
opt.Credentials = new SslCredentials();
})
More info on using OtlpExportProtocol.HttpProtobuf
can be found here.
If you wish to use an OpenTelemetry Collector, the configuration for AddOtlpExporter
would look like this:
Start tabs
Collector (gRPC)
1
2
3
4
5
6
...
.AddOtlpExporter(opt =>
{
opt.Endpoint = new Uri("http://0.0.0.0:4317");
})
...
Collector (HTTP)
1
2
3
4
5
6
7
...
.AddOtlpExporter(opt =>
{
opt.Protocol = OtlpExportProtocol.HttpProtobuf;
opt.Endpoint = new Uri("http://0.0.0.0:4318/v1/traces");
})
...
Noteworthy items:
opt.Protocol
is not specified, the default value is OtlpExportProtocol.Grpc
.OtlpExportProtocol.HttpProtobuf
can be found here.End code tabs
Symptom
Operation names in Cloud Observability are not clear or are very long and unhelpful.
This feature requires a Satellite upgrade to the June 2020 release.
This can happen because the auto-installer is getting the name from a parameter in Datadog that might not be appropriate for your language. You can set that parameter to different values to see if that results in better operation names.
You can use either the resource
or the name
parameter, or both.
Which to use (or if using the both, the order to use) depends on the language of the installer. Refer to the Datadog docs for more info.
To configure how the operation name is set, add the following parameter to your Microsatellite configuration:
1
2
3
4
5
receivers:
datadog:
operation_name_extractors:
- resource
- name
If you set both, the order of the values matters. Cloud Observability tries to extract a name from the first variable value. If one isn’t found, it looks for the second value and uses that.
If multiple versions of OpenTelemetry are installed, traces are not created or propagated correctly. Check your dependencies to ensure that only a single version of OpenTelemetry is installed.
Cloud Observability’s public Microsatellites only accept spans via a secure endpoint. If you see security related errors (e.g., Netty TLS errors with Java), you may not have the necessary root certificate installed on the machine where the tracer is running. To add a root certificate, see the documentation about encrypted connections.
Not seeing metrics come through the OpenTelemetry Collector? Make sure that you have defined a Metrics pipeline in your Collector’s YAML config file.
Send traces to Cloud Observability with Python
Send traces to Cloud Observability with Java
Send traces to Cloud Observability with Node.JS
Updated Sep 20, 2022