From fdd26581ad775d4007cbda70228727db183dec51 Mon Sep 17 00:00:00 2001 From: Steve Gordon Date: Mon, 9 Dec 2024 11:03:53 +0000 Subject: [PATCH] Update ASP.NET Core documentation --- docs/configuration.asciidoc | 55 ++++++++++++++------------------ docs/packages.asciidoc | 21 +++++------- docs/public-api.asciidoc | 9 ++++-- docs/setup-asp-net-core.asciidoc | 43 ++++++++++++------------- docs/troubleshooting.asciidoc | 23 +++++++++---- 5 files changed, 74 insertions(+), 77 deletions(-) diff --git a/docs/configuration.asciidoc b/docs/configuration.asciidoc index 84fe6f1f0..4d92ac5cd 100644 --- a/docs/configuration.asciidoc +++ b/docs/configuration.asciidoc @@ -6,9 +6,11 @@ endif::[] [[configuration]] == Configuration -Utilize configuration options to adapt the Elastic APM agent to your needs. There are multiple configuration sources, each with different naming conventions for the property key. +Utilize configuration options to adapt the Elastic APM agent to your needs. There are multiple configuration sources, +each with different naming conventions for the property key. -By default, the agent uses environment variables. Additionally, on ASP.NET Core, the agent can plug into the https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.2[Microsoft.Extensions.Configuration] infrastructure. +By default, the agent uses environment variables. Additionally, on ASP.NET Core, the agent plugs +into the https://learn.microsoft.com/aspnet/core/fundamentals/configuration[Microsoft.Extensions.Configuration] infrastructure. [float] [[dynamic-configuration]] @@ -24,47 +26,39 @@ This feature is enabled in the Agent by default, with <>. [[configuration-on-asp-net-core]] === Configuration on ASP.NET Core -The `UseElasticApm()` extension method offers an overload to pass an `IConfiguration` instance to the APM Agent. -To use this type of setup, which is typical in an ASP.NET Core application, your application's `Startup.cs` file should contain code similar to the following: +The `AddElasticApm()` extension method on the `IServiceCollection` automatically accesses configuration bound via +the `Microsoft.Extensions.Configuration` sources. To use this type of setup, which is typical in an ASP.NET Core application, +your application's `Program.cs` file should contain code similar to the following: [source,csharp] ---- -using Elastic.Apm.AspNetCore; +var builder = WebApplication.CreateBuilder(args); -public class Startup -{ - private readonly IConfiguration _configuration; +builder.Services.AddAllElasticApm(); - public Startup(IConfiguration configuration) - { - _configuration = configuration; - } +var app = builder.Build(); - public void Configure(IApplicationBuilder app, IHostingEnvironment env) - { - //Registers the agent with an IConfiguration instance: - app.UseElasticApm(_configuration); +// Configure the HTTP request pipeline. - //Rest of the Configure() method... - } -} +app.Run(); ---- With this setup, the Agent is able to be configured in the same way as any other library in your application. -For example, any configuration source that has been configured on the `IConfiguration` instance being passed to the APM Agent can be used to set Agent configuration values. +For example, any configuration source that has been configured on the `IConfiguration` instance in use in the application + can be used to set Agent configuration values. -More information is available in the official https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1[Microsoft .NET Core configuration docs] +More information is available in the official https://learn.microsoft.com/aspnet/core/fundamentals/configuration[Microsoft .NET Core configuration docs] You can find the key for each APM configuration option in this documentation, under the `IConfiguration or Web.config key` column of the option's description. -NOTE: It is also possible to call `UseElasticApm()` without the overload. In this case, the agent will only read configurations from environment variables. - -NOTE: The `UseElasticApm` method only turns on ASP.NET Core monitoring. To turn on tracing for everything supported by the Agent on .NET Core, including HTTP and database monitoring, use the `UseAllElasticApm` method from the `Elastic.Apm NetCoreAll` package. Learn more in <>. +NOTE: The `AddElasticApm` method only turns on ASP.NET Core monitoring. To turn on tracing for everything supported by the Agent on .NET Core, including HTTP +and database monitoring, use the `AddAllElasticApm` method from the `Elastic.Apm NetCoreAll` package. Learn more in <>. [float] [[sample-config]] ==== Sample configuration file -Here is a sample `appsettings.json` configuration file for a typical ASP.NET Core application that has been activated with `UseElasticApm()`. There are two important takeaways, which are listed as callouts below the example: +Here is a sample `appsettings.json` configuration file for a typical ASP.NET Core application that has been activated with +`AddElasticApm()`. There is one important takeaway, listed as a callout below the example: [source,js] ---- @@ -76,7 +70,7 @@ Here is a sample `appsettings.json` configuration file for a typical ASP.NET Cor } }, "AllowedHosts": "*", - "ElasticApm": <2> + "ElasticApm": { "ServerUrl": "http://myapmserver:8200", "SecretToken": "apm-server-secret-token", @@ -85,9 +79,8 @@ Here is a sample `appsettings.json` configuration file for a typical ASP.NET Cor } ---- <1> With ASP.NET Core, you must set `LogLevel` for the internal APM logger in the standard `Logging` section with the `Elastic.Apm` category name. -<2> The configurations below `ElasticApm` are fetched by the agent if the corresponding `IConfiguration` is passed to the agent. -In certain scenarios--like when you're not using ASP.NET Core--you won't activate the agent with the `UseElasticApm()` method. +In certain scenarios--like when you're not using ASP.NET Core--you won't activate the agent with the `AddElasticApm()` method. In this case, set the agent log level with <>, as shown in the following `appsettings.json` file: [source,js] @@ -1356,9 +1349,9 @@ Sets the logging level for the agent. Valid options: `Critical`, `Error`, `Warning`, `Info`, `Debug`, `Trace` and `None` (`None` disables the logging). -IMPORTANT: The `UseElasticApm()` extension offers an overload to pass an `IConfiguration` instance to the agent. -When configuring your agent in this way, as is typical in an ASP.NET Core application, -you must instead set the `LogLevel` for the internal APM logger under the `Logging` section of `appsettings.json`. More details, including a <> are available in <>. +IMPORTANT: The `AddElasticApm()` extension enables configuration, as is typical in an ASP.NET Core application. +You must instead set the `LogLevel` for the internal APM logger under the `Logging` section of `appsettings.json`. +More details, including a <> are available in <>. [options="header"] |============ diff --git a/docs/packages.asciidoc b/docs/packages.asciidoc index c056a83cd..bcc820594 100644 --- a/docs/packages.asciidoc +++ b/docs/packages.asciidoc @@ -100,13 +100,12 @@ A package containing instrumentation to capture spans for commands sent to redis ==== Quick start Instrumentation can be enabled for Entity Framework Core by referencing {nuget}/Elastic.Apm.EntityFrameworkCore[`Elastic.Apm.EntityFrameworkCore`] package -and passing `EfCoreDiagnosticsSubscriber` to the `UseElasticApm` method in case of ASP.NET Core as following +and passing `EfCoreDiagnosticsSubscriber` to the `AddElasticApm` method in case of ASP.NET Core as following [source,csharp] ---- -app.UseElasticApm(Configuration, new EfCoreDiagnosticsSubscriber()); <1> +app.Services.AddElasticApm(new EfCoreDiagnosticsSubscriber()); ---- -<1> Configuration is the `IConfiguration` instance passed to your `Startup` type or passing `EfCoreDiagnosticsSubscriber` to the `Subscribe` method @@ -159,14 +158,13 @@ as this will register multiple instances, causing multiple database spans to be ==== Quick start Instrumentation can be enabled for Elasticsearch when using the official Elasticsearch clients, Elasticsearch.Net and Nest, by referencing -{nuget}/Elastic.Apm.Elasticsearch[`Elastic.Apm.Elasticsearch`] package and passing `ElasticsearchDiagnosticsSubscriber` to the `UseElasticApm` +{nuget}/Elastic.Apm.Elasticsearch[`Elastic.Apm.Elasticsearch`] package and passing `ElasticsearchDiagnosticsSubscriber` to the `AddElasticApm` method in case of ASP.NET Core as following [source,csharp] ---- -app.UseElasticApm(Configuration, new ElasticsearchDiagnosticsSubscriber()); <1> +app.Services.AddElasticApm(new ElasticsearchDiagnosticsSubscriber()); ---- -<1> Configuration is the `IConfiguration` instance passed to your `Startup` type or passing `ElasticsearchDiagnosticsSubscriber` to the `Subscribe` method @@ -194,13 +192,12 @@ Automatic instrumentation for gRPC can be enabled for both client-side and serve Automatic instrumentation for ASP.NET Core server-side is built in to <> Automatic instrumentation can be enabled for the client-side by referencing {nuget}/Elastic.Apm.GrpcClient[`Elastic.Apm.GrpcClient`] package -and passing `GrpcClientDiagnosticListener` to the `UseElasticApm` method in case of ASP.NET Core +and passing `GrpcClientDiagnosticListener` to the `AddElasticApm` method in case of ASP.NET Core [source,csharp] ---- -app.UseElasticApm(Configuration, new GrpcClientDiagnosticListener()); <1> +app.Services.AddElasticApm(new GrpcClientDiagnosticListener()); ---- -<1> Configuration is the `IConfiguration` instance passed to your `Startup` type or passing `GrpcClientDiagnosticSubscriber` to the `Subscribe` method @@ -211,7 +208,6 @@ Agent.Subscribe(new GrpcClientDiagnosticSubscriber()); Diagnostic events from `Grpc.Net.Client` are captured as spans. - [[setup-sqlclient]] === SqlClient @@ -219,14 +215,13 @@ Diagnostic events from `Grpc.Net.Client` are captured as spans. ==== Quick start You can enable auto instrumentation for `System.Data.SqlClient` or `Microsoft.Data.SqlClient` by referencing {nuget}/Elastic.Apm.SqlClient[`Elastic.Apm.SqlClient`] package -and passing `SqlClientDiagnosticSubscriber` to the `UseElasticApm` method in case of ASP.NET Core as it shown in example: +and passing `SqlClientDiagnosticSubscriber` to the `AddElasticApm` method in case of ASP.NET Core as it shown in example: [source,csharp] ---- // Enable tracing of outgoing db requests -app.UseElasticApm(Configuration, new SqlClientDiagnosticSubscriber()); <1> +app.Services.AddElasticApm(new SqlClientDiagnosticSubscriber()); ---- -<1> Configuration is the `IConfiguration` instance passed to your `Startup` type or passing `SqlClientDiagnosticSubscriber` to the `Subscribe` method and make sure that the code is called only once, otherwise the same database call could be captured multiple times: diff --git a/docs/public-api.asciidoc b/docs/public-api.asciidoc index ce1c26922..fc689de11 100644 --- a/docs/public-api.asciidoc +++ b/docs/public-api.asciidoc @@ -26,7 +26,7 @@ This implicit initialization of the agent happens on the first call on the `Elas NOTE: One exception is the `Elastic.Apm.Agent.IsConfigured` method. This method never initializes the agent, it only checks if the agent is already initialized. -Another example of initialization is when you enable the Agent with one of the technology-specific methods from the <> instructions. Specifically when the `UseElasticApm` or `UseAllElasticApm` method is called in ASP.NET Core or when the IIS module is initialized in an IIS application. +Another example of initialization is when you enable the Agent with one of the technology-specific methods from the <> instructions. Specifically when the `AddElasticApm` or `AddAllElasticApm` method is called in ASP.NET Core or when the IIS module is initialized in an IIS application. The default agent setup should cover most of the use cases and the primary way to configure the agent is through environment variables. @@ -41,7 +41,10 @@ In the AgentComponents you can pass following optional components to the agent: - `IPayloadSender`: A component that receives all the captured events like spans, transactions, and metrics. The default implementation serializes all events and sends them to the Elastic APM Server - `IConfigurationReader`: A component that reads <>. The default implementation reads configuration through environment variables. -NOTE: In the case of ASP.NET Core, when you register the agent, the `UseElasticApm` and the `UseAllElasticApm` methods both implicitly initialize the agent by calling the `Elastic.Apm.Agent.Setup` method internally. In that setup, the `IConfigurationReader` implementation will read configuration from the ASP.NET Core configuration system in case you pass an `IConfiguration` instance to the method. The `IApmLogger` instance will also log through the configured logging provider by integrating into the ASP.NET Core logging system. +NOTE: In the case of ASP.NET Core, when you register the agent, the `AddElasticApm` and the `AddAllElasticApm` methods both implicitly initialize the agent by +calling the `Elastic.Apm.Agent.Setup` method internally. In that setup, the `IConfigurationReader` implementation will read configuration from the ASP.NET Core +configuration system in case you pass an `IConfiguration` instance to the method. The `IApmLogger` instance will also log through the configured logging +provider by integrating into the ASP.NET Core logging system. [float] [[auto-instrumentation-and-agent-api]] @@ -49,7 +52,7 @@ NOTE: In the case of ASP.NET Core, when you register the agent, the `UseElasticA With the `Elastic.Apm.Agent.Subscribe(params IDiagnosticsSubscriber[] subscribers)` method you can turn on auto instrumentation for supported libraries. -In the case of ASP.NET Core, when you turn on the agent with the `UseAllElasticApm` method, the agent will do this automatically. +In the case of ASP.NET Core, when you turn on the agent with the `AddAllElasticApm` method, the agent will do this automatically. With a typical console application, you need to do this manually by calling `Elastic.Apm.Agent.Subscribe(params IDiagnosticsSubscriber[] subscribers)` method somewhere in your application, ideally in diff --git a/docs/setup-asp-net-core.asciidoc b/docs/setup-asp-net-core.asciidoc index 9008a84b1..ec94deef1 100644 --- a/docs/setup-asp-net-core.asciidoc +++ b/docs/setup-asp-net-core.asciidoc @@ -7,44 +7,41 @@ [float] ==== Quick start -[IMPORTANT] --- -We strongly suggest using the approach described in the <>, -to register the agent on the `IServiceCollection`, as opposed to using `IApplicationBuilder` as described below. +For ASP.NET Core, once you reference the {nuget}/Elastic.Apm.NetCoreAll[`Elastic.Apm.NetCoreAll`] package, you can enable auto instrumentation +by calling the `AddAllElasticApm()` extension method on the `IServiceCollection` in the `Program.cs` file. -We keep the `IApplicationBuilder` introduced here only for backwards compatibility. +[NOTE] +-- +The following code sample assumes the instrumentation of a ASP.NET Core 8 application, using +https://learn.microsoft.com/en-us/dotnet/csharp/tutorials/top-level-statements[top-level statements]. -- - -For ASP.NET Core, once you reference the {nuget}/Elastic.Apm.NetCoreAll[`Elastic.Apm.NetCoreAll`] package, you can enable auto instrumentation by calling the `UseAllElasticApm()` extension method: [source,csharp] ---- -using Elastic.Apm.NetCoreAll; - -public class Startup -{ - public void Configure(IApplicationBuilder app, IHostingEnvironment env) - { - app.UseAllElasticApm(Configuration); - //…rest of the method - } - //…rest of the class -} ----- +var builder = WebApplication.CreateBuilder(args); -The `app.UseAllElasticApm(...)` line **must** be the first line in the `Configure` method, otherwise the agent won't be able to properly measure the timing of your requests, and complete requests may potentially be missed by the agent. +builder.Services.AddAllElasticApm(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. + +app.Run(); +---- With this you enable every agent component including ASP.NET Core tracing, monitoring of outgoing HTTP request, Entity Framework Core database tracing, etc. -In case you only reference the {nuget}/Elastic.Apm.AspNetCore[`Elastic.Apm.AspNetCore`] package, you won't find the `UseAllElasticApm`. Instead you need to use the `UseElasticApm()` method from the `Elastic.Apm.AspNetCore` namespace. This method turns on ASP.NET Core tracing, and gives you the opportunity to manually turn on other components. By default it will only trace ASP.NET Core requests - No HTTP request tracing, database call tracing or any other tracing component will be turned on. +In case you only reference the {nuget}/Elastic.Apm.AspNetCore[`Elastic.Apm.AspNetCore`] package, you won't find the `AddAllElasticApm`. Instead you need to use +the `AddElasticApmForAspNetCore()` method. This method turns on ASP.NET Core tracing, and gives you the opportunity to manually turn on other components. By default it +will only trace ASP.NET Core requests - No HTTP request tracing, database call tracing or any other tracing component will be turned on. -In case you would like to turn on specific tracing components you can pass those to the `UseElasticApm` method. +In case you would like to turn on specific tracing components you can pass those to the `AddElasticApm` method. For example: [source,csharp] ---- -app.UseElasticApm(Configuration, +builder.Services.AddElasticApm( new HttpDiagnosticsSubscriber(), /* Enable tracing of outgoing HTTP requests */ new EfCoreDiagnosticsSubscriber()); /* Enable tracing of database calls through EF Core*/ ---- diff --git a/docs/troubleshooting.asciidoc b/docs/troubleshooting.asciidoc index ce4dea0d7..43184704e 100644 --- a/docs/troubleshooting.asciidoc +++ b/docs/troubleshooting.asciidoc @@ -89,8 +89,8 @@ The default value is `file` if `OTEL_DOTNET_AUTO_LOG_DIRECTORY` is set or `OTEL_ [[collect-logs-core]] ==== ASP.NET Core -If you added the agent to your application as per the <> document with the `UseAllElasticApm` or `UseElasticApm` method, it will integrate with the -https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging[ASP.NET Core logging infrastructure]. +If you added the agent to your application as per the <> document with the `AddAllElasticApm` or `AddElasticApm` method, it will integrate with the +https://learn.microsoft.com/aspnet/core/fundamentals/logging[ASP.NET Core logging infrastructure]. This means the Agent will pick up the configured logging provider and log as any other component logs. [IMPORTANT] @@ -192,17 +192,26 @@ See "<>". [[double-agent-initialization]] === An `InstanceAlreadyCreatedException` exception is thrown -In the early stage of a monitored process, the Agent might throw an `InstanceAlreadyCreatedException` exception with the following message: "The singleton APM agent has already been instantiated and can no longer be configured.", or an error log appears with the same message. This happens when you attempt to initialize the Agent multiple times, which is prohibited. Allowing multiple Agent instances per process would open up problems, like capturing events and metrics multiple times for each instance, or having multiple background threads for event serialization and transfer to the APM Server. +In the early stage of a monitored process, the Agent might throw an `InstanceAlreadyCreatedException` exception with the following message: +"The singleton APM agent has already been instantiated and can no longer be configured.", or an error log appears with the same message. This +happens when you attempt to initialize the Agent multiple times, which is prohibited. Allowing multiple Agent instances per process would open +up problems, like capturing events and metrics multiple times for each instance, or having multiple background threads for event serialization +and transfer to the APM Server. TIP: Take a look at the initialization section of the <> for more information on how agent initialization works. -As an example, this issue can happen if you call the `Elastic.Apm.Agent.Setup` method multiple times, or if you call another method on `Elastic.Apm.Agent` that implicitly initializes the agent, and then you call the `Elastic.Apm.Agent.Setup` method on the already initialized agent. +As an example, this issue can happen if you call the `Elastic.Apm.Agent.Setup` method multiple times, or if you call another method on `Elastic.Apm.Agent` +that implicitly initializes the agent, and then you call the `Elastic.Apm.Agent.Setup` method on the already initialized agent. -Another example might be when you use the Public Agent API in combination with the IIS module or the ASP.NET Core NuGet package, where you enable the agent with the `UseElasticApm` or `UseAllElasticApm` methods. Both the first call to the IIS module and the `UseElasticApm`/`UseAllElasticApm` methods internally call the `Elastic.Apm.Agent.Setup` method to initialize the agent. +Another example might be when you use the Public Agent API in combination with the IIS module or the ASP.NET Core NuGet package, where you enable +the agent with the `AddElasticApm` or `UseAllElasticApm` methods. Both the first call to the IIS module and the `AddElasticApm`/`AddllElasticApm` +methods internally call the `Elastic.Apm.Agent.Setup` method to initialize the agent. -You may use the Public Agent API with the `Elastic.Apm.Agent` class in code that can potentially execute before the IIS module initializes or the `UseElasticApm`/`UseAllElasticApm` calls execute. If that happens, those will fail, as the Agent has been implicitly initialized already. +You may use the Public Agent API with the `Elastic.Apm.Agent` class in code that can potentially execute before the IIS module initializes or +the `AddElasticApm`/`AddAllElasticApm` calls execute. If that happens, those will fail, as the Agent has been implicitly initialized already. -To prevent the `InstanceAlreadyCreatedException` in these scenarios, first use the `Elastic.Apm.Agent.IsConfigured` method to check if the agent is already initialized. After the check, you can safely use other methods in the Public Agent API. This will prevent accidental implicit agent initialization. +To prevent the `InstanceAlreadyCreatedException` in these scenarios, first use the `Elastic.Apm.Agent.IsConfigured` method to check if the agent +is already initialized. After the check, you can safely use other methods in the Public Agent API. This will prevent accidental implicit agent initialization. [float] [[legacy-asp-net-sync-context]]