-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
307 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
111 changes: 111 additions & 0 deletions
111
src/OpenTelemetry.AutoInstrumentation/Diagnostics/SdkSelfDiagnosticsEventListener.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// <copyright file="SdkSelfDiagnosticsEventListener.cs" company="OpenTelemetry Authors"> | ||
// 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. | ||
// </copyright> | ||
|
||
// Source originated from https://github.com/open-telemetry/opentelemetry-dotnet/blob/23609730ddd73c860553de847e67c9b2226cff94/src/OpenTelemetry/Internal/SelfDiagnosticsEventListener.cs | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics.Tracing; | ||
using OpenTelemetry.AutoInstrumentation.Logging; | ||
|
||
namespace OpenTelemetry.AutoInstrumentation.Diagnostics; | ||
|
||
/// <summary> | ||
/// SdkSelfDiagnosticsEventListener class enables the events from OpenTelemetry event sources | ||
/// and write the events to the OpenTelemetry.AutoInstrumentation logger | ||
/// </summary> | ||
internal class SdkSelfDiagnosticsEventListener : EventListener | ||
{ | ||
private const string EventSourceNamePrefix = "OpenTelemetry-"; | ||
|
||
private static readonly ILogger Log = OtelLogging.GetLogger(); | ||
private readonly object lockObj = new(); | ||
private readonly EventLevel logLevel; | ||
private readonly List<EventSource> eventSourcesBeforeConstructor = new(); | ||
|
||
public SdkSelfDiagnosticsEventListener(EventLevel eventLevel) | ||
{ | ||
logLevel = eventLevel; | ||
|
||
List<EventSource> eventSources; | ||
lock (lockObj) | ||
{ | ||
eventSources = this.eventSourcesBeforeConstructor; | ||
eventSourcesBeforeConstructor = null; | ||
} | ||
|
||
foreach (var eventSource in eventSources) | ||
{ | ||
EnableEvents(eventSource, logLevel, EventKeywords.All); | ||
} | ||
} | ||
|
||
protected override void OnEventSourceCreated(EventSource eventSource) | ||
{ | ||
if (eventSource.Name.StartsWith(EventSourceNamePrefix, StringComparison.Ordinal)) | ||
{ | ||
// If there are EventSource classes already initialized as of now, this method would be called from | ||
// the base class constructor before the first line of code in SelfDiagnosticsEventListener constructor. | ||
// In this case logLevel is always its default value, "LogAlways". | ||
// Thus we should save the event source and enable them later, when code runs in constructor. | ||
if (eventSourcesBeforeConstructor != null) | ||
{ | ||
lock (lockObj) | ||
{ | ||
if (eventSourcesBeforeConstructor != null) | ||
{ | ||
eventSourcesBeforeConstructor.Add(eventSource); | ||
return; | ||
} | ||
} | ||
} | ||
|
||
EnableEvents(eventSource, logLevel, EventKeywords.All); | ||
} | ||
|
||
base.OnEventSourceCreated(eventSource); | ||
} | ||
|
||
/// <summary> | ||
/// This method records the events from event sources to a local file, which is provided as a stream object by | ||
/// SelfDiagnosticsConfigRefresher class. The file size is bound to a upper limit. Once the write position | ||
/// reaches the end, it will be reset to the beginning of the file. | ||
/// </summary> | ||
/// <param name="eventData">Data of the EventSource event.</param> | ||
protected override void OnEventWritten(EventWrittenEventArgs eventData) | ||
{ | ||
var payloadArray = new object[eventData.Payload.Count]; | ||
eventData.Payload.CopyTo(payloadArray, 0); | ||
|
||
switch (eventData.Level) | ||
{ | ||
case EventLevel.Critical: | ||
case EventLevel.Error: | ||
Log.Error("EventSource={0}, Message={1}", eventData.EventSource.Name, string.Format(eventData.Message, payloadArray)); | ||
break; | ||
case EventLevel.Warning: | ||
Log.Warning("EventSource={0}, Message={1}", eventData.EventSource.Name, string.Format(eventData.Message, payloadArray)); | ||
break; | ||
case EventLevel.LogAlways: | ||
case EventLevel.Informational: | ||
Log.Information("EventSource={0}, Message={1}", eventData.EventSource.Name, string.Format(eventData.Message, payloadArray)); | ||
break; | ||
case EventLevel.Verbose: | ||
Log.Debug("EventSource={0}, Message={1}", eventData.EventSource.Name, string.Format(eventData.Message, payloadArray)); | ||
break; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
84 changes: 84 additions & 0 deletions
84
.../OpenTelemetry.AutoInstrumentation.Tests/Configuration/PluginsConfigurationHelperTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// <copyright file="PluginsConfigurationHelperTests.cs" company="OpenTelemetry Authors"> | ||
// 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. | ||
// </copyright> | ||
|
||
using System; | ||
using System.IO; | ||
using FluentAssertions; | ||
using OpenTelemetry.AutoInstrumentation.Configuration; | ||
using OpenTelemetry.Trace; | ||
using Xunit; | ||
|
||
namespace OpenTelemetry.AutoInstrumentation.Tests.Configuration; | ||
|
||
public class PluginsConfigurationHelperTests | ||
{ | ||
[Fact] | ||
public void MissingAssembly() | ||
{ | ||
var action = () => Sdk.CreateTracerProviderBuilder().InvokePlugins(new[] { "Missing.Assembly.PluginType, Missing.Assembly" }); | ||
|
||
action.Should().Throw<FileNotFoundException>(); | ||
} | ||
|
||
[Fact] | ||
public void MissingPluginTypeFromAssembly() | ||
{ | ||
var action = () => Sdk.CreateTracerProviderBuilder().InvokePlugins(new[] { "Missing.PluginType" }); | ||
|
||
action.Should().Throw<TypeLoadException>(); | ||
} | ||
|
||
[Fact] | ||
public void PluginTypeMissingExpectedMethod() | ||
{ | ||
var pluginAssemblyQualifiedName = GetType().AssemblyQualifiedName; | ||
var action = () => Sdk.CreateTracerProviderBuilder().InvokePlugins(new[] { pluginAssemblyQualifiedName }); | ||
|
||
action.Should().Throw<MissingMethodException>(); | ||
} | ||
|
||
[Fact] | ||
public void PluginTypeMissingDefaultConstructor() | ||
{ | ||
var pluginAssemblyQualifiedName = typeof(MockPluginMissingDefaultConstructor).AssemblyQualifiedName; | ||
var action = () => Sdk.CreateTracerProviderBuilder().InvokePlugins(new[] { pluginAssemblyQualifiedName }); | ||
|
||
action.Should().Throw<MissingMethodException>(); | ||
} | ||
|
||
[Fact] | ||
public void InvokePluginSuccess() | ||
{ | ||
var pluginAssemblyQualifiedName = typeof(MockPlugin).AssemblyQualifiedName; | ||
Sdk.CreateTracerProviderBuilder().InvokePlugins(new[] { pluginAssemblyQualifiedName }); | ||
} | ||
|
||
public class MockPlugin | ||
{ | ||
public TracerProviderBuilder ConfigureTracerProvider(TracerProviderBuilder builder) | ||
{ | ||
return builder; | ||
} | ||
} | ||
|
||
public class MockPluginMissingDefaultConstructor : MockPlugin | ||
{ | ||
public MockPluginMissingDefaultConstructor(string ignored) | ||
{ | ||
throw new InvalidOperationException("this plugin is not expected to be successfully constructed"); | ||
} | ||
} | ||
} |
95 changes: 95 additions & 0 deletions
95
...enTelemetry.AutoInstrumentation.Tests/Diagnostics/SdkSelfDiagnosticsEventListenerTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// <copyright file="SdkSelfDiagnosticsEventListenerTests.cs" company="OpenTelemetry Authors"> | ||
// 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. | ||
// </copyright> | ||
|
||
// Source originated from https://github.com/open-telemetry/opentelemetry-dotnet/blob/23609730ddd73c860553de847e67c9b2226cff94/test/OpenTelemetry.Tests/Internal/SelfDiagnosticsEventListenerTest.cs | ||
|
||
using System; | ||
using System.Diagnostics.Tracing; | ||
using System.IO; | ||
using FluentAssertions; | ||
using OpenTelemetry.AutoInstrumentation.Diagnostics; | ||
using Xunit; | ||
|
||
public class SdkSelfDiagnosticsEventListenerTests | ||
{ | ||
[Fact] | ||
public void EventSourceSetup_LowerSeverity() | ||
{ | ||
var originalConsoleOut = Console.Out; // preserve the original stream | ||
using var writer = new StringWriter(); | ||
var listener = new SdkSelfDiagnosticsEventListener(EventLevel.Error); | ||
|
||
// Emitting a Verbose event. Or any EventSource event with lower severity than Error. | ||
AspNetTelemetryEventSource.Log.ActivityRestored("123"); | ||
OpenTelemetrySdkEventSource.Log.ActivityStarted("Activity started", "1"); | ||
|
||
// Prepare the output for assertion | ||
writer.Flush(); | ||
var outputString = writer.GetStringBuilder().ToString(); | ||
outputString.Should().NotContain("EventSource=OpenTelemetry-Instrumentation-AspNet-Telemetry, Message=Activity restored, Id='123'"); | ||
outputString.Should().NotContain("EventSource=OpenTelemetry-Sdk, Message=Activity started."); | ||
|
||
// Cleanup | ||
Console.SetOut(originalConsoleOut); | ||
} | ||
|
||
[Fact] | ||
public void EventSourceSetup_HigherSeverity() | ||
{ | ||
// Redirect the ConsoleLogger | ||
var originalConsoleOut = Console.Out; | ||
using var writer = new StringWriter(); | ||
Console.SetOut(writer); | ||
var listener = new SdkSelfDiagnosticsEventListener(EventLevel.Verbose); | ||
|
||
// Emitting a Verbose event. Or any EventSource event with lower severity than Error. | ||
AspNetTelemetryEventSource.Log.ActivityRestored("123"); | ||
OpenTelemetrySdkEventSource.Log.ActivityStarted("Activity started", "1"); | ||
|
||
// Prepare the output for assertion | ||
writer.Flush(); | ||
var outputString = writer.GetStringBuilder().ToString(); | ||
outputString.Should().Contain("EventSource=OpenTelemetry-Instrumentation-AspNet-Telemetry, Message=Activity restored, Id='123'"); | ||
outputString.Should().Contain("EventSource=OpenTelemetry-Sdk, Message=Activity started."); | ||
|
||
// Cleanup | ||
Console.SetOut(originalConsoleOut); | ||
} | ||
|
||
[EventSource(Name = "OpenTelemetry-Instrumentation-AspNet-Telemetry", Guid = "1de158cc-f7ce-4293-bd19-2358c93c8186")] | ||
internal sealed class AspNetTelemetryEventSource : EventSource | ||
{ | ||
public static readonly AspNetTelemetryEventSource Log = new(); | ||
|
||
[Event(4, Message = "Activity restored, Id='{0}'", Level = EventLevel.Informational)] | ||
public void ActivityRestored(string id) | ||
{ | ||
this.WriteEvent(4, id); | ||
} | ||
} | ||
|
||
[EventSource(Name = "OpenTelemetry-Sdk")] | ||
internal class OpenTelemetrySdkEventSource : EventSource | ||
{ | ||
public static readonly OpenTelemetrySdkEventSource Log = new(); | ||
|
||
[Event(24, Message = "Activity started. OperationName = '{0}', Id = '{1}'.", Level = EventLevel.Verbose)] | ||
public void ActivityStarted(string operationName, string id) | ||
{ | ||
this.WriteEvent(24, operationName, id); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters