diff --git a/src/data/nav.yml b/src/data/nav.yml index a27b518c3..c28d31545 100644 --- a/src/data/nav.yml +++ b/src/data/nav.yml @@ -27,6 +27,15 @@ url: '/collect-data/pixie/scenario-1' - title: Debug latency in the TinyHat admin url: '/collect-data/pixie/scenario-2' + - title: Instrument your application with OpenTelemetry + url: '/collect-data/opentelemetry' + pages: + - title: Set up your lab environment + url: '/collect-data/opentelemetry/set-up-env' + - title: Instrument your app with Open Telemetry + url: '/collect-data/opentelemetry/instrument' + - title: View your OpenTelemetry data in New Relic + url: '/collect-data/opentelemetry/view' - title: Automate workflows icon: nr-automation url: '/automate-workflows' diff --git a/src/images/opentelemetry/dt.png b/src/images/opentelemetry/dt.png new file mode 100644 index 000000000..9558ea2ba Binary files /dev/null and b/src/images/opentelemetry/dt.png differ diff --git a/src/images/opentelemetry/metrics-explorer.png b/src/images/opentelemetry/metrics-explorer.png new file mode 100644 index 000000000..07fccd2c9 Binary files /dev/null and b/src/images/opentelemetry/metrics-explorer.png differ diff --git a/src/images/opentelemetry/otel-data.png b/src/images/opentelemetry/otel-data.png new file mode 100644 index 000000000..799d1c574 Binary files /dev/null and b/src/images/opentelemetry/otel-data.png differ diff --git a/src/images/opentelemetry/service.png b/src/images/opentelemetry/service.png new file mode 100644 index 000000000..74103c12b Binary files /dev/null and b/src/images/opentelemetry/service.png differ diff --git a/src/images/opentelemetry/span-details.png b/src/images/opentelemetry/span-details.png new file mode 100644 index 000000000..92c97413b Binary files /dev/null and b/src/images/opentelemetry/span-details.png differ diff --git a/src/images/opentelemetry/spans.png b/src/images/opentelemetry/spans.png new file mode 100644 index 000000000..f2427d4a1 Binary files /dev/null and b/src/images/opentelemetry/spans.png differ diff --git a/src/images/opentelemetry/trace-group.png b/src/images/opentelemetry/trace-group.png new file mode 100644 index 000000000..bfea5ca2e Binary files /dev/null and b/src/images/opentelemetry/trace-group.png differ diff --git a/src/images/opentelemetry/trace.png b/src/images/opentelemetry/trace.png new file mode 100644 index 000000000..f5d68a743 Binary files /dev/null and b/src/images/opentelemetry/trace.png differ diff --git a/src/markdown-pages/collect-data/opentelemetry/index.mdx b/src/markdown-pages/collect-data/opentelemetry/index.mdx new file mode 100644 index 000000000..1035df7a4 --- /dev/null +++ b/src/markdown-pages/collect-data/opentelemetry/index.mdx @@ -0,0 +1,40 @@ +--- +path: '/collect-data/opentelemetry' +title: 'Instrument and Analyze OpenTelemetry data' +template: 'LabOverviewTemplate' +description: 'Instrument and Analyze OpenTelemetry data' +--- + + + +You're a developer who recently released a simple .NET weather forecast application to the world, and people can't stop talking about it! Surprised by the spike in popularity, you decided you should start collecting metrics and traces from your application so you can analyze them in New Relic. + +You first thought about using our [.NET agent](https://docs.newrelic.com/docs/apm/agents/net-agent/), but before going through the efforts of setting that up, you heard about the ["future of instrumentation"](https://newrelic.com/blog/best-practices/what-is-opentelemetry), called OpenTelemetry, and you decided to reconsider. + +OpenTelemetry is a standard for how to collect and send telemetry data to any backend observability platform. It's open source, flexible, and ubiquitous. Convinced that OpenTelemetry is indeed the future, you set off to use it in your application. + + + +
+ +
+ +## Objectives + +- Instrument a .NET application with OpenTelemetry +- Analyze the telemetry data in New Relic + +
+ +
+ +## Requirements + +- A free [New Relic account](https://newrelic.com/signup?utm_source=developer-site) +- The [.NET SDK](https://dotnet.microsoft.com/download) + +
+ +
+ +
diff --git a/src/markdown-pages/collect-data/opentelemetry/instrument.mdx b/src/markdown-pages/collect-data/opentelemetry/instrument.mdx new file mode 100644 index 000000000..57b229437 --- /dev/null +++ b/src/markdown-pages/collect-data/opentelemetry/instrument.mdx @@ -0,0 +1,405 @@ +--- +path: '/collect-data/opentelemetry/instrument' +duration: 5 +title: 'Instrument your application with OpenTelemetry' +template: 'GuideTemplate' +description: 'Auto-instrument your application with the OpenTelemetry .NET SDK' +procIdx: 2 +--- + + + + + +```jsx fileName=app/Program.cs +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddControllers(); +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); +``` + + + + + +This procedure is part of a lab that teaches you how to instrument your application with OpenTelemetry. + +Each procedure in the lab builds upon the last, so make sure you've completed the last procedure, [_Set up your lab environment_](/collect-data/opentelemetry/set-up-env), before starting this one. + + + +Your .NET application is running and is getting a lot of traffic. You want to instrument it with OpenTelemetry because it lets you avoid being locked into a single vendor, it's open source, and it's supported by many actors in the observability space. + +Here, you learn how easy it is to configure the [OpenTelemetry SDK](https://github.com/open-telemetry/opentelemetry-dotnet) to automatically collect metrics and traces from your application and send them to New Relic so you can analyze the results later. + +## Instrument your application + + + + + +In the terminal window that's running your development server, press ``. + +You should see your server shut down. Now you can add some dependencies and update your app logic. + + + + + +Add the OpenTelemetry SDK and supporting packages: + +<> + +```bash +dotnet add app package --prerelease OpenTelemetry +dotnet add app package --prerelease OpenTelemetry.Instrumentation.AspNetCore +dotnet add app package --prerelease OpenTelemetry.Exporter.OpenTelemetryProtocol +dotnet add app package --prerelease OpenTelemetry.Extensions.Hosting +``` + + + + + + + +Create two environment variables that you use to configure your OpenTelemetry pipelines: + +<> + +```bash +export OTEL_EXPORTER_OTLP_ENDPOINT= +export NR_LICENSE_KEY= +``` + +The [OpenTelemetry Protocol](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md) (OTLP) endpoint is the url of our OpenTelemetry receiver. Your service sends data directly to New Relic through this endpoint. [We have a US endpoint and an EU endpoint](https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/opentelemetry-quick-start/#review-settings), so make sure you choose the appropriate one based on your region. + +There are several different types of API keys to choose from in New Relic that each serve a different purpose. To instrument your application with OpenTelemetry, you need a [license key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#ingest-license-key). + + + + + + + +In _app/Program.cs_, create a resource builder: + +<> + +```jsx fileName=app/Program.cs +using OpenTelemetry.Resources; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddControllers(); +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var resourceBuilder = ResourceBuilder + .CreateDefault() + .AddService("Weather-Forecast") + .AddAttributes(new Dictionary { + { "environment", "production" } + }) + .AddTelemetrySdk(); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); +``` + + + +
+ +An [OpenTelemetry resource](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/sdk.md) describes a service as a collection of attributes. + +Here, on top of the default resource attributes, you define a service name and an environment. You also call `AddTelemetrySdk()`, which adds a suite of standard attributes defined within OpenTelemetry's sematic conventions such as: + +- `telemetry.sdk.name` +- `telemetry.sdk.language` +- `telemetry.sdk.version` + +This is important because it helps New Relic present you with an experience that's tailored to your application. + +You configure your telemetry pipelines with this resource builder. That way, these attributes are associated with all metrics and traces that this service generates. + +
+ + + +Configure the OpenTelemetry SDK for [traces](https://docs.newrelic.com/docs/apm/transactions/transaction-traces/introduction-transaction-traces/): + +<> + +```jsx fileName=app/Program.cs +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddControllers(); +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var resourceBuilder = ResourceBuilder + .CreateDefault() + .AddService("Weather-Forecast") + .AddAttributes(new Dictionary { + { "environment", "production" } + }) + .AddTelemetrySdk(); + +builder.Services.AddOpenTelemetryTracing(tracerProviderBuilder => +{ + tracerProviderBuilder + .SetResourceBuilder(resourceBuilder); + + tracerProviderBuilder + .AddAspNetCoreInstrumentation(options => + { + options.RecordException = true; + options.Filter = (context) => + { + return context.Request.Method == "GET"; + }; + }); + + tracerProviderBuilder + .AddSource("WeatherForecast"); + + tracerProviderBuilder + .AddOtlpExporter(options => + { + options.Endpoint = new Uri($"{Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT")}"); + options.Headers = $"api-key={Environment.GetEnvironmentVariable("NR_LICENSE_KEY")}"; + }); +}); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); +``` + + + +
+ +`AddOpenTelemetryTracing()` takes a delegate that builds a tracer provider that, in turn, automatically provides traces to your OpenTelemetry exporter. + +First in configuring your tracer, you specify the resource builder you created in the last step. This ties the attributes you previously defined to all traces from your service. Next, with `tracerProviderBuilder.AddAspNetCoreInstrumentation()`, you configure the SDK to listen to auto-instrumentation. You also tell it to record exceptions and only track GET requests. Finally, you configure the OTLP exporter to export traces to New Relic using the environment variables you defined earlier. + +
+ + + +Configure the OpenTelemetry SDK for [metrics](https://docs.newrelic.com/docs/data-apis/understand-data/new-relic-data-types/#metrics): + +<> + +```jsx fileName=app/Program.cs +using OpenTelemetry.Metrics; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddControllers(); +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var resourceBuilder = ResourceBuilder + .CreateDefault() + .AddService("Weather-Forecast") + .AddAttributes(new Dictionary { + { "environment", "production" } + }) + .AddTelemetrySdk(); + +builder.Services.AddOpenTelemetryTracing(tracerProviderBuilder => +{ + tracerProviderBuilder + .SetResourceBuilder(resourceBuilder); + + tracerProviderBuilder + .AddAspNetCoreInstrumentation(options => + { + options.RecordException = true; + options.Filter = (context) => + { + return context.Request.Method == "GET"; + }; + }); + + tracerProviderBuilder + .AddSource("WeatherForecast"); + + tracerProviderBuilder + .AddOtlpExporter(options => + { + options.Endpoint = new Uri($"{Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT")}"); + options.Headers = $"api-key={Environment.GetEnvironmentVariable("NR_LICENSE_KEY")}"; + }); +}); + +builder.Services.AddOpenTelemetryMetrics(meterProviderBuilder => +{ + meterProviderBuilder + .SetResourceBuilder(resourceBuilder); + + meterProviderBuilder + .AddAspNetCoreInstrumentation(); + + meterProviderBuilder + .AddOtlpExporter(options => + { + options.Endpoint = new Uri($"{Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT")}"); + options.Headers = $"api-key={Environment.GetEnvironmentVariable("NR_LICENSE_KEY")}"; + options.AggregationTemporality = AggregationTemporality.Delta; + }); +}); + +var app = builder.Build(); + +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.UseAuthorization(); + +app.MapControllers(); + +app.Run(); +``` + + + +
+ +Besides configuring a `MetricsProviderBuilder`, this is mostly the same as how you configured tracing. + +There is one important detail, however. Currently, New Relic only supports sending metrics over OTLP using [delta aggregation temporality](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/datamodel.md#temporality). The SDK's default aggregation temporality is cumulative, so you specify `Delta` here. + +
+ +
+ +
+ +## Restart your application + +Now that you've changed the application logic, you need to restart your local server. Make sure you do this in the same terminal window where you set your environment variables. + + + + + +Restart it: + +<> + +```bash +dotnet restore app +dotnet build app +dotnet run --project app +[output] +[output] Determining projects to restore... +[output] All projects are up-to-date for restore. +[output] Microsoft (R) Build Engine version 17.0.0+c9eb9dd64 for .NET +[output] Copyright (C) Microsoft Corporation. All rights reserved. +[output] +[output] Determining projects to restore... +[output] All projects are up-to-date for restore. +[output] opentelemetry-dotnet-lab-materials -> /workspace/opentelemetry-dotnet-lab-materials/app/bin/Debug/net6.0/app.dll +[output] +[output] {success}Build succeeded. +[output] 0 Warning(s) +[output] 0 Error(s) +[output] +[output] Time Elapsed 00:00:01.16 +[output] Building... +[output] {green}info: {plain}Microsoft.Hosting.Lifetime[14] +[output] Now listening on: {blue}https://localhost:7072 +[output] {green}info: {plain}Microsoft.Hosting.Lifetime[0] +[output] Application started. Press Ctrl+C to shut down. +[output] {green}info: {plain}Microsoft.Hosting.Lifetime[0] +[output] Hosting environment: Development +[output] {green}info: {plain}Microsoft.Hosting.Lifetime[0] +[output] Content root path: /workspace/opentelemetry-dotnet-lab-materials/app/ +[output] {green}info: {plain}Microsoft.Hosting.Lifetime[0] +``` + +Now, your server is running again. However, because you shut it down, your load generator might have failed, having been unable to find your app. If it's no longer running, restart that too. + + + + + + + +In the terminal window where you ran your load generator, restart it: + +<> + +```bash +python simulator.py +``` + + + + + + + +You've instrumented your application to send metrics and traces to New Relic using our OTLP receiver. You've also restarted your service and load generator. Now, it's time to view your data. + + + +This procedure is part of a lab that teaches you how to instrument your application with OpenTelemetry. Now that you've set up your environment, [view your telemetry data in New Relic](/collect-data/opentelemetry/view). + + diff --git a/src/markdown-pages/collect-data/opentelemetry/setup.mdx b/src/markdown-pages/collect-data/opentelemetry/setup.mdx new file mode 100644 index 000000000..874ca35c3 --- /dev/null +++ b/src/markdown-pages/collect-data/opentelemetry/setup.mdx @@ -0,0 +1,130 @@ +--- +path: '/collect-data/opentelemetry/set-up-env' +duration: 5 +title: 'Set up your lab environment' +template: 'GuideTemplate' +description: 'Spin up your weather forecast application and simulator' +procIdx: 1 +--- + + + +This procedure is part of a lab that teaches you how to instrument your application with OpenTelemetry. If you haven't already, check out the [lab introduction](/collect-data/opentelemetry). + + + +Before you can walk through the lab proper, you need to set up your development environment. Here, you: + +1. Spin up your .NET application +2. Send traffic to your app with a simple load generator + + + + + +Clone the lab repository: + +<> + +```bash +git clone https://github.com/newrelic-experimental/opentelemetry-dotnet-lab-materials +``` + + + + + + + +Restore dependencies, build, and run the application: + +<> + +```bash +cd opentelemetry-dotnet-lab-materials +dotnet restore app +dotnet build app +dotnet run --project app +``` + + + +In the output, you see a url for your app: + +<> + +```bash +[output] Determining projects to restore... +[output] All projects are up-to-date for restore. +[output] Microsoft (R) Build Engine version 17.0.0+c9eb9dd64 for .NET +[output] Copyright (C) Microsoft Corporation. All rights reserved. +[output] +[output] Determining projects to restore... +[output] All projects are up-to-date for restore. +[output] opentelemetry-dotnet-lab-materials -> /workspace/opentelemetry-dotnet-lab-materials/app/bin/Debug/net6.0/opentelemetry-dotnet-lab-materials.dll +[output] +[output] {success}Build succeeded. +[output] 0 Warning(s) +[output] 0 Error(s) +[output] +[output] Time Elapsed 00:00:01.42 +[output] Building... +[output] {success}info: {plain}Microsoft.Hosting.Lifetime[14] +[output] Now listening on: {blue}https://localhost:7072 +[output] {success}info: {plain}Microsoft.Hosting.Lifetime[0] +[output] Application started. Press Ctrl+C to shut down. +[output] {success}info: {plain}Microsoft.Hosting.Lifetime[0] +[output] Hosting environment: Development +[output] {success}info: {plain}Microsoft.Hosting.Lifetime[0] +[output] Content root path: /workspace/opentelemetry-dotnet-lab-materials/app/ +``` + + + +The application has a single endpoint at `/WeatherForcast`, which you can visit in your browser or with curl: + +<> + +```bash +curl -k https://localhost:7072/WeatherForecast +[output] [{"date":"2021-11-18T16:03:02.655159-05:00","temperatureC":38,"temperatureF":100,"summary":"Chilly"},{"date":"2021-11-19T16:03:02.655161-05:00","temperatureC":-3,"temperatureF":27,"summary":"Mild"},{"date":"2021-11-20T16:03:02.655162-05:00","temperatureC":-8,"temperatureF":18,"summary":"Hot"},{"date":"2021-11-21T16:03:02.655162-05:00","temperatureC":3,"temperatureF":37,"summary":"Cool"},{"date":"2021-11-22T16:03:02.655162-05:00","temperatureC":10,"temperatureF":49,"summary":"Warm"}] +``` + + + + + +You use the `-k` option to instruct curl to not verify the site's SSL certification. This is fine because you're making a request against localhost. + + + +Leave this open so you can simulate requests against it. + + + + + +In another terminal window, run the load generator: + +<> + +```bash +cd opentelemetry-dotnet-lab-materials/sim +pip install requests +python simulator.py +``` + + + + + + + +Now that you've got your application and load generator running, it's time to see what OpenTelemetry's all about. + + + +This procedure is part of a lab that teaches you how to instrument your application with OpenTelemetry. Now that you've set up your environment, [instrument your application](/collect-data/opentelemetry/instrument). + + + diff --git a/src/markdown-pages/collect-data/opentelemetry/view.mdx b/src/markdown-pages/collect-data/opentelemetry/view.mdx new file mode 100644 index 000000000..c123a6bab --- /dev/null +++ b/src/markdown-pages/collect-data/opentelemetry/view.mdx @@ -0,0 +1,122 @@ +--- +path: '/collect-data/opentelemetry/view' +duration: 5 +title: 'View your OpenTelemetry data in New Relic' +template: 'GuideTemplate' +description: 'View your OpenTelemetry data in New Relic' +procIdx: 3 +--- + + + +This procedure is part of a lab that teaches you how to instrument your application with OpenTelemetry. + +Each procedure in the lab builds upon the last, so make sure you've completed the last procedure, [_Instrument your application with OpenTelemetry_](/collect-data/opentelemetry/instrument), before starting this one. + + + +You've instrumented your weather forecast application with OpenTelemetry and you're sending metric and trace data to New Relic. + +Here, you move to New Relic to see the kinds of detailed telemetry data that OpenTelemetry was able to collect automatically with just a few lines of SDK code. + +## View your data + + + + + +Log into [New Relic](https://one.newrelic.com). + + + + + +In the entity explorer, click the **Weather-Forecast** OpenTelemetry service: + +![Click Weather Forecast service in the entity explorer](../../../images/opentelemetry/service.png) + +This brings you to a service view that shows trace data from your application, including: + +- Response time +- Throughput +- Error rate + +![OpenTelemetry data on service view](../../../images/opentelemetry/otel-data.png) + + + + + +In the left-hand navigation, click **Distributed tracing**: + +![Distributed tracing view](../../../images/opentelemetry/dt.png) + +This shows trace data that the OpenTelemetry SDK automatically captured in your service, such as: + +- Trace count +- Trace duration +- Trace groups + + + + + +Under **Trace groups** click the **WeatherForecast** group: + +![Trace group view](../../../images/opentelemetry/trace-group.png) + +This group shows similar traces. Since your application has only one endpoint, all traces are grouped together. + + + + + +Click one of the traces: + +![Trace view](../../../images/opentelemetry/trace.png) + +Because your weather application is simple, there is only one span in the trace. + + + + + +Click on the span: + +![Trace spans view](../../../images/opentelemetry/spans.png) + +Here, you see information about the particular span, including not only performance metrics, but also attributes that OpenTelemetry sent. + + + + + +Click **Attributes**: + +![Span detail view](../../../images/opentelemetry/span-details.png) + +You configured many of the attributes you see here in your SDK code. + + + + + +While New Relic doesn't yet have a curated experience for .NET OpenTelemetry metrics data, you can see the metrics in the metrics explorer: + +![Metrics explorer](../../../images/opentelemetry/metrics-explorer.png) + + + + + +## Summary + +As the developer of WeatherForecast, you've now instrumented your application with OpenTelemetry to send automatically collected metrics and traces to New Relic. And because you instrumented your app with OpenTelemetry instead of a .NET agent, you are more flexible in how you can use your data. For example, if you want to add additional backend data sources besides New Relic, you can easily change that without having to add another vendor-specific agent. + +## Homework + +Now that you know how to instrument a .NET application with OpenTelemetry and send that data to New Relic, here are some things you can do next to familiarize yourself even more with New Relic and OpenTelemetry: + +- Check out our [repository of OpenTelemetry examples](https://github.com/newrelic/newrelic-opentelemetry-examples) +- Learn more about [OpenTelemetry's .NET SDK](https://github.com/open-telemetry/opentelemetry-dotnet) +- Read our [documentation on New Relic + OpenTelemetry](https://docs.newrelic.com/docs/more-integrations/open-source-telemetry-integrations/opentelemetry/introduction-opentelemetry-new-relic/)