diff --git a/OpenTelemetry.sln b/OpenTelemetry.sln index e34a707790d..8e14f86b9bc 100644 --- a/OpenTelemetry.sln +++ b/OpenTelemetry.sln @@ -159,6 +159,9 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "metrics", "metrics", "{3277B1C0-BDFE-4460-9B0D-D9A661FB48DB}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "logs", "logs", "{3862190B-E2C5-418E-AFDC-DB281FB5C705}" + ProjectSection(SolutionItems) = preProject + docs\logs\getting-started\README.md = docs\logs\getting-started\README.md + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MicroserviceExample", "MicroserviceExample", "{4D492D62-5150-45F9-817F-C99562E364E2}" ProjectSection(SolutionItems) = preProject @@ -230,6 +233,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.Pr EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.Propagators.Tests", "test\OpenTelemetry.Extensions.Propagators.Tests\OpenTelemetry.Extensions.Propagators.Tests.csproj", "{476D804B-BFEC-4D34-814C-DFFD97109989}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "correlation", "docs\logs\correlation\correlation.csproj", "{9A07D215-90AC-4BAF-BCDB-73D74FD3A5C5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -484,6 +489,10 @@ Global {476D804B-BFEC-4D34-814C-DFFD97109989}.Debug|Any CPU.Build.0 = Debug|Any CPU {476D804B-BFEC-4D34-814C-DFFD97109989}.Release|Any CPU.ActiveCfg = Release|Any CPU {476D804B-BFEC-4D34-814C-DFFD97109989}.Release|Any CPU.Build.0 = Release|Any CPU + {9A07D215-90AC-4BAF-BCDB-73D74FD3A5C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9A07D215-90AC-4BAF-BCDB-73D74FD3A5C5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9A07D215-90AC-4BAF-BCDB-73D74FD3A5C5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9A07D215-90AC-4BAF-BCDB-73D74FD3A5C5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -521,6 +530,7 @@ Global {1F6CC903-04C9-4E7C-B388-C215C467BFB9} = {3862190B-E2C5-418E-AFDC-DB281FB5C705} {41B784AA-3301-4126-AF9F-1D59BD04B0BF} = {3277B1C0-BDFE-4460-9B0D-D9A661FB48DB} {6C7A1595-36D6-4229-BBB5-5A6B5791791D} = {3862190B-E2C5-418E-AFDC-DB281FB5C705} + {9A07D215-90AC-4BAF-BCDB-73D74FD3A5C5} = {3862190B-E2C5-418E-AFDC-DB281FB5C705} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {55639B5C-0770-4A22-AB56-859604650521} diff --git a/docs/logs/correlation/Program.cs b/docs/logs/correlation/Program.cs new file mode 100644 index 00000000000..722e66347e6 --- /dev/null +++ b/docs/logs/correlation/Program.cs @@ -0,0 +1,59 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System.Diagnostics; +using Microsoft.Extensions.Logging; +using OpenTelemetry; +using OpenTelemetry.Logs; +using OpenTelemetry.Trace; + +namespace Correlation; + +public class Program +{ + private static readonly ActivitySource MyActivitySource = new( + "MyCompany.MyProduct.MyLibrary"); + + public static void Main() + { + // Setup Logging + using var loggerFactory = LoggerFactory.Create(builder => + { + builder.AddOpenTelemetry(options => + { + options.AddConsoleExporter(); + }); + }); + + var logger = loggerFactory.CreateLogger(); + + // Setup Traces + using var tracerProvider = Sdk.CreateTracerProviderBuilder() + .AddSource("MyCompany.MyProduct.MyLibrary") + .AddConsoleExporter() + .Build(); + + // Emit activity + using (var activity = MyActivitySource.StartActivity("SayHello")) + { + activity?.SetTag("foo", 1); + + // emit logs within the context + // of activity + logger.LogInformation("Hello from {name} {price}.", "tomato", 2.99); + } + } +} diff --git a/docs/logs/correlation/README.md b/docs/logs/correlation/README.md new file mode 100644 index 00000000000..84e7ec1b59a --- /dev/null +++ b/docs/logs/correlation/README.md @@ -0,0 +1,64 @@ +# Logs correlation + +The getting started docs for [logs](../getting-started/README.md) and +[traces](../../trace/getting-started/README.md) showed how to emit logs and +traces independently, and export them to console exporter. + +This doc explains how logs can be correlated to traces. + +## Logging Data Model support for correlation + +[Logging Data +Model](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#trace-context-fields) +defines fields which allow a log to be correlated with span (`Activity` in +.NET). The fields `TraceId` and `SpanId` allow a log to be correlated to +corresponding `Activity`. + +## Correlation in OpenTelemetry .NET + +The good news is that, in OpenTelemetry .NET SDK, there is no user action +required to enable correlation. i.e the SDK automatically enables logs to +`Activity` correlation, by populating the fields `TraceId`, `SpanId`, +`TraceFlags`, `TraceState` from the active activity (i.e `Activity.Current`), if +any. + +The example [Program.cs](./Program.cs) shows how to emit logs within the context +of an active `Activity`. Running the application will show the following output +on the console: + +```text +LogRecord.Timestamp: 2022-05-18T18:51:16.4348626Z +LogRecord.TraceId: d7aca5b2422ed8d15f56b6a93be4537d +LogRecord.SpanId: c90ac2ad41ab4d46 +LogRecord.TraceFlags: Recorded +LogRecord.CategoryName: Correlation.Program +LogRecord.LogLevel: Information +LogRecord.State: Hello from tomato 2.99. + +Resource associated with LogRecord: +service.name: unknown_service:correlation + +Activity.TraceId: d7aca5b2422ed8d15f56b6a93be4537d +Activity.SpanId: c90ac2ad41ab4d46 +Activity.TraceFlags: Recorded +Activity.ActivitySourceName: MyCompany.MyProduct.MyLibrary +Activity.DisplayName: SayHello +Activity.Kind: Internal +Activity.StartTime: 2022-05-18T18:51:16.3427411Z +Activity.Duration: 00:00:00.2248932 +Activity.Tags: + foo: 1 +Resource associated with Activity: + service.name: unknown_service:correlation +``` + +As you can see, the `LogRecord` automatically had the `TraceId`, `SpanId` fields +matching the ones from the `Activity`. In [the logs getting +started](../getting-started/README.md) doc, the logging was done outside of an +`Activity` context, hence these fields in `LogRecord` were not populated. + +## Learn more + +Check [ASP.NET Core](../../../examples/AspNetCore/README.md) example application +which shows how all the logs done within the context of request are +automatically correlated to the `Activity` representing the incoming request. diff --git a/docs/logs/correlation/correlation.csproj b/docs/logs/correlation/correlation.csproj new file mode 100644 index 00000000000..a0d4b1e148b --- /dev/null +++ b/docs/logs/correlation/correlation.csproj @@ -0,0 +1,6 @@ + + + + + +