diff --git a/OpenTelemetry.sln b/OpenTelemetry.sln
index d661f7604c5..917ae4b448e 100644
--- a/OpenTelemetry.sln
+++ b/OpenTelemetry.sln
@@ -227,13 +227,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.Pr
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "correlation", "docs\logs\correlation\correlation.csproj", "{9A07D215-90AC-4BAF-BCDB-73D74FD3A5C5}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Tests.Stress.Logs", "test\OpenTelemetry.Tests.Stress.Logs\OpenTelemetry.Tests.Stress.Logs.csproj", "{4298057B-24E0-47B3-BB76-C17E81AF6B39}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Tests.Stress.Logs", "test\OpenTelemetry.Tests.Stress.Logs\OpenTelemetry.Tests.Stress.Logs.csproj", "{5FC0660F-3757-4594-806B-4375E06177A3}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Examples.LoggingExtensions", "examples\LoggingExtensions\Examples.LoggingExtensions.csproj", "{F5EFF065-7AF5-4D7D-8038-CC419ABD8777}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.Serilog", "src\OpenTelemetry.Extensions.Serilog\OpenTelemetry.Extensions.Serilog.csproj", "{F5062ED1-6B59-45FC-8E08-2F5D41A19864}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.Serilog", "src\OpenTelemetry.Extensions.Serilog\OpenTelemetry.Extensions.Serilog.csproj", "{0D85558E-15B9-4251-BDBD-9CB7933B57E2}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.Tracing", "src\OpenTelemetry.Extensions.Tracing\OpenTelemetry.Extensions.Tracing.csproj", "{F1C65913-81EC-4297-A666-A66280E3E1B6}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.Serilog.Tests", "test\OpenTelemetry.Extensions.Serilog.Tests\OpenTelemetry.Extensions.Serilog.Tests.csproj", "{6A2C122A-C1CD-4B6B-AE09-2ABB7D3C50CE}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Examples.LoggingExtensions", "examples\LoggingExtensions\Examples.LoggingExtensions.csproj", "{CCBBAD69-4A7D-41F8-8697-6E3F043F7BD5}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Extensions.Serilog.Tests", "test\OpenTelemetry.Extensions.Serilog.Tests\OpenTelemetry.Extensions.Serilog.Tests.csproj", "{C470DC46-8DE6-4668-BD25-ADF851F6E1E2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -465,22 +467,26 @@ Global
{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
- {4298057B-24E0-47B3-BB76-C17E81AF6B39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {4298057B-24E0-47B3-BB76-C17E81AF6B39}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {4298057B-24E0-47B3-BB76-C17E81AF6B39}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {4298057B-24E0-47B3-BB76-C17E81AF6B39}.Release|Any CPU.Build.0 = Release|Any CPU
- {F5EFF065-7AF5-4D7D-8038-CC419ABD8777}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F5EFF065-7AF5-4D7D-8038-CC419ABD8777}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F5EFF065-7AF5-4D7D-8038-CC419ABD8777}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F5EFF065-7AF5-4D7D-8038-CC419ABD8777}.Release|Any CPU.Build.0 = Release|Any CPU
- {0D85558E-15B9-4251-BDBD-9CB7933B57E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0D85558E-15B9-4251-BDBD-9CB7933B57E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0D85558E-15B9-4251-BDBD-9CB7933B57E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0D85558E-15B9-4251-BDBD-9CB7933B57E2}.Release|Any CPU.Build.0 = Release|Any CPU
- {6A2C122A-C1CD-4B6B-AE09-2ABB7D3C50CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {6A2C122A-C1CD-4B6B-AE09-2ABB7D3C50CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {6A2C122A-C1CD-4B6B-AE09-2ABB7D3C50CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {6A2C122A-C1CD-4B6B-AE09-2ABB7D3C50CE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5FC0660F-3757-4594-806B-4375E06177A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5FC0660F-3757-4594-806B-4375E06177A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5FC0660F-3757-4594-806B-4375E06177A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5FC0660F-3757-4594-806B-4375E06177A3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F5062ED1-6B59-45FC-8E08-2F5D41A19864}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F5062ED1-6B59-45FC-8E08-2F5D41A19864}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F5062ED1-6B59-45FC-8E08-2F5D41A19864}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F5062ED1-6B59-45FC-8E08-2F5D41A19864}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F1C65913-81EC-4297-A666-A66280E3E1B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F1C65913-81EC-4297-A666-A66280E3E1B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F1C65913-81EC-4297-A666-A66280E3E1B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F1C65913-81EC-4297-A666-A66280E3E1B6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CCBBAD69-4A7D-41F8-8697-6E3F043F7BD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CCBBAD69-4A7D-41F8-8697-6E3F043F7BD5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CCBBAD69-4A7D-41F8-8697-6E3F043F7BD5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CCBBAD69-4A7D-41F8-8697-6E3F043F7BD5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C470DC46-8DE6-4668-BD25-ADF851F6E1E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C470DC46-8DE6-4668-BD25-ADF851F6E1E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C470DC46-8DE6-4668-BD25-ADF851F6E1E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C470DC46-8DE6-4668-BD25-ADF851F6E1E2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -518,7 +524,7 @@ Global
{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}
- {F5EFF065-7AF5-4D7D-8038-CC419ABD8777} = {E359BB2B-9AEC-497D-B321-7DF2450C3B8E}
+ {CCBBAD69-4A7D-41F8-8697-6E3F043F7BD5} = {E359BB2B-9AEC-497D-B321-7DF2450C3B8E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {55639B5C-0770-4A22-AB56-859604650521}
diff --git a/examples/AspNetCore/Controllers/WeatherForecastController.cs b/examples/AspNetCore/Controllers/WeatherForecastController.cs
index 54f19e63b4d..5f724a36412 100644
--- a/examples/AspNetCore/Controllers/WeatherForecastController.cs
+++ b/examples/AspNetCore/Controllers/WeatherForecastController.cs
@@ -24,7 +24,7 @@ public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
- "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching",
+ "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching",
};
private static readonly HttpClient HttpClient = new();
diff --git a/examples/LoggingExtensions/Examples.LoggingExtensions.csproj b/examples/LoggingExtensions/Examples.LoggingExtensions.csproj
index 8e502ea56d8..c365a45c62c 100644
--- a/examples/LoggingExtensions/Examples.LoggingExtensions.csproj
+++ b/examples/LoggingExtensions/Examples.LoggingExtensions.csproj
@@ -9,6 +9,7 @@
+
diff --git a/examples/LoggingExtensions/Program.cs b/examples/LoggingExtensions/Program.cs
index 310e225337f..22b89381304 100644
--- a/examples/LoggingExtensions/Program.cs
+++ b/examples/LoggingExtensions/Program.cs
@@ -14,11 +14,12 @@
// limitations under the License.
//
+using System.Diagnostics.Tracing;
using OpenTelemetry.Logs;
using OpenTelemetry.Resources;
using Serilog;
-var resourceBuilder = ResourceBuilder.CreateDefault().AddService("Examples.LogEmitter");
+var resourceBuilder = ResourceBuilder.CreateDefault().AddService("Examples.LoggingExtensions");
// Note: It is important that OpenTelemetryLoggerProvider is disposed when the
// app is shutdown. In this example we allow Serilog to do that by calling CloseAndFlush.
@@ -30,6 +31,12 @@
.AddConsoleExporter();
});
+// Creates an OpenTelemetryEventSourceLogEmitter for routing EventSources with
+// names matching OpenTelemetry* into logs
+using var openTelemetryEventSourceLogEmitter = new OpenTelemetryEventSourceLogEmitter(
+ openTelemetryLoggerProvider,
+ (name) => name.StartsWith("OpenTelemetry") ? EventLevel.LogAlways : null);
+
// Configure Serilog global logger
Log.Logger = new LoggerConfiguration()
.WriteTo.OpenTelemetry(openTelemetryLoggerProvider, disposeProvider: true) // <- Register OpenTelemetry Serilog sink
diff --git a/src/OpenTelemetry.Extensions.Tracing/.publicApi/netstandard2.0/PublicAPI.Shipped.txt b/src/OpenTelemetry.Extensions.Tracing/.publicApi/netstandard2.0/PublicAPI.Shipped.txt
new file mode 100644
index 00000000000..7dc5c58110b
--- /dev/null
+++ b/src/OpenTelemetry.Extensions.Tracing/.publicApi/netstandard2.0/PublicAPI.Shipped.txt
@@ -0,0 +1 @@
+#nullable enable
diff --git a/src/OpenTelemetry.Extensions.Tracing/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Extensions.Tracing/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt
new file mode 100644
index 00000000000..16452ff842c
--- /dev/null
+++ b/src/OpenTelemetry.Extensions.Tracing/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt
@@ -0,0 +1,5 @@
+#nullable enable
+OpenTelemetry.Logs.OpenTelemetryEventSourceLogEmitter
+OpenTelemetry.Logs.OpenTelemetryEventSourceLogEmitter.OpenTelemetryEventSourceLogEmitter(OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider, string! name, System.Diagnostics.Tracing.EventLevel logLevel = System.Diagnostics.Tracing.EventLevel.LogAlways) -> void
+OpenTelemetry.Logs.OpenTelemetryEventSourceLogEmitter.OpenTelemetryEventSourceLogEmitter(OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider, System.Func! shouldListenToFunc) -> void
+override OpenTelemetry.Logs.OpenTelemetryEventSourceLogEmitter.Dispose() -> void
diff --git a/src/OpenTelemetry.Extensions.Tracing/.publicApi/netstandard2.1/PublicAPI.Shipped.txt b/src/OpenTelemetry.Extensions.Tracing/.publicApi/netstandard2.1/PublicAPI.Shipped.txt
new file mode 100644
index 00000000000..7dc5c58110b
--- /dev/null
+++ b/src/OpenTelemetry.Extensions.Tracing/.publicApi/netstandard2.1/PublicAPI.Shipped.txt
@@ -0,0 +1 @@
+#nullable enable
diff --git a/src/OpenTelemetry.Extensions.Tracing/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry.Extensions.Tracing/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt
new file mode 100644
index 00000000000..16452ff842c
--- /dev/null
+++ b/src/OpenTelemetry.Extensions.Tracing/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt
@@ -0,0 +1,5 @@
+#nullable enable
+OpenTelemetry.Logs.OpenTelemetryEventSourceLogEmitter
+OpenTelemetry.Logs.OpenTelemetryEventSourceLogEmitter.OpenTelemetryEventSourceLogEmitter(OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider, string! name, System.Diagnostics.Tracing.EventLevel logLevel = System.Diagnostics.Tracing.EventLevel.LogAlways) -> void
+OpenTelemetry.Logs.OpenTelemetryEventSourceLogEmitter.OpenTelemetryEventSourceLogEmitter(OpenTelemetry.Logs.OpenTelemetryLoggerProvider! openTelemetryLoggerProvider, System.Func! shouldListenToFunc) -> void
+override OpenTelemetry.Logs.OpenTelemetryEventSourceLogEmitter.Dispose() -> void
diff --git a/src/OpenTelemetry.Extensions.Tracing/AssemblyInfo.cs b/src/OpenTelemetry.Extensions.Tracing/AssemblyInfo.cs
new file mode 100644
index 00000000000..a51a83d9d1d
--- /dev/null
+++ b/src/OpenTelemetry.Extensions.Tracing/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+//
+// 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;
+using System.Runtime.CompilerServices;
+
+[assembly: CLSCompliant(false)]
+[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2" + AssemblyInfo.MoqPublicKey)]
+
+#if SIGNED
+internal static class AssemblyInfo
+{
+ public const string PublicKey = ", PublicKey=002400000480000094000000060200000024000052534131000400000100010051C1562A090FB0C9F391012A32198B5E5D9A60E9B80FA2D7B434C9E5CCB7259BD606E66F9660676AFC6692B8CDC6793D190904551D2103B7B22FA636DCBB8208839785BA402EA08FC00C8F1500CCEF28BBF599AA64FFB1E1D5DC1BF3420A3777BADFE697856E9D52070A50C3EA5821C80BEF17CA3ACFFA28F89DD413F096F898";
+ public const string MoqPublicKey = ", PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7";
+}
+#else
+internal static class AssemblyInfo
+{
+ public const string PublicKey = "";
+ public const string MoqPublicKey = "";
+}
+#endif
diff --git a/src/OpenTelemetry.Extensions.Tracing/CHANGELOG.md b/src/OpenTelemetry.Extensions.Tracing/CHANGELOG.md
new file mode 100644
index 00000000000..63bfc986bdc
--- /dev/null
+++ b/src/OpenTelemetry.Extensions.Tracing/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Changelog
+
+## Unreleased
+
+Initial release.
diff --git a/src/OpenTelemetry.Extensions.Tracing/OpenTelemetry.Extensions.Tracing.csproj b/src/OpenTelemetry.Extensions.Tracing/OpenTelemetry.Extensions.Tracing.csproj
new file mode 100644
index 00000000000..eaa13a04b69
--- /dev/null
+++ b/src/OpenTelemetry.Extensions.Tracing/OpenTelemetry.Extensions.Tracing.csproj
@@ -0,0 +1,19 @@
+
+
+
+ netstandard2.1;netstandard2.0
+ Extensions for using OpenTelemetry with System.Diagnostics.Tracing
+ enable
+ AllEnabledByDefault
+ latest
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/OpenTelemetry.Extensions.Tracing/OpenTelemetryEventSourceLogEmitter.cs b/src/OpenTelemetry.Extensions.Tracing/OpenTelemetryEventSourceLogEmitter.cs
new file mode 100644
index 00000000000..da1541b2709
--- /dev/null
+++ b/src/OpenTelemetry.Extensions.Tracing/OpenTelemetryEventSourceLogEmitter.cs
@@ -0,0 +1,218 @@
+//
+// 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;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.Tracing;
+using System.Globalization;
+using System.Linq;
+using Microsoft.Extensions.Logging;
+using OpenTelemetry.Internal;
+
+namespace OpenTelemetry.Logs
+{
+ ///
+ /// Implements an which will convert events into OpenTelemetry logs.
+ ///
+ public sealed class OpenTelemetryEventSourceLogEmitter : EventListener
+ {
+ private readonly bool includeFormattedMessage;
+ private readonly LogEmitter logEmitter;
+ private readonly object lockObj = new();
+ private readonly Func shouldListenToFunc;
+ private readonly List eventSources = new();
+ private readonly List? eventSourcesBeforeConstructor = new();
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// .
+ /// Name of the to listen to.
+ /// Event level to capture.
+ public OpenTelemetryEventSourceLogEmitter(
+ OpenTelemetryLoggerProvider openTelemetryLoggerProvider,
+ string name,
+ EventLevel logLevel = EventLevel.LogAlways)
+ : this(openTelemetryLoggerProvider, (n) => n == name ? logLevel : null)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// .
+ /// Callback function used to decide if
+ /// events should be captured for a given .
+ /// Return if no events should be
+ /// captured.
+ public OpenTelemetryEventSourceLogEmitter(
+ OpenTelemetryLoggerProvider openTelemetryLoggerProvider,
+ Func shouldListenToFunc)
+ {
+ Guard.ThrowIfNull(openTelemetryLoggerProvider);
+ Guard.ThrowIfNull(shouldListenToFunc);
+
+ this.includeFormattedMessage = openTelemetryLoggerProvider.IncludeFormattedMessage;
+ this.logEmitter = openTelemetryLoggerProvider.CreateEmitter();
+ this.shouldListenToFunc = shouldListenToFunc;
+
+ lock (this.lockObj)
+ {
+ foreach (EventSource eventSource in this.eventSourcesBeforeConstructor)
+ {
+ this.ProcessSource(eventSource);
+ }
+
+ this.eventSourcesBeforeConstructor = null;
+ }
+ }
+
+ ///
+ public override void Dispose()
+ {
+ foreach (EventSource eventSource in this.eventSources)
+ {
+ this.DisableEvents(eventSource);
+ }
+
+ this.eventSources.Clear();
+
+ base.Dispose();
+ }
+
+#pragma warning disable CA1062 // Validate arguments of public methods
+ ///
+ protected override void OnEventSourceCreated(EventSource eventSource)
+ {
+ Debug.Assert(eventSource != null, "EventSource was null.");
+
+ try
+ {
+ if (this.eventSourcesBeforeConstructor != null)
+ {
+ lock (this.lockObj)
+ {
+ if (this.eventSourcesBeforeConstructor != null)
+ {
+ this.eventSourcesBeforeConstructor.Add(eventSource!);
+ return;
+ }
+ }
+ }
+
+ this.ProcessSource(eventSource!);
+ }
+ finally
+ {
+ base.OnEventSourceCreated(eventSource);
+ }
+ }
+#pragma warning restore CA1062 // Validate arguments of public methods
+
+#pragma warning disable CA1062 // Validate arguments of public methods
+ ///
+ protected override void OnEventWritten(EventWrittenEventArgs eventData)
+ {
+ Debug.Assert(eventData != null, "EventData was null.");
+
+ string? rawMessage = eventData!.Message;
+
+ LogRecordData data = new(Activity.Current)
+ {
+#if NETSTANDARD2_1_OR_GREATER
+ Timestamp = eventData.TimeStamp,
+#endif
+ EventId = new EventId(eventData.EventId, eventData.EventName),
+ LogLevel = ConvertEventLevelToLogLevel(eventData.Level),
+ };
+
+ LogRecordAttributeList attributes = default;
+
+ attributes.Add("event_source.name", eventData.EventSource.Name);
+
+ if (eventData.ActivityId != Guid.Empty)
+ {
+ attributes.Add("event_source.activity_id", eventData.ActivityId);
+ }
+
+ if (eventData.RelatedActivityId != Guid.Empty)
+ {
+ attributes.Add("event_source.related_activity_id", eventData.RelatedActivityId);
+ }
+
+ int payloadCount = eventData.Payload?.Count ?? 0;
+
+ if (payloadCount > 0 && payloadCount == eventData.PayloadNames?.Count)
+ {
+ for (int i = 0; i < payloadCount; i++)
+ {
+ string name = eventData.PayloadNames[i];
+
+ if (!string.IsNullOrEmpty(rawMessage) && !this.includeFormattedMessage)
+ {
+ // TODO: This code converts the event message from
+ // string.Format syntax (eg: "Some message {0} {1}")
+ // into structured log format (eg: "Some message
+ // {propertyName1} {propertyName2}") but it is
+ // expensive. Probably needs a cache.
+#if NETSTANDARD2_0
+ rawMessage = rawMessage.Replace($"{{{i}}}", $"{{{name}}}");
+#else
+ rawMessage = rawMessage.Replace($"{{{i}}}", $"{{{name}}}", StringComparison.Ordinal);
+#endif
+ }
+
+ attributes.Add(name, eventData.Payload![i]);
+ }
+ }
+
+ if (!string.IsNullOrEmpty(rawMessage) && this.includeFormattedMessage && payloadCount > 0)
+ {
+ rawMessage = string.Format(CultureInfo.InvariantCulture, rawMessage, eventData.Payload!.ToArray());
+ }
+
+ data.Message = rawMessage;
+
+ this.logEmitter.Emit(in data, in attributes);
+ }
+#pragma warning restore CA1062 // Validate arguments of public methods
+
+ private static LogLevel ConvertEventLevelToLogLevel(EventLevel eventLevel)
+ {
+ return eventLevel switch
+ {
+ EventLevel.Informational => LogLevel.Information,
+ EventLevel.Warning => LogLevel.Warning,
+ EventLevel.Error => LogLevel.Error,
+ EventLevel.Critical => LogLevel.Critical,
+ _ => LogLevel.Trace,
+ };
+ }
+
+ private void ProcessSource(EventSource eventSource)
+ {
+ EventLevel? eventLevel = this.shouldListenToFunc(eventSource.Name);
+
+ if (eventLevel.HasValue)
+ {
+ this.eventSources.Add(eventSource);
+ this.EnableEvents(eventSource, eventLevel.Value, EventKeywords.All);
+ }
+ }
+ }
+}
diff --git a/src/OpenTelemetry.Extensions.Tracing/README.md b/src/OpenTelemetry.Extensions.Tracing/README.md
new file mode 100644
index 00000000000..d14f85bd468
--- /dev/null
+++ b/src/OpenTelemetry.Extensions.Tracing/README.md
@@ -0,0 +1,30 @@
+# OpenTelemetry.Extensions.Tracing
+
+This project contains an
+[EventListener](https://docs.microsoft.com/dotnet/api/system.diagnostics.tracing.eventlistener)
+which can be used to translate events written to an
+[EventSource](https://docs.microsoft.com/dotnet/api/system.diagnostics.tracing.eventsource)
+into to OpenTelemetry logs.
+
+## Usage Example
+
+```csharp
+// Step 1: Configure OpenTelemetryLoggerProvider...
+var resourceBuilder = ResourceBuilder.CreateDefault().AddService("MyService");
+
+using var openTelemetryLoggerProvider = new OpenTelemetryLoggerProvider(options =>
+{
+ options
+ .SetResourceBuilder(resourceBuilder)
+ .AddConsoleExporter();
+});
+
+// Step 2: Create OpenTelemetryEventSourceLogEmitter to listen to events...
+using var openTelemetryEventSourceLogEmitter = new OpenTelemetryEventSourceLogEmitter(
+ openTelemetryLoggerProvider,
+ (name) => name.StartsWith("OpenTelemetry") ? EventLevel.LogAlways : null);
+```
+
+## References
+
+* [OpenTelemetry Project](https://opentelemetry.io/)
diff --git a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt
index ecaf006aa47..ff683034d4a 100644
--- a/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry/.publicApi/net462/PublicAPI.Unshipped.txt
@@ -8,6 +8,7 @@ OpenTelemetry.Logs.LogRecord.TraceFlags.set -> void
OpenTelemetry.Logs.LogRecord.TraceId.set -> void
OpenTelemetry.Logs.LogRecord.TraceState.set -> void
OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMilliseconds = -1) -> bool
+OpenTelemetry.Logs.OpenTelemetryLoggerProvider.IncludeFormattedMessage.get -> bool
OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void
OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions!
diff --git a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt
index 43156ee3c3a..a316ab5d377 100644
--- a/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry/.publicApi/net6.0/PublicAPI.Unshipped.txt
@@ -9,6 +9,7 @@ OpenTelemetry.Logs.LogRecord.TraceId.set -> void
OpenTelemetry.Logs.LogRecord.TraceState.set -> void
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions!
OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMilliseconds = -1) -> bool
+OpenTelemetry.Logs.OpenTelemetryLoggerProvider.IncludeFormattedMessage.get -> bool
OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void
OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void
~static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder
diff --git a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt
index ecaf006aa47..ff683034d4a 100644
--- a/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry/.publicApi/netstandard2.0/PublicAPI.Unshipped.txt
@@ -8,6 +8,7 @@ OpenTelemetry.Logs.LogRecord.TraceFlags.set -> void
OpenTelemetry.Logs.LogRecord.TraceId.set -> void
OpenTelemetry.Logs.LogRecord.TraceState.set -> void
OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMilliseconds = -1) -> bool
+OpenTelemetry.Logs.OpenTelemetryLoggerProvider.IncludeFormattedMessage.get -> bool
OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void
OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions!
diff --git a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt
index 43156ee3c3a..a316ab5d377 100644
--- a/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt
+++ b/src/OpenTelemetry/.publicApi/netstandard2.1/PublicAPI.Unshipped.txt
@@ -9,6 +9,7 @@ OpenTelemetry.Logs.LogRecord.TraceId.set -> void
OpenTelemetry.Logs.LogRecord.TraceState.set -> void
OpenTelemetry.Logs.OpenTelemetryLoggerOptions.ConfigureResource(System.Action! configure) -> OpenTelemetry.Logs.OpenTelemetryLoggerOptions!
OpenTelemetry.Logs.OpenTelemetryLoggerProvider.ForceFlush(int timeoutMilliseconds = -1) -> bool
+OpenTelemetry.Logs.OpenTelemetryLoggerProvider.IncludeFormattedMessage.get -> bool
OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider() -> void
OpenTelemetry.Logs.OpenTelemetryLoggerProvider.OpenTelemetryLoggerProvider(System.Action! configure) -> void
~static OpenTelemetry.Metrics.MeterProviderBuilderExtensions.ConfigureResource(this OpenTelemetry.Metrics.MeterProviderBuilder meterProviderBuilder, System.Action configure) -> OpenTelemetry.Metrics.MeterProviderBuilder
diff --git a/src/OpenTelemetry/AssemblyInfo.cs b/src/OpenTelemetry/AssemblyInfo.cs
index 0a79a36dfe5..99d1bfa8ad4 100644
--- a/src/OpenTelemetry/AssemblyInfo.cs
+++ b/src/OpenTelemetry/AssemblyInfo.cs
@@ -21,6 +21,7 @@
[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus" + AssemblyInfo.PublicKey)]
[assembly: InternalsVisibleTo("OpenTelemetry.Exporter.Prometheus.Tests" + AssemblyInfo.PublicKey)]
[assembly: InternalsVisibleTo("OpenTelemetry.Extensions.Hosting.Tests" + AssemblyInfo.PublicKey)]
+[assembly: InternalsVisibleTo("OpenTelemetry.Extensions.Tracing" + AssemblyInfo.PublicKey)]
[assembly: InternalsVisibleTo("OpenTelemetry.Extensions.Serilog" + AssemblyInfo.PublicKey)]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2" + AssemblyInfo.MoqPublicKey)]
[assembly: InternalsVisibleTo("Benchmarks" + AssemblyInfo.PublicKey)]
diff --git a/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs b/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs
index d94769b7f59..672d4ef8250 100644
--- a/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs
+++ b/src/OpenTelemetry/Logs/OpenTelemetryLoggerProvider.cs
@@ -33,7 +33,6 @@ namespace OpenTelemetry.Logs
public class OpenTelemetryLoggerProvider : BaseProvider, ILoggerProvider, ISupportExternalScope
{
internal readonly bool IncludeScopes;
- internal readonly bool IncludeFormattedMessage;
internal readonly bool ParseStateValues;
internal BaseProcessor? Processor;
internal Resource Resource;
@@ -90,6 +89,11 @@ internal OpenTelemetryLoggerProvider(OpenTelemetryLoggerOptions options)
}
}
+ ///
+ /// Gets a value indicating whether or not formatted messages should be included on log messages.
+ ///
+ public bool IncludeFormattedMessage { get; }
+
internal IExternalScopeProvider? ScopeProvider { get; private set; }
internal ILogRecordPool LogRecordPool => this.threadStaticPool ?? LogRecordSharedPool.Current;