Enable unique EventSource for each project (#879)
* Enable unique EventSource for each project * updating using place from Hosting project * InstrumentationEventSource is now internal, adding EventSource to Hosting project * removing unused methods, updating messages
This commit is contained in:
parent
1ed4a28927
commit
a2b1b45c94
|
|
@ -0,0 +1,81 @@
|
||||||
|
// <copyright file="PrometheusExporterEventSource.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.Diagnostics.Tracing;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace OpenTelemetry.Exporter.Prometheus.Implementation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// EventSource events emitted from the project.
|
||||||
|
/// </summary>
|
||||||
|
[EventSource(Name = "OpenTelemetry-Exporter-Prometheus")]
|
||||||
|
internal class PrometheusExporterEventSource : EventSource
|
||||||
|
{
|
||||||
|
public static PrometheusExporterEventSource Log = new PrometheusExporterEventSource();
|
||||||
|
|
||||||
|
[NonEvent]
|
||||||
|
public void FailedExport(Exception ex)
|
||||||
|
{
|
||||||
|
if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
|
||||||
|
{
|
||||||
|
this.FailedExport(ToInvariantString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[NonEvent]
|
||||||
|
public void CanceledExport(Exception ex)
|
||||||
|
{
|
||||||
|
if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
|
||||||
|
{
|
||||||
|
this.CanceledExport(ToInvariantString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a culture-independent string representation of the given <paramref name="exception"/> object,
|
||||||
|
/// appropriate for diagnostics tracing.
|
||||||
|
/// </summary>
|
||||||
|
private static string ToInvariantString(Exception exception)
|
||||||
|
{
|
||||||
|
var originalUICulture = Thread.CurrentThread.CurrentUICulture;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||||
|
return exception.ToString();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Thread.CurrentThread.CurrentUICulture = originalUICulture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Event(1, Message = "Failed to export activities: '{0}'", Level = EventLevel.Error)]
|
||||||
|
private void FailedExport(string exception)
|
||||||
|
{
|
||||||
|
this.WriteEvent(1, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Event(2, Message = "Canceled to export activities: '{0}'", Level = EventLevel.Error)]
|
||||||
|
private void CanceledExport(string exception)
|
||||||
|
{
|
||||||
|
this.WriteEvent(2, exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -117,13 +117,13 @@ namespace OpenTelemetry.Exporter.Prometheus
|
||||||
this.exporter.WriteMetricsCollection(writer);
|
this.exporter.WriteMetricsCollection(writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException ex)
|
||||||
{
|
{
|
||||||
// this will happen when cancellation will be requested
|
PrometheusExporterEventSource.Log.CanceledExport(ex);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// TODO: report error
|
PrometheusExporterEventSource.Log.FailedExport(ex);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
// <copyright file="ZPagesExporterEventSource.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.Diagnostics.Tracing;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace OpenTelemetry.Exporter.Prometheus.Implementation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// EventSource events emitted from the project.
|
||||||
|
/// </summary>
|
||||||
|
[EventSource(Name = "OpenTelemetry-Exporter-ZPages")]
|
||||||
|
internal class ZPagesExporterEventSource : EventSource
|
||||||
|
{
|
||||||
|
public static ZPagesExporterEventSource Log = new ZPagesExporterEventSource();
|
||||||
|
|
||||||
|
[NonEvent]
|
||||||
|
public void FailedExport(Exception ex)
|
||||||
|
{
|
||||||
|
if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
|
||||||
|
{
|
||||||
|
this.FailedExport(ToInvariantString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[NonEvent]
|
||||||
|
public void CanceledExport(Exception ex)
|
||||||
|
{
|
||||||
|
if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
|
||||||
|
{
|
||||||
|
this.CanceledExport(ToInvariantString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[NonEvent]
|
||||||
|
public void FailedProcess(Exception ex)
|
||||||
|
{
|
||||||
|
if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
|
||||||
|
{
|
||||||
|
this.FailedProcess(ToInvariantString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a culture-independent string representation of the given <paramref name="exception"/> object,
|
||||||
|
/// appropriate for diagnostics tracing.
|
||||||
|
/// </summary>
|
||||||
|
private static string ToInvariantString(Exception exception)
|
||||||
|
{
|
||||||
|
var originalUICulture = Thread.CurrentThread.CurrentUICulture;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||||
|
return exception.ToString();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Thread.CurrentThread.CurrentUICulture = originalUICulture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Event(1, Message = "Failed to export activities: '{0}'", Level = EventLevel.Error)]
|
||||||
|
private void FailedExport(string exception)
|
||||||
|
{
|
||||||
|
this.WriteEvent(1, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Event(2, Message = "Canceled to export activities: '{0}'", Level = EventLevel.Error)]
|
||||||
|
private void CanceledExport(string exception)
|
||||||
|
{
|
||||||
|
this.WriteEvent(2, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Event(3, Message = "Failed to process activity: '{0}'", Level = EventLevel.Error)]
|
||||||
|
private void FailedProcess(string exception)
|
||||||
|
{
|
||||||
|
this.WriteEvent(3, exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,6 +20,7 @@ using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using OpenTelemetry.Exporter.Prometheus.Implementation;
|
||||||
using OpenTelemetry.Exporter.ZPages.Implementation;
|
using OpenTelemetry.Exporter.ZPages.Implementation;
|
||||||
#if NET452
|
#if NET452
|
||||||
using OpenTelemetry.Internal;
|
using OpenTelemetry.Internal;
|
||||||
|
|
@ -178,13 +179,13 @@ namespace OpenTelemetry.Exporter.ZPages
|
||||||
writer.WriteLine("</div></div></body></html>");
|
writer.WriteLine("</div></div></body></html>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException ex)
|
||||||
{
|
{
|
||||||
// this will happen when cancellation will be requested
|
ZPagesExporterEventSource.Log.CanceledExport(ex);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// TODO: report error
|
ZPagesExporterEventSource.Log.FailedExport(ex);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using OpenTelemetry.Exporter.Prometheus.Implementation;
|
||||||
using OpenTelemetry.Exporter.ZPages.Implementation;
|
using OpenTelemetry.Exporter.ZPages.Implementation;
|
||||||
#if NET452
|
#if NET452
|
||||||
using OpenTelemetry.Internal;
|
using OpenTelemetry.Internal;
|
||||||
|
|
@ -115,10 +116,10 @@ namespace OpenTelemetry.Exporter.ZPages
|
||||||
minuteSpanInformation.LastUpdated = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds();
|
minuteSpanInformation.LastUpdated = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds();
|
||||||
hourSpanInformation.LastUpdated = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds();
|
hourSpanInformation.LastUpdated = new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds();
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// Log.SpanProcessorException("OnEnd", ex);
|
ZPagesExporterEventSource.Log.FailedProcess(ex);
|
||||||
Console.Write("OnEnd", exception);
|
Console.Write("OnEnd", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
// <copyright file="HostingExtensionsEventSource.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.Diagnostics.Tracing;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace OpenTelemetry.Extensions.Hosting.Implementation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// EventSource events emitted from the project.
|
||||||
|
/// </summary>
|
||||||
|
[EventSource(Name = "OpenTelemetry-Extensions-Hosting")]
|
||||||
|
internal class HostingExtensionsEventSource : EventSource
|
||||||
|
{
|
||||||
|
public static HostingExtensionsEventSource Log = new HostingExtensionsEventSource();
|
||||||
|
|
||||||
|
[NonEvent]
|
||||||
|
public void FailedInitialize(Exception ex)
|
||||||
|
{
|
||||||
|
if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
|
||||||
|
{
|
||||||
|
this.FailedInitialize(ToInvariantString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[NonEvent]
|
||||||
|
public void FailedOpenTelemetrySDK(Exception ex)
|
||||||
|
{
|
||||||
|
if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
|
||||||
|
{
|
||||||
|
this.FailedOpenTelemetrySDK(ToInvariantString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a culture-independent string representation of the given <paramref name="exception"/> object,
|
||||||
|
/// appropriate for diagnostics tracing.
|
||||||
|
/// </summary>
|
||||||
|
private static string ToInvariantString(Exception exception)
|
||||||
|
{
|
||||||
|
var originalUICulture = Thread.CurrentThread.CurrentUICulture;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||||
|
return exception.ToString();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Thread.CurrentThread.CurrentUICulture = originalUICulture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Event(1, Message = "Failed to initialize: '{0}'. OpenTelemetry will not work.", Level = EventLevel.Error)]
|
||||||
|
private void FailedInitialize(string exception)
|
||||||
|
{
|
||||||
|
this.WriteEvent(1, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Event(2, Message = "Failed to get OpenTelemetrySDK: '{0}'. OpenTelemetry will not work.", Level = EventLevel.Error)]
|
||||||
|
private void FailedOpenTelemetrySDK(string exception)
|
||||||
|
{
|
||||||
|
this.WriteEvent(2, exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,15 +14,15 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
// </copyright>
|
// </copyright>
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using OpenTelemetry.Trace.Configuration;
|
||||||
|
|
||||||
namespace OpenTelemetry.Extensions.Hosting.Implementation
|
namespace OpenTelemetry.Extensions.Hosting.Implementation
|
||||||
{
|
{
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using OpenTelemetry.Trace.Configuration;
|
|
||||||
|
|
||||||
internal class TelemetryHostedService : IHostedService
|
internal class TelemetryHostedService : IHostedService
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider serviceProvider;
|
private readonly IServiceProvider serviceProvider;
|
||||||
|
|
@ -34,12 +34,19 @@ namespace OpenTelemetry.Extensions.Hosting.Implementation
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
public Task StartAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// The sole purpose of this HostedService is to ensure
|
try
|
||||||
// all instrumentations are created and started.
|
{
|
||||||
// This method is invoked when host starts, and
|
// The sole purpose of this HostedService is to ensure
|
||||||
// by requesting the OpenTelemetrySdk from DI
|
// all instrumentations are created and started.
|
||||||
// it ensures all instrumentations gets started.
|
// This method is invoked when host starts, and
|
||||||
this.serviceProvider.GetRequiredService<OpenTelemetrySdk>();
|
// by requesting the OpenTelemetrySdk from DI
|
||||||
|
// it ensures all instrumentations gets started.
|
||||||
|
this.serviceProvider.GetRequiredService<OpenTelemetrySdk>();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
HostingExtensionsEventSource.Log.FailedOpenTelemetrySDK(ex);
|
||||||
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,14 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
// </copyright>
|
// </copyright>
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using OpenTelemetry.Extensions.Hosting.Implementation;
|
||||||
|
using OpenTelemetry.Trace.Configuration;
|
||||||
|
|
||||||
namespace Microsoft.Extensions.DependencyInjection
|
namespace Microsoft.Extensions.DependencyInjection
|
||||||
{
|
{
|
||||||
using System;
|
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using OpenTelemetry.Extensions.Hosting.Implementation;
|
|
||||||
using OpenTelemetry.Trace.Configuration;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Extension methods for setting up OpenTelemetry services in an <see cref="IServiceCollection" />.
|
/// Extension methods for setting up OpenTelemetry services in an <see cref="IServiceCollection" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -80,8 +80,15 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
throw new ArgumentNullException(nameof(createSdk));
|
throw new ArgumentNullException(nameof(createSdk));
|
||||||
}
|
}
|
||||||
|
|
||||||
services.AddSingleton(s => createSdk());
|
try
|
||||||
AddOpenTelemetryInternal(services);
|
{
|
||||||
|
services.AddSingleton(s => createSdk());
|
||||||
|
AddOpenTelemetryInternal(services);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
HostingExtensionsEventSource.Log.FailedInitialize(ex);
|
||||||
|
}
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
@ -104,8 +111,15 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
throw new ArgumentNullException(nameof(createSdk));
|
throw new ArgumentNullException(nameof(createSdk));
|
||||||
}
|
}
|
||||||
|
|
||||||
services.AddSingleton(s => createSdk(s));
|
try
|
||||||
AddOpenTelemetryInternal(services);
|
{
|
||||||
|
services.AddSingleton(s => createSdk(s));
|
||||||
|
AddOpenTelemetryInternal(services);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
HostingExtensionsEventSource.Log.FailedInitialize(ex);
|
||||||
|
}
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
// <copyright file="AspNetInstrumentationEventSource.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.Diagnostics.Tracing;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace OpenTelemetry.Instrumentation.AspNet.Implementation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// EventSource events emitted from the project.
|
||||||
|
/// </summary>
|
||||||
|
[EventSource(Name = "OpenTelemetry-Instrumentation-AspNet")]
|
||||||
|
internal class AspNetInstrumentationEventSource : EventSource
|
||||||
|
{
|
||||||
|
public static AspNetInstrumentationEventSource Log = new AspNetInstrumentationEventSource();
|
||||||
|
|
||||||
|
[Event(1, Message = "Payload is NULL in event '{1}' from handler '{0}', span will not be recorded.", Level = EventLevel.Warning)]
|
||||||
|
public void NullPayload(string handlerName, string eventName)
|
||||||
|
{
|
||||||
|
this.WriteEvent(1, handlerName, eventName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Event(2, Message = "Request is filtered out.", Level = EventLevel.Verbose)]
|
||||||
|
public void RequestIsFilteredOut(string eventName)
|
||||||
|
{
|
||||||
|
this.WriteEvent(2, eventName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a culture-independent string representation of the given <paramref name="exception"/> object,
|
||||||
|
/// appropriate for diagnostics tracing.
|
||||||
|
/// </summary>
|
||||||
|
private static string ToInvariantString(Exception exception)
|
||||||
|
{
|
||||||
|
var originalUICulture = Thread.CurrentThread.CurrentUICulture;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||||
|
return exception.ToString();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Thread.CurrentThread.CurrentUICulture = originalUICulture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,207 +1,207 @@
|
||||||
// <copyright file="HttpInListener.cs" company="OpenTelemetry Authors">
|
// <copyright file="HttpInListener.cs" company="OpenTelemetry Authors">
|
||||||
// Copyright The OpenTelemetry Authors
|
// Copyright The OpenTelemetry Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
// You may obtain a copy of the License at
|
// You may obtain a copy of the License at
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
// </copyright>
|
// </copyright>
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using System.Web.Routing;
|
using System.Web.Routing;
|
||||||
using OpenTelemetry.Context.Propagation;
|
using OpenTelemetry.Context.Propagation;
|
||||||
using OpenTelemetry.Trace;
|
using OpenTelemetry.Trace;
|
||||||
|
|
||||||
namespace OpenTelemetry.Instrumentation.AspNet.Implementation
|
namespace OpenTelemetry.Instrumentation.AspNet.Implementation
|
||||||
{
|
{
|
||||||
internal class HttpInListener : ListenerHandler
|
internal class HttpInListener : ListenerHandler
|
||||||
{
|
{
|
||||||
private static readonly string ActivityNameByHttpInListener = "ActivityCreatedByHttpInListener";
|
private static readonly string ActivityNameByHttpInListener = "ActivityCreatedByHttpInListener";
|
||||||
private static readonly Func<HttpRequest, string, IEnumerable<string>> HttpRequestHeaderValuesGetter = (request, name) => request.Headers.GetValues(name);
|
private static readonly Func<HttpRequest, string, IEnumerable<string>> HttpRequestHeaderValuesGetter = (request, name) => request.Headers.GetValues(name);
|
||||||
private readonly PropertyFetcher routeFetcher = new PropertyFetcher("Route");
|
private readonly PropertyFetcher routeFetcher = new PropertyFetcher("Route");
|
||||||
private readonly PropertyFetcher routeTemplateFetcher = new PropertyFetcher("RouteTemplate");
|
private readonly PropertyFetcher routeTemplateFetcher = new PropertyFetcher("RouteTemplate");
|
||||||
private readonly AspNetInstrumentationOptions options;
|
private readonly AspNetInstrumentationOptions options;
|
||||||
private readonly ActivitySourceAdapter activitySource;
|
private readonly ActivitySourceAdapter activitySource;
|
||||||
|
|
||||||
public HttpInListener(string name, AspNetInstrumentationOptions options, ActivitySourceAdapter activitySource)
|
public HttpInListener(string name, AspNetInstrumentationOptions options, ActivitySourceAdapter activitySource)
|
||||||
: base(name)
|
: base(name)
|
||||||
{
|
{
|
||||||
this.options = options ?? throw new ArgumentNullException(nameof(options));
|
this.options = options ?? throw new ArgumentNullException(nameof(options));
|
||||||
this.activitySource = activitySource;
|
this.activitySource = activitySource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnStartActivity(Activity activity, object payload)
|
public override void OnStartActivity(Activity activity, object payload)
|
||||||
{
|
{
|
||||||
var context = HttpContext.Current;
|
var context = HttpContext.Current;
|
||||||
if (context == null)
|
if (context == null)
|
||||||
{
|
{
|
||||||
InstrumentationEventSource.Log.NullPayload(nameof(HttpInListener), nameof(this.OnStartActivity));
|
AspNetInstrumentationEventSource.Log.NullPayload(nameof(HttpInListener), nameof(this.OnStartActivity));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.RequestFilter != null && !this.options.RequestFilter(context))
|
if (this.options.RequestFilter != null && !this.options.RequestFilter(context))
|
||||||
{
|
{
|
||||||
InstrumentationEventSource.Log.RequestIsFilteredOut(activity.OperationName);
|
AspNetInstrumentationEventSource.Log.RequestIsFilteredOut(activity.OperationName);
|
||||||
activity.IsAllDataRequested = false;
|
activity.IsAllDataRequested = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var request = context.Request;
|
var request = context.Request;
|
||||||
var requestValues = request.Unvalidated;
|
var requestValues = request.Unvalidated;
|
||||||
|
|
||||||
if (!(this.options.TextFormat is TraceContextFormatActivity))
|
if (!(this.options.TextFormat is TraceContextFormatActivity))
|
||||||
{
|
{
|
||||||
// This requires to ignore the current activity and create a new one
|
// This requires to ignore the current activity and create a new one
|
||||||
// using the context extracted using the format TextFormat supports.
|
// using the context extracted using the format TextFormat supports.
|
||||||
var ctx = this.options.TextFormat.Extract(request, HttpRequestHeaderValuesGetter);
|
var ctx = this.options.TextFormat.Extract(request, HttpRequestHeaderValuesGetter);
|
||||||
|
|
||||||
// Create a new activity with its parent set from the extracted context.
|
// Create a new activity with its parent set from the extracted context.
|
||||||
// This makes the new activity as a "sibling" of the activity created by
|
// This makes the new activity as a "sibling" of the activity created by
|
||||||
// Asp.Net.
|
// Asp.Net.
|
||||||
Activity newOne = new Activity(ActivityNameByHttpInListener);
|
Activity newOne = new Activity(ActivityNameByHttpInListener);
|
||||||
newOne.SetParentId(ctx.TraceId, ctx.SpanId, ctx.TraceFlags);
|
newOne.SetParentId(ctx.TraceId, ctx.SpanId, ctx.TraceFlags);
|
||||||
newOne.TraceStateString = ctx.TraceState;
|
newOne.TraceStateString = ctx.TraceState;
|
||||||
|
|
||||||
// Starting the new activity make it the Activity.Current one.
|
// Starting the new activity make it the Activity.Current one.
|
||||||
newOne.Start();
|
newOne.Start();
|
||||||
|
|
||||||
// Both new activity and old one store the other activity
|
// Both new activity and old one store the other activity
|
||||||
// inside them. This is required in the Stop step to
|
// inside them. This is required in the Stop step to
|
||||||
// correctly stop and restore Activity.Current.
|
// correctly stop and restore Activity.Current.
|
||||||
newOne.SetCustomProperty("ActivityByAspNet", activity);
|
newOne.SetCustomProperty("ActivityByAspNet", activity);
|
||||||
activity.SetCustomProperty("ActivityByHttpInListener", newOne);
|
activity.SetCustomProperty("ActivityByHttpInListener", newOne);
|
||||||
activity = newOne;
|
activity = newOne;
|
||||||
}
|
}
|
||||||
|
|
||||||
// see the spec https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md
|
// see the spec https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md
|
||||||
var path = requestValues.Path;
|
var path = requestValues.Path;
|
||||||
activity.DisplayName = path;
|
activity.DisplayName = path;
|
||||||
|
|
||||||
activity.SetKind(ActivityKind.Server);
|
activity.SetKind(ActivityKind.Server);
|
||||||
|
|
||||||
this.activitySource.Start(activity);
|
this.activitySource.Start(activity);
|
||||||
|
|
||||||
if (activity.IsAllDataRequested)
|
if (activity.IsAllDataRequested)
|
||||||
{
|
{
|
||||||
if (request.Url.Port == 80 || request.Url.Port == 443)
|
if (request.Url.Port == 80 || request.Url.Port == 443)
|
||||||
{
|
{
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPHost, request.Url.Host);
|
activity.AddTag(SemanticConventions.AttributeHTTPHost, request.Url.Host);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPHost, request.Url.Host + ":" + request.Url.Port);
|
activity.AddTag(SemanticConventions.AttributeHTTPHost, request.Url.Host + ":" + request.Url.Port);
|
||||||
}
|
}
|
||||||
|
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPMethod, request.HttpMethod);
|
activity.AddTag(SemanticConventions.AttributeHTTPMethod, request.HttpMethod);
|
||||||
activity.AddTag(SpanAttributeConstants.HttpPathKey, path);
|
activity.AddTag(SpanAttributeConstants.HttpPathKey, path);
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPUserAgent, request.UserAgent);
|
activity.AddTag(SemanticConventions.AttributeHTTPUserAgent, request.UserAgent);
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPURL, request.Url.ToString());
|
activity.AddTag(SemanticConventions.AttributeHTTPURL, request.Url.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnStopActivity(Activity activity, object payload)
|
public override void OnStopActivity(Activity activity, object payload)
|
||||||
{
|
{
|
||||||
Activity activityToEnrich = activity;
|
Activity activityToEnrich = activity;
|
||||||
|
|
||||||
if (!(this.options.TextFormat is TraceContextFormatActivity))
|
if (!(this.options.TextFormat is TraceContextFormatActivity))
|
||||||
{
|
{
|
||||||
// If using custom context propagator, then the activity here
|
// If using custom context propagator, then the activity here
|
||||||
// could be either the one from Asp.Net, or the one
|
// could be either the one from Asp.Net, or the one
|
||||||
// this instrumentation created in Start.
|
// this instrumentation created in Start.
|
||||||
// This is because Asp.Net, under certain circumstances, restores Activity.Current
|
// This is because Asp.Net, under certain circumstances, restores Activity.Current
|
||||||
// to its own activity.
|
// to its own activity.
|
||||||
if (activity.OperationName.Equals("Microsoft.AspNet.HttpReqIn.Start"))
|
if (activity.OperationName.Equals("Microsoft.AspNet.HttpReqIn.Start"))
|
||||||
{
|
{
|
||||||
// This block is hit if Asp.Net did restore Current to its own activity,
|
// This block is hit if Asp.Net did restore Current to its own activity,
|
||||||
// then we need to retrieve the one created by HttpInListener
|
// then we need to retrieve the one created by HttpInListener
|
||||||
// and populate tags to it.
|
// and populate tags to it.
|
||||||
activityToEnrich = (Activity)activity.GetCustomProperty("ActivityByHttpInListener");
|
activityToEnrich = (Activity)activity.GetCustomProperty("ActivityByHttpInListener");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activityToEnrich.IsAllDataRequested)
|
if (activityToEnrich.IsAllDataRequested)
|
||||||
{
|
{
|
||||||
var context = HttpContext.Current;
|
var context = HttpContext.Current;
|
||||||
if (context == null)
|
if (context == null)
|
||||||
{
|
{
|
||||||
InstrumentationEventSource.Log.NullPayload(nameof(HttpInListener), nameof(this.OnStopActivity));
|
AspNetInstrumentationEventSource.Log.NullPayload(nameof(HttpInListener), nameof(this.OnStopActivity));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = context.Response;
|
var response = context.Response;
|
||||||
|
|
||||||
activityToEnrich.AddTag(SemanticConventions.AttributeHTTPStatusCode, response.StatusCode.ToString());
|
activityToEnrich.AddTag(SemanticConventions.AttributeHTTPStatusCode, response.StatusCode.ToString());
|
||||||
|
|
||||||
activityToEnrich.SetStatus(
|
activityToEnrich.SetStatus(
|
||||||
SpanHelper
|
SpanHelper
|
||||||
.ResolveSpanStatusForHttpStatusCode(response.StatusCode)
|
.ResolveSpanStatusForHttpStatusCode(response.StatusCode)
|
||||||
.WithDescription(response.StatusDescription));
|
.WithDescription(response.StatusDescription));
|
||||||
|
|
||||||
var routeData = context.Request.RequestContext.RouteData;
|
var routeData = context.Request.RequestContext.RouteData;
|
||||||
|
|
||||||
string template = null;
|
string template = null;
|
||||||
if (routeData.Values.TryGetValue("MS_SubRoutes", out object msSubRoutes))
|
if (routeData.Values.TryGetValue("MS_SubRoutes", out object msSubRoutes))
|
||||||
{
|
{
|
||||||
// WebAPI attribute routing flows here. Use reflection to not take a dependency on microsoft.aspnet.webapi.core\[version]\lib\[framework]\System.Web.Http.
|
// WebAPI attribute routing flows here. Use reflection to not take a dependency on microsoft.aspnet.webapi.core\[version]\lib\[framework]\System.Web.Http.
|
||||||
|
|
||||||
if (msSubRoutes is Array attributeRouting && attributeRouting.Length == 1)
|
if (msSubRoutes is Array attributeRouting && attributeRouting.Length == 1)
|
||||||
{
|
{
|
||||||
var subRouteData = attributeRouting.GetValue(0);
|
var subRouteData = attributeRouting.GetValue(0);
|
||||||
|
|
||||||
var route = this.routeFetcher.Fetch(subRouteData);
|
var route = this.routeFetcher.Fetch(subRouteData);
|
||||||
template = this.routeTemplateFetcher.Fetch(route) as string;
|
template = this.routeTemplateFetcher.Fetch(route) as string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (routeData.Route is Route route)
|
else if (routeData.Route is Route route)
|
||||||
{
|
{
|
||||||
// MVC + WebAPI traditional routing & MVC attribute routing flow here.
|
// MVC + WebAPI traditional routing & MVC attribute routing flow here.
|
||||||
template = route.Url;
|
template = route.Url;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(template))
|
if (!string.IsNullOrEmpty(template))
|
||||||
{
|
{
|
||||||
// Override the name that was previously set to the path part of URL.
|
// Override the name that was previously set to the path part of URL.
|
||||||
activityToEnrich.DisplayName = template;
|
activityToEnrich.DisplayName = template;
|
||||||
activityToEnrich.AddTag(SemanticConventions.AttributeHTTPRoute, template);
|
activityToEnrich.AddTag(SemanticConventions.AttributeHTTPRoute, template);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(this.options.TextFormat is TraceContextFormatActivity))
|
if (!(this.options.TextFormat is TraceContextFormatActivity))
|
||||||
{
|
{
|
||||||
if (activity.OperationName.Equals(ActivityNameByHttpInListener))
|
if (activity.OperationName.Equals(ActivityNameByHttpInListener))
|
||||||
{
|
{
|
||||||
// If instrumentation started a new Activity, it must
|
// If instrumentation started a new Activity, it must
|
||||||
// be stopped here.
|
// be stopped here.
|
||||||
activity.Stop();
|
activity.Stop();
|
||||||
|
|
||||||
// Restore the original activity as Current.
|
// Restore the original activity as Current.
|
||||||
var activityByAspNet = (Activity)activity.GetCustomProperty("ActivityByAspNet");
|
var activityByAspNet = (Activity)activity.GetCustomProperty("ActivityByAspNet");
|
||||||
Activity.Current = activityByAspNet;
|
Activity.Current = activityByAspNet;
|
||||||
}
|
}
|
||||||
else if (activity.OperationName.Equals("Microsoft.AspNet.HttpReqIn.Start"))
|
else if (activity.OperationName.Equals("Microsoft.AspNet.HttpReqIn.Start"))
|
||||||
{
|
{
|
||||||
// This block is hit if Asp.Net did restore Current to its own activity,
|
// This block is hit if Asp.Net did restore Current to its own activity,
|
||||||
// then we need to retrieve the one created by HttpInListener
|
// then we need to retrieve the one created by HttpInListener
|
||||||
// and stop it.
|
// and stop it.
|
||||||
var activityByHttpInListener = (Activity)activity.GetCustomProperty("ActivityByHttpInListener");
|
var activityByHttpInListener = (Activity)activity.GetCustomProperty("ActivityByHttpInListener");
|
||||||
activityByHttpInListener.Stop();
|
activityByHttpInListener.Stop();
|
||||||
|
|
||||||
// Restore current back to the one created by Asp.Net
|
// Restore current back to the one created by Asp.Net
|
||||||
Activity.Current = activity;
|
Activity.Current = activity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.activitySource.Stop(activityToEnrich);
|
this.activitySource.Stop(activityToEnrich);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
// <copyright file="AspNetCoreInstrumentationEventSource.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.Diagnostics.Tracing;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace OpenTelemetry.Instrumentation.AspNetCore.Implementation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// EventSource events emitted from the project.
|
||||||
|
/// </summary>
|
||||||
|
[EventSource(Name = "OpenTelemetry-Instrumentation-AspNetCore")]
|
||||||
|
internal class AspNetCoreInstrumentationEventSource : EventSource
|
||||||
|
{
|
||||||
|
public static AspNetCoreInstrumentationEventSource Log = new AspNetCoreInstrumentationEventSource();
|
||||||
|
|
||||||
|
[Event(1, Message = "Payload is NULL in event '{1}' from handler '{0}', span will not be recorded.", Level = EventLevel.Warning)]
|
||||||
|
public void NullPayload(string handlerName, string eventName)
|
||||||
|
{
|
||||||
|
this.WriteEvent(1, handlerName, eventName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Event(2, Message = "Request is filtered out.", Level = EventLevel.Verbose)]
|
||||||
|
public void RequestIsFilteredOut(string eventName)
|
||||||
|
{
|
||||||
|
this.WriteEvent(2, eventName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a culture-independent string representation of the given <paramref name="exception"/> object,
|
||||||
|
/// appropriate for diagnostics tracing.
|
||||||
|
/// </summary>
|
||||||
|
private static string ToInvariantString(Exception exception)
|
||||||
|
{
|
||||||
|
var originalUICulture = Thread.CurrentThread.CurrentUICulture;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||||
|
return exception.ToString();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Thread.CurrentThread.CurrentUICulture = originalUICulture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,224 +1,224 @@
|
||||||
// <copyright file="HttpInListener.cs" company="OpenTelemetry Authors">
|
// <copyright file="HttpInListener.cs" company="OpenTelemetry Authors">
|
||||||
// Copyright The OpenTelemetry Authors
|
// Copyright The OpenTelemetry Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
// You may obtain a copy of the License at
|
// You may obtain a copy of the License at
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
// </copyright>
|
// </copyright>
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using OpenTelemetry.Context.Propagation;
|
using OpenTelemetry.Context.Propagation;
|
||||||
using OpenTelemetry.Trace;
|
using OpenTelemetry.Trace;
|
||||||
|
|
||||||
namespace OpenTelemetry.Instrumentation.AspNetCore.Implementation
|
namespace OpenTelemetry.Instrumentation.AspNetCore.Implementation
|
||||||
{
|
{
|
||||||
internal class HttpInListener : ListenerHandler
|
internal class HttpInListener : ListenerHandler
|
||||||
{
|
{
|
||||||
private static readonly string UnknownHostName = "UNKNOWN-HOST";
|
private static readonly string UnknownHostName = "UNKNOWN-HOST";
|
||||||
private static readonly string ActivityNameByHttpInListener = "ActivityCreatedByHttpInListener";
|
private static readonly string ActivityNameByHttpInListener = "ActivityCreatedByHttpInListener";
|
||||||
private static readonly Func<HttpRequest, string, IEnumerable<string>> HttpRequestHeaderValuesGetter = (request, name) => request.Headers[name];
|
private static readonly Func<HttpRequest, string, IEnumerable<string>> HttpRequestHeaderValuesGetter = (request, name) => request.Headers[name];
|
||||||
private readonly PropertyFetcher startContextFetcher = new PropertyFetcher("HttpContext");
|
private readonly PropertyFetcher startContextFetcher = new PropertyFetcher("HttpContext");
|
||||||
private readonly PropertyFetcher stopContextFetcher = new PropertyFetcher("HttpContext");
|
private readonly PropertyFetcher stopContextFetcher = new PropertyFetcher("HttpContext");
|
||||||
private readonly PropertyFetcher beforeActionActionDescriptorFetcher = new PropertyFetcher("actionDescriptor");
|
private readonly PropertyFetcher beforeActionActionDescriptorFetcher = new PropertyFetcher("actionDescriptor");
|
||||||
private readonly PropertyFetcher beforeActionAttributeRouteInfoFetcher = new PropertyFetcher("AttributeRouteInfo");
|
private readonly PropertyFetcher beforeActionAttributeRouteInfoFetcher = new PropertyFetcher("AttributeRouteInfo");
|
||||||
private readonly PropertyFetcher beforeActionTemplateFetcher = new PropertyFetcher("Template");
|
private readonly PropertyFetcher beforeActionTemplateFetcher = new PropertyFetcher("Template");
|
||||||
private readonly bool hostingSupportsW3C = false;
|
private readonly bool hostingSupportsW3C = false;
|
||||||
private readonly AspNetCoreInstrumentationOptions options;
|
private readonly AspNetCoreInstrumentationOptions options;
|
||||||
private readonly ActivitySourceAdapter activitySource;
|
private readonly ActivitySourceAdapter activitySource;
|
||||||
|
|
||||||
public HttpInListener(string name, AspNetCoreInstrumentationOptions options, ActivitySourceAdapter activitySource)
|
public HttpInListener(string name, AspNetCoreInstrumentationOptions options, ActivitySourceAdapter activitySource)
|
||||||
: base(name)
|
: base(name)
|
||||||
{
|
{
|
||||||
this.hostingSupportsW3C = typeof(HttpRequest).Assembly.GetName().Version.Major >= 3;
|
this.hostingSupportsW3C = typeof(HttpRequest).Assembly.GetName().Version.Major >= 3;
|
||||||
this.options = options ?? throw new ArgumentNullException(nameof(options));
|
this.options = options ?? throw new ArgumentNullException(nameof(options));
|
||||||
this.activitySource = activitySource;
|
this.activitySource = activitySource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnStartActivity(Activity activity, object payload)
|
public override void OnStartActivity(Activity activity, object payload)
|
||||||
{
|
{
|
||||||
var context = this.startContextFetcher.Fetch(payload) as HttpContext;
|
var context = this.startContextFetcher.Fetch(payload) as HttpContext;
|
||||||
|
|
||||||
if (context == null)
|
if (context == null)
|
||||||
{
|
{
|
||||||
InstrumentationEventSource.Log.NullPayload(nameof(HttpInListener), nameof(this.OnStartActivity));
|
AspNetCoreInstrumentationEventSource.Log.NullPayload(nameof(HttpInListener), nameof(this.OnStartActivity));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.RequestFilter != null && !this.options.RequestFilter(context))
|
if (this.options.RequestFilter != null && !this.options.RequestFilter(context))
|
||||||
{
|
{
|
||||||
InstrumentationEventSource.Log.RequestIsFilteredOut(activity.OperationName);
|
AspNetCoreInstrumentationEventSource.Log.RequestIsFilteredOut(activity.OperationName);
|
||||||
activity.IsAllDataRequested = false;
|
activity.IsAllDataRequested = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var request = context.Request;
|
var request = context.Request;
|
||||||
if (!this.hostingSupportsW3C || !(this.options.TextFormat is TraceContextFormatActivity))
|
if (!this.hostingSupportsW3C || !(this.options.TextFormat is TraceContextFormatActivity))
|
||||||
{
|
{
|
||||||
// This requires to ignore the current activity and create a new one
|
// This requires to ignore the current activity and create a new one
|
||||||
// using the context extracted from w3ctraceparent header or
|
// using the context extracted from w3ctraceparent header or
|
||||||
// using the format TextFormat supports.
|
// using the format TextFormat supports.
|
||||||
|
|
||||||
var ctx = this.options.TextFormat.Extract(request, HttpRequestHeaderValuesGetter);
|
var ctx = this.options.TextFormat.Extract(request, HttpRequestHeaderValuesGetter);
|
||||||
|
|
||||||
// Create a new activity with its parent set from the extracted context.
|
// Create a new activity with its parent set from the extracted context.
|
||||||
// This makes the new activity as a "sibling" of the activity created by
|
// This makes the new activity as a "sibling" of the activity created by
|
||||||
// Asp.Net Core.
|
// Asp.Net Core.
|
||||||
Activity newOne = new Activity(ActivityNameByHttpInListener);
|
Activity newOne = new Activity(ActivityNameByHttpInListener);
|
||||||
newOne.SetParentId(ctx.TraceId, ctx.SpanId, ctx.TraceFlags);
|
newOne.SetParentId(ctx.TraceId, ctx.SpanId, ctx.TraceFlags);
|
||||||
newOne.TraceStateString = ctx.TraceState;
|
newOne.TraceStateString = ctx.TraceState;
|
||||||
|
|
||||||
// Starting the new activity make it the Activity.Current one.
|
// Starting the new activity make it the Activity.Current one.
|
||||||
newOne.Start();
|
newOne.Start();
|
||||||
activity = newOne;
|
activity = newOne;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move setting displayname to inside IsAllDataRequested?
|
// TODO: move setting displayname to inside IsAllDataRequested?
|
||||||
var path = (request.PathBase.HasValue || request.Path.HasValue) ? (request.PathBase + request.Path).ToString() : "/";
|
var path = (request.PathBase.HasValue || request.Path.HasValue) ? (request.PathBase + request.Path).ToString() : "/";
|
||||||
activity.DisplayName = path;
|
activity.DisplayName = path;
|
||||||
|
|
||||||
activity.SetKind(ActivityKind.Server);
|
activity.SetKind(ActivityKind.Server);
|
||||||
|
|
||||||
this.activitySource.Start(activity);
|
this.activitySource.Start(activity);
|
||||||
|
|
||||||
if (activity.IsAllDataRequested)
|
if (activity.IsAllDataRequested)
|
||||||
{
|
{
|
||||||
// see the spec https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md
|
// see the spec https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-semantic-conventions.md
|
||||||
|
|
||||||
if (request.Host.Port == 80 || request.Host.Port == 443)
|
if (request.Host.Port == 80 || request.Host.Port == 443)
|
||||||
{
|
{
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPHost, request.Host.Host);
|
activity.AddTag(SemanticConventions.AttributeHTTPHost, request.Host.Host);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPHost, request.Host.Host + ":" + request.Host.Port);
|
activity.AddTag(SemanticConventions.AttributeHTTPHost, request.Host.Host + ":" + request.Host.Port);
|
||||||
}
|
}
|
||||||
|
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPMethod, request.Method);
|
activity.AddTag(SemanticConventions.AttributeHTTPMethod, request.Method);
|
||||||
activity.AddTag(SpanAttributeConstants.HttpPathKey, path);
|
activity.AddTag(SpanAttributeConstants.HttpPathKey, path);
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPURL, GetUri(request));
|
activity.AddTag(SemanticConventions.AttributeHTTPURL, GetUri(request));
|
||||||
|
|
||||||
var userAgent = request.Headers["User-Agent"].FirstOrDefault();
|
var userAgent = request.Headers["User-Agent"].FirstOrDefault();
|
||||||
if (!string.IsNullOrEmpty(userAgent))
|
if (!string.IsNullOrEmpty(userAgent))
|
||||||
{
|
{
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPUserAgent, userAgent);
|
activity.AddTag(SemanticConventions.AttributeHTTPUserAgent, userAgent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnStopActivity(Activity activity, object payload)
|
public override void OnStopActivity(Activity activity, object payload)
|
||||||
{
|
{
|
||||||
if (activity.IsAllDataRequested)
|
if (activity.IsAllDataRequested)
|
||||||
{
|
{
|
||||||
if (!(this.stopContextFetcher.Fetch(payload) is HttpContext context))
|
if (!(this.stopContextFetcher.Fetch(payload) is HttpContext context))
|
||||||
{
|
{
|
||||||
InstrumentationEventSource.Log.NullPayload(nameof(HttpInListener), nameof(this.OnStopActivity));
|
AspNetCoreInstrumentationEventSource.Log.NullPayload(nameof(HttpInListener), nameof(this.OnStopActivity));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = context.Response;
|
var response = context.Response;
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPStatusCode, response.StatusCode.ToString());
|
activity.AddTag(SemanticConventions.AttributeHTTPStatusCode, response.StatusCode.ToString());
|
||||||
|
|
||||||
Status status = SpanHelper.ResolveSpanStatusForHttpStatusCode(response.StatusCode);
|
Status status = SpanHelper.ResolveSpanStatusForHttpStatusCode(response.StatusCode);
|
||||||
activity.SetStatus(status.WithDescription(response.HttpContext.Features.Get<IHttpResponseFeature>()?.ReasonPhrase));
|
activity.SetStatus(status.WithDescription(response.HttpContext.Features.Get<IHttpResponseFeature>()?.ReasonPhrase));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activity.OperationName.Equals(ActivityNameByHttpInListener))
|
if (activity.OperationName.Equals(ActivityNameByHttpInListener))
|
||||||
{
|
{
|
||||||
// If instrumentation started a new Activity, it must
|
// If instrumentation started a new Activity, it must
|
||||||
// be stopped here.
|
// be stopped here.
|
||||||
activity.Stop();
|
activity.Stop();
|
||||||
|
|
||||||
// After the activity.Stop() code, Activity.Current becomes null.
|
// After the activity.Stop() code, Activity.Current becomes null.
|
||||||
// If Asp.Net Core uses Activity.Current?.Stop() - it'll not stop the activity
|
// If Asp.Net Core uses Activity.Current?.Stop() - it'll not stop the activity
|
||||||
// it created.
|
// it created.
|
||||||
// Currently Asp.Net core does not use Activity.Current, instead it stores a
|
// Currently Asp.Net core does not use Activity.Current, instead it stores a
|
||||||
// reference to its activity, and calls .Stop on it.
|
// reference to its activity, and calls .Stop on it.
|
||||||
|
|
||||||
// TODO: Should we still restore Activity.Current here?
|
// TODO: Should we still restore Activity.Current here?
|
||||||
// If yes, then we need to store the asp.net core activity inside
|
// If yes, then we need to store the asp.net core activity inside
|
||||||
// the one created by the instrumentation.
|
// the one created by the instrumentation.
|
||||||
// And retrieve it here, and set it to Current.
|
// And retrieve it here, and set it to Current.
|
||||||
}
|
}
|
||||||
|
|
||||||
this.activitySource.Stop(activity);
|
this.activitySource.Stop(activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnCustom(string name, Activity activity, object payload)
|
public override void OnCustom(string name, Activity activity, object payload)
|
||||||
{
|
{
|
||||||
if (name == "Microsoft.AspNetCore.Mvc.BeforeAction")
|
if (name == "Microsoft.AspNetCore.Mvc.BeforeAction")
|
||||||
{
|
{
|
||||||
if (activity.IsAllDataRequested)
|
if (activity.IsAllDataRequested)
|
||||||
{
|
{
|
||||||
// See https://github.com/aspnet/Mvc/blob/2414db256f32a047770326d14d8b0e2afd49ba49/src/Microsoft.AspNetCore.Mvc.Core/MvcCoreDiagnosticSourceExtensions.cs#L36-L44
|
// See https://github.com/aspnet/Mvc/blob/2414db256f32a047770326d14d8b0e2afd49ba49/src/Microsoft.AspNetCore.Mvc.Core/MvcCoreDiagnosticSourceExtensions.cs#L36-L44
|
||||||
// Reflection accessing: ActionDescriptor.AttributeRouteInfo.Template
|
// Reflection accessing: ActionDescriptor.AttributeRouteInfo.Template
|
||||||
// The reason to use reflection is to avoid a reference on MVC package.
|
// The reason to use reflection is to avoid a reference on MVC package.
|
||||||
// This package can be used with non-MVC apps and this logic simply wouldn't run.
|
// This package can be used with non-MVC apps and this logic simply wouldn't run.
|
||||||
// Taking reference on MVC will increase size of deployment for non-MVC apps.
|
// Taking reference on MVC will increase size of deployment for non-MVC apps.
|
||||||
var actionDescriptor = this.beforeActionActionDescriptorFetcher.Fetch(payload);
|
var actionDescriptor = this.beforeActionActionDescriptorFetcher.Fetch(payload);
|
||||||
var attributeRouteInfo = this.beforeActionAttributeRouteInfoFetcher.Fetch(actionDescriptor);
|
var attributeRouteInfo = this.beforeActionAttributeRouteInfoFetcher.Fetch(actionDescriptor);
|
||||||
var template = this.beforeActionTemplateFetcher.Fetch(attributeRouteInfo) as string;
|
var template = this.beforeActionTemplateFetcher.Fetch(attributeRouteInfo) as string;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(template))
|
if (!string.IsNullOrEmpty(template))
|
||||||
{
|
{
|
||||||
// override the span name that was previously set to the path part of URL.
|
// override the span name that was previously set to the path part of URL.
|
||||||
activity.DisplayName = template;
|
activity.DisplayName = template;
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPRoute, template);
|
activity.AddTag(SemanticConventions.AttributeHTTPRoute, template);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Should we get values from RouteData?
|
// TODO: Should we get values from RouteData?
|
||||||
// private readonly PropertyFetcher beforActionRouteDataFetcher = new PropertyFetcher("routeData");
|
// private readonly PropertyFetcher beforActionRouteDataFetcher = new PropertyFetcher("routeData");
|
||||||
// var routeData = this.beforActionRouteDataFetcher.Fetch(payload) as RouteData;
|
// var routeData = this.beforActionRouteDataFetcher.Fetch(payload) as RouteData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetUri(HttpRequest request)
|
private static string GetUri(HttpRequest request)
|
||||||
{
|
{
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
|
|
||||||
builder.Append(request.Scheme).Append("://");
|
builder.Append(request.Scheme).Append("://");
|
||||||
|
|
||||||
if (request.Host.HasValue)
|
if (request.Host.HasValue)
|
||||||
{
|
{
|
||||||
builder.Append(request.Host.Value);
|
builder.Append(request.Host.Value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// HTTP 1.0 request with NO host header would result in empty Host.
|
// HTTP 1.0 request with NO host header would result in empty Host.
|
||||||
// Use placeholder to avoid incorrect URL like "http:///"
|
// Use placeholder to avoid incorrect URL like "http:///"
|
||||||
builder.Append(UnknownHostName);
|
builder.Append(UnknownHostName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.PathBase.HasValue)
|
if (request.PathBase.HasValue)
|
||||||
{
|
{
|
||||||
builder.Append(request.PathBase.Value);
|
builder.Append(request.PathBase.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.Path.HasValue)
|
if (request.Path.HasValue)
|
||||||
{
|
{
|
||||||
builder.Append(request.Path.Value);
|
builder.Append(request.Path.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.QueryString.HasValue)
|
if (request.QueryString.HasValue)
|
||||||
{
|
{
|
||||||
builder.Append(request.QueryString);
|
builder.Append(request.QueryString);
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,114 @@
|
||||||
|
// <copyright file="DependenciesInstrumentationEventSource.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.Diagnostics.Tracing;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace OpenTelemetry.Instrumentation.Dependencies.Implementation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// EventSource events emitted from the project.
|
||||||
|
/// </summary>
|
||||||
|
[EventSource(Name = "OpenTelemetry-Instrumentation-Dependencies")]
|
||||||
|
internal class DependenciesInstrumentationEventSource : EventSource
|
||||||
|
{
|
||||||
|
public static DependenciesInstrumentationEventSource Log = new DependenciesInstrumentationEventSource();
|
||||||
|
|
||||||
|
[NonEvent]
|
||||||
|
public void UnknownErrorProcessingEvent(string handlerName, string eventName, Exception ex)
|
||||||
|
{
|
||||||
|
if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
|
||||||
|
{
|
||||||
|
this.UnknownErrorProcessingEvent(handlerName, eventName, ToInvariantString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[NonEvent]
|
||||||
|
public void FailedProcessResult(Exception ex)
|
||||||
|
{
|
||||||
|
if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
|
||||||
|
{
|
||||||
|
this.FailedProcessResult(ToInvariantString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[NonEvent]
|
||||||
|
public void ExceptionInitializingInstrumentation(string instrumentationType, Exception ex)
|
||||||
|
{
|
||||||
|
if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
|
||||||
|
{
|
||||||
|
this.ExceptionInitializingInstrumentation(instrumentationType, ToInvariantString(ex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Event(4, Message = "Current Activity is NULL the '{0}' callback. Span will not be recorded.", Level = EventLevel.Warning)]
|
||||||
|
public void NullActivity(string eventName)
|
||||||
|
{
|
||||||
|
this.WriteEvent(4, eventName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Event(5, Message = "Payload is NULL in event '{1}' from handler '{0}', span will not be recorded.", Level = EventLevel.Warning)]
|
||||||
|
public void NullPayload(string handlerName, string eventName)
|
||||||
|
{
|
||||||
|
this.WriteEvent(5, handlerName, eventName);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Event(6, Message = "Payload is invalid in event '{1}' from handler '{0}', span will not be recorded.", Level = EventLevel.Warning)]
|
||||||
|
public void InvalidPayload(string handlerName, string eventName)
|
||||||
|
{
|
||||||
|
this.WriteEvent(6, handlerName, eventName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a culture-independent string representation of the given <paramref name="exception"/> object,
|
||||||
|
/// appropriate for diagnostics tracing.
|
||||||
|
/// </summary>
|
||||||
|
private static string ToInvariantString(Exception exception)
|
||||||
|
{
|
||||||
|
var originalUICulture = Thread.CurrentThread.CurrentUICulture;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
|
||||||
|
return exception.ToString();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Thread.CurrentThread.CurrentUICulture = originalUICulture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Event(1, Message = "Unknown error processing event '{1}' from handler '{0}', Exception: {2}", Level = EventLevel.Error)]
|
||||||
|
private void UnknownErrorProcessingEvent(string handlerName, string eventName, string ex)
|
||||||
|
{
|
||||||
|
this.WriteEvent(1, handlerName, eventName, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Event(2, Message = "Failed to process result: '{0}'", Level = EventLevel.Error)]
|
||||||
|
private void FailedProcessResult(string ex)
|
||||||
|
{
|
||||||
|
this.WriteEvent(2, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Event(3, Message = "Error initializing instrumentation type {0}. Exception : {1}", Level = EventLevel.Error)]
|
||||||
|
private void ExceptionInitializingInstrumentation(string instrumentationType, string ex)
|
||||||
|
{
|
||||||
|
this.WriteEvent(3, instrumentationType, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -41,7 +41,7 @@ namespace OpenTelemetry.Instrumentation.Dependencies.Implementation
|
||||||
{
|
{
|
||||||
if (!(this.startRequestFetcher.Fetch(payload) is HttpRequestMessage request))
|
if (!(this.startRequestFetcher.Fetch(payload) is HttpRequestMessage request))
|
||||||
{
|
{
|
||||||
InstrumentationEventSource.Log.NullPayload(nameof(GrpcClientDiagnosticListener), nameof(this.OnStartActivity));
|
DependenciesInstrumentationEventSource.Log.NullPayload(nameof(GrpcClientDiagnosticListener), nameof(this.OnStartActivity));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,34 @@
|
||||||
// <copyright file="HttpHandlerDiagnosticListener.cs" company="OpenTelemetry Authors">
|
// <copyright file="HttpHandlerDiagnosticListener.cs" company="OpenTelemetry Authors">
|
||||||
// Copyright The OpenTelemetry Authors
|
// Copyright The OpenTelemetry Authors
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
// You may obtain a copy of the License at
|
// You may obtain a copy of the License at
|
||||||
//
|
//
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
// </copyright>
|
// </copyright>
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using OpenTelemetry.Context.Propagation;
|
using OpenTelemetry.Context.Propagation;
|
||||||
using OpenTelemetry.Trace;
|
using OpenTelemetry.Trace;
|
||||||
|
|
||||||
namespace OpenTelemetry.Instrumentation.Dependencies.Implementation
|
namespace OpenTelemetry.Instrumentation.Dependencies.Implementation
|
||||||
{
|
{
|
||||||
internal class HttpHandlerDiagnosticListener : ListenerHandler
|
internal class HttpHandlerDiagnosticListener : ListenerHandler
|
||||||
{
|
{
|
||||||
private static readonly Func<HttpRequestMessage, string, IEnumerable<string>> HttpRequestMessageHeaderValuesGetter = (request, name) =>
|
private static readonly Func<HttpRequestMessage, string, IEnumerable<string>> HttpRequestMessageHeaderValuesGetter = (request, name) =>
|
||||||
{
|
{
|
||||||
if (request.Headers.TryGetValues(name, out var values))
|
if (request.Headers.TryGetValues(name, out var values))
|
||||||
|
|
@ -40,142 +40,142 @@ namespace OpenTelemetry.Instrumentation.Dependencies.Implementation
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly Action<HttpRequestMessage, string, string> HttpRequestMessageHeaderValueSetter = (request, name, value) => request.Headers.Add(name, value);
|
private static readonly Action<HttpRequestMessage, string, string> HttpRequestMessageHeaderValueSetter = (request, name, value) => request.Headers.Add(name, value);
|
||||||
|
|
||||||
private static readonly Regex CoreAppMajorVersionCheckRegex = new Regex("^\\.NETCoreApp,Version=v(\\d+)\\.", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
private static readonly Regex CoreAppMajorVersionCheckRegex = new Regex("^\\.NETCoreApp,Version=v(\\d+)\\.", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
private readonly ActivitySourceAdapter activitySource;
|
private readonly ActivitySourceAdapter activitySource;
|
||||||
private readonly PropertyFetcher startRequestFetcher = new PropertyFetcher("Request");
|
private readonly PropertyFetcher startRequestFetcher = new PropertyFetcher("Request");
|
||||||
private readonly PropertyFetcher stopResponseFetcher = new PropertyFetcher("Response");
|
private readonly PropertyFetcher stopResponseFetcher = new PropertyFetcher("Response");
|
||||||
private readonly PropertyFetcher stopExceptionFetcher = new PropertyFetcher("Exception");
|
private readonly PropertyFetcher stopExceptionFetcher = new PropertyFetcher("Exception");
|
||||||
private readonly PropertyFetcher stopRequestStatusFetcher = new PropertyFetcher("RequestTaskStatus");
|
private readonly PropertyFetcher stopRequestStatusFetcher = new PropertyFetcher("RequestTaskStatus");
|
||||||
private readonly bool httpClientSupportsW3C = false;
|
private readonly bool httpClientSupportsW3C = false;
|
||||||
private readonly HttpClientInstrumentationOptions options;
|
private readonly HttpClientInstrumentationOptions options;
|
||||||
|
|
||||||
public HttpHandlerDiagnosticListener(HttpClientInstrumentationOptions options, ActivitySourceAdapter activitySource)
|
public HttpHandlerDiagnosticListener(HttpClientInstrumentationOptions options, ActivitySourceAdapter activitySource)
|
||||||
: base("HttpHandlerDiagnosticListener")
|
: base("HttpHandlerDiagnosticListener")
|
||||||
{
|
{
|
||||||
var framework = Assembly
|
var framework = Assembly
|
||||||
.GetEntryAssembly()?
|
.GetEntryAssembly()?
|
||||||
.GetCustomAttribute<TargetFrameworkAttribute>()?
|
.GetCustomAttribute<TargetFrameworkAttribute>()?
|
||||||
.FrameworkName;
|
.FrameworkName;
|
||||||
|
|
||||||
// Depending on the .NET version/flavor this will look like
|
// Depending on the .NET version/flavor this will look like
|
||||||
// '.NETCoreApp,Version=v3.0', '.NETCoreApp,Version = v2.2' or '.NETFramework,Version = v4.7.1'
|
// '.NETCoreApp,Version=v3.0', '.NETCoreApp,Version = v2.2' or '.NETFramework,Version = v4.7.1'
|
||||||
|
|
||||||
if (framework != null)
|
if (framework != null)
|
||||||
{
|
{
|
||||||
var match = CoreAppMajorVersionCheckRegex.Match(framework);
|
var match = CoreAppMajorVersionCheckRegex.Match(framework);
|
||||||
|
|
||||||
this.httpClientSupportsW3C = match.Success && int.Parse(match.Groups[1].Value) >= 3;
|
this.httpClientSupportsW3C = match.Success && int.Parse(match.Groups[1].Value) >= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.activitySource = activitySource;
|
this.activitySource = activitySource;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnStartActivity(Activity activity, object payload)
|
public override void OnStartActivity(Activity activity, object payload)
|
||||||
{
|
{
|
||||||
if (!(this.startRequestFetcher.Fetch(payload) is HttpRequestMessage request))
|
if (!(this.startRequestFetcher.Fetch(payload) is HttpRequestMessage request))
|
||||||
{
|
{
|
||||||
InstrumentationEventSource.Log.NullPayload(nameof(HttpHandlerDiagnosticListener), nameof(this.OnStartActivity));
|
DependenciesInstrumentationEventSource.Log.NullPayload(nameof(HttpHandlerDiagnosticListener), nameof(this.OnStartActivity));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.TextFormat.IsInjected(request, HttpRequestMessageHeaderValuesGetter))
|
if (this.options.TextFormat.IsInjected(request, HttpRequestMessageHeaderValuesGetter))
|
||||||
{
|
{
|
||||||
// this request is already instrumented, we should back off
|
// this request is already instrumented, we should back off
|
||||||
activity.IsAllDataRequested = false;
|
activity.IsAllDataRequested = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
activity.SetKind(ActivityKind.Client);
|
activity.SetKind(ActivityKind.Client);
|
||||||
activity.DisplayName = HttpTagHelper.GetOperationNameForHttpMethod(request.Method);
|
activity.DisplayName = HttpTagHelper.GetOperationNameForHttpMethod(request.Method);
|
||||||
|
|
||||||
this.activitySource.Start(activity);
|
this.activitySource.Start(activity);
|
||||||
|
|
||||||
if (activity.IsAllDataRequested)
|
if (activity.IsAllDataRequested)
|
||||||
{
|
{
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPMethod, HttpTagHelper.GetNameForHttpMethod(request.Method));
|
activity.AddTag(SemanticConventions.AttributeHTTPMethod, HttpTagHelper.GetNameForHttpMethod(request.Method));
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPHost, HttpTagHelper.GetHostTagValueFromRequestUri(request.RequestUri));
|
activity.AddTag(SemanticConventions.AttributeHTTPHost, HttpTagHelper.GetHostTagValueFromRequestUri(request.RequestUri));
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPURL, request.RequestUri.OriginalString);
|
activity.AddTag(SemanticConventions.AttributeHTTPURL, request.RequestUri.OriginalString);
|
||||||
|
|
||||||
if (this.options.SetHttpFlavor)
|
if (this.options.SetHttpFlavor)
|
||||||
{
|
{
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPFlavor, HttpTagHelper.GetFlavorTagValueFromProtocolVersion(request.Version));
|
activity.AddTag(SemanticConventions.AttributeHTTPFlavor, HttpTagHelper.GetFlavorTagValueFromProtocolVersion(request.Version));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(this.httpClientSupportsW3C && this.options.TextFormat is TraceContextFormatActivity))
|
if (!(this.httpClientSupportsW3C && this.options.TextFormat is TraceContextFormatActivity))
|
||||||
{
|
{
|
||||||
this.options.TextFormat.Inject(activity.Context, request, HttpRequestMessageHeaderValueSetter);
|
this.options.TextFormat.Inject(activity.Context, request, HttpRequestMessageHeaderValueSetter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnStopActivity(Activity activity, object payload)
|
public override void OnStopActivity(Activity activity, object payload)
|
||||||
{
|
{
|
||||||
if (activity.IsAllDataRequested)
|
if (activity.IsAllDataRequested)
|
||||||
{
|
{
|
||||||
var requestTaskStatus = this.stopRequestStatusFetcher.Fetch(payload) as TaskStatus?;
|
var requestTaskStatus = this.stopRequestStatusFetcher.Fetch(payload) as TaskStatus?;
|
||||||
|
|
||||||
if (requestTaskStatus.HasValue)
|
if (requestTaskStatus.HasValue)
|
||||||
{
|
{
|
||||||
if (requestTaskStatus != TaskStatus.RanToCompletion)
|
if (requestTaskStatus != TaskStatus.RanToCompletion)
|
||||||
{
|
{
|
||||||
if (requestTaskStatus == TaskStatus.Canceled)
|
if (requestTaskStatus == TaskStatus.Canceled)
|
||||||
{
|
{
|
||||||
activity.SetStatus(Status.Cancelled);
|
activity.SetStatus(Status.Cancelled);
|
||||||
}
|
}
|
||||||
else if (requestTaskStatus != TaskStatus.Faulted)
|
else if (requestTaskStatus != TaskStatus.Faulted)
|
||||||
{
|
{
|
||||||
// Faults are handled in OnException and should already have a span.Status of Unknown w/ Description.
|
// Faults are handled in OnException and should already have a span.Status of Unknown w/ Description.
|
||||||
activity.SetStatus(Status.Unknown);
|
activity.SetStatus(Status.Unknown);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.stopResponseFetcher.Fetch(payload) is HttpResponseMessage response)
|
if (this.stopResponseFetcher.Fetch(payload) is HttpResponseMessage response)
|
||||||
{
|
{
|
||||||
// response could be null for DNS issues, timeouts, etc...
|
// response could be null for DNS issues, timeouts, etc...
|
||||||
activity.AddTag(SemanticConventions.AttributeHTTPStatusCode, response.StatusCode.ToString());
|
activity.AddTag(SemanticConventions.AttributeHTTPStatusCode, response.StatusCode.ToString());
|
||||||
|
|
||||||
activity.SetStatus(
|
activity.SetStatus(
|
||||||
SpanHelper
|
SpanHelper
|
||||||
.ResolveSpanStatusForHttpStatusCode((int)response.StatusCode)
|
.ResolveSpanStatusForHttpStatusCode((int)response.StatusCode)
|
||||||
.WithDescription(response.ReasonPhrase));
|
.WithDescription(response.ReasonPhrase));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.activitySource.Stop(activity);
|
this.activitySource.Stop(activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnException(Activity activity, object payload)
|
public override void OnException(Activity activity, object payload)
|
||||||
{
|
{
|
||||||
if (activity.IsAllDataRequested)
|
if (activity.IsAllDataRequested)
|
||||||
{
|
{
|
||||||
if (!(this.stopExceptionFetcher.Fetch(payload) is Exception exc))
|
if (!(this.stopExceptionFetcher.Fetch(payload) is Exception exc))
|
||||||
{
|
{
|
||||||
InstrumentationEventSource.Log.NullPayload(nameof(HttpHandlerDiagnosticListener), nameof(this.OnException));
|
DependenciesInstrumentationEventSource.Log.NullPayload(nameof(HttpHandlerDiagnosticListener), nameof(this.OnException));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exc is HttpRequestException)
|
if (exc is HttpRequestException)
|
||||||
{
|
{
|
||||||
if (exc.InnerException is SocketException exception)
|
if (exc.InnerException is SocketException exception)
|
||||||
{
|
{
|
||||||
switch (exception.SocketErrorCode)
|
switch (exception.SocketErrorCode)
|
||||||
{
|
{
|
||||||
case SocketError.HostNotFound:
|
case SocketError.HostNotFound:
|
||||||
activity.SetStatus(Status.InvalidArgument.WithDescription(exc.Message));
|
activity.SetStatus(Status.InvalidArgument.WithDescription(exc.Message));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exc.InnerException != null)
|
if (exc.InnerException != null)
|
||||||
{
|
{
|
||||||
activity.SetStatus(Status.Unknown.WithDescription(exc.Message));
|
activity.SetStatus(Status.Unknown.WithDescription(exc.Message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -76,7 +76,7 @@ namespace OpenTelemetry.Instrumentation.Dependencies.Implementation
|
||||||
var command = this.commandFetcher.Fetch(payload);
|
var command = this.commandFetcher.Fetch(payload);
|
||||||
if (command == null)
|
if (command == null)
|
||||||
{
|
{
|
||||||
InstrumentationEventSource.Log.NullPayload(nameof(SqlClientDiagnosticListener), name);
|
DependenciesInstrumentationEventSource.Log.NullPayload(nameof(SqlClientDiagnosticListener), name);
|
||||||
activity.Stop();
|
activity.Stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -132,7 +132,7 @@ namespace OpenTelemetry.Instrumentation.Dependencies.Implementation
|
||||||
{
|
{
|
||||||
if (activity == null)
|
if (activity == null)
|
||||||
{
|
{
|
||||||
InstrumentationEventSource.Log.NullActivity(name);
|
DependenciesInstrumentationEventSource.Log.NullActivity(name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,7 +160,7 @@ namespace OpenTelemetry.Instrumentation.Dependencies.Implementation
|
||||||
{
|
{
|
||||||
if (activity == null)
|
if (activity == null)
|
||||||
{
|
{
|
||||||
InstrumentationEventSource.Log.NullActivity(name);
|
DependenciesInstrumentationEventSource.Log.NullActivity(name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,7 +179,7 @@ namespace OpenTelemetry.Instrumentation.Dependencies.Implementation
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InstrumentationEventSource.Log.NullPayload(nameof(SqlClientDiagnosticListener), name);
|
DependenciesInstrumentationEventSource.Log.NullPayload(nameof(SqlClientDiagnosticListener), name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ namespace OpenTelemetry.Instrumentation.Dependencies.Implementation
|
||||||
}
|
}
|
||||||
catch (Exception exc)
|
catch (Exception exc)
|
||||||
{
|
{
|
||||||
InstrumentationEventSource.Log.UnknownErrorProcessingEvent(nameof(SqlEventSourceListener), nameof(this.OnEventWritten), exc);
|
DependenciesInstrumentationEventSource.Log.UnknownErrorProcessingEvent(nameof(SqlEventSourceListener), nameof(this.OnEventWritten), exc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,7 +93,7 @@ namespace OpenTelemetry.Instrumentation.Dependencies.Implementation
|
||||||
|
|
||||||
if ((eventData?.Payload?.Count ?? 0) < 4)
|
if ((eventData?.Payload?.Count ?? 0) < 4)
|
||||||
{
|
{
|
||||||
InstrumentationEventSource.Log.InvalidPayload(nameof(SqlEventSourceListener), nameof(this.OnBeginExecute));
|
DependenciesInstrumentationEventSource.Log.InvalidPayload(nameof(SqlEventSourceListener), nameof(this.OnBeginExecute));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -142,7 +142,7 @@ namespace OpenTelemetry.Instrumentation.Dependencies.Implementation
|
||||||
|
|
||||||
if ((eventData?.Payload?.Count ?? 0) < 3)
|
if ((eventData?.Payload?.Count ?? 0) < 3)
|
||||||
{
|
{
|
||||||
InstrumentationEventSource.Log.InvalidPayload(nameof(SqlEventSourceListener), nameof(this.OnEndExecute));
|
DependenciesInstrumentationEventSource.Log.InvalidPayload(nameof(SqlEventSourceListener), nameof(this.OnEndExecute));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,76 +25,29 @@ namespace OpenTelemetry.Instrumentation
|
||||||
/// EventSource events emitted from the project.
|
/// EventSource events emitted from the project.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EventSource(Name = "OpenTelemetry-Instrumentation")]
|
[EventSource(Name = "OpenTelemetry-Instrumentation")]
|
||||||
public class InstrumentationEventSource : EventSource
|
internal class InstrumentationEventSource : EventSource
|
||||||
{
|
{
|
||||||
public static InstrumentationEventSource Log = new InstrumentationEventSource();
|
public static InstrumentationEventSource Log = new InstrumentationEventSource();
|
||||||
|
|
||||||
[Event(1, Message = "Span is NULL or blank in the '{0}' callback. Span will not be recorded.", Level = EventLevel.Warning)]
|
[Event(1, Message = "Current Activity is NULL the '{0}' callback. Span will not be recorded.", Level = EventLevel.Warning)]
|
||||||
public void NullOrBlankSpan(string eventName)
|
|
||||||
{
|
|
||||||
this.WriteEvent(1, eventName);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Event(2, Message = "Error getting custom sampler, the default sampler will be used. Exception : {0}", Level = EventLevel.Warning)]
|
|
||||||
public void ExceptionInCustomSampler(string ex)
|
|
||||||
{
|
|
||||||
this.WriteEvent(2, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Event(3, Message = "Current Activity is NULL the '{0}' callback. Span will not be recorded.", Level = EventLevel.Warning)]
|
|
||||||
public void NullActivity(string eventName)
|
public void NullActivity(string eventName)
|
||||||
{
|
{
|
||||||
this.WriteEvent(3, eventName);
|
this.WriteEvent(1, eventName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NonEvent]
|
[NonEvent]
|
||||||
public void UnknownErrorProcessingEvent(string handlerName, string eventName, Exception ex)
|
public void UnknownErrorProcessingEvent(string handlerName, string eventName, Exception ex)
|
||||||
{
|
|
||||||
if (!this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.UnknownErrorProcessingEvent(handlerName, eventName, ToInvariantString(ex));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Event(4, Message = "Unknown error processing event '{1}' from handler '{0}', Exception: {2}", Level = EventLevel.Error)]
|
|
||||||
public void UnknownErrorProcessingEvent(string handlerName, string eventName, string ex)
|
|
||||||
{
|
|
||||||
this.WriteEvent(4, handlerName, eventName, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Event(5, Message = "Payload is NULL in event '{1}' from handler '{0}', span will not be recorded.", Level = EventLevel.Warning)]
|
|
||||||
public void NullPayload(string handlerName, string eventName)
|
|
||||||
{
|
|
||||||
this.WriteEvent(5, handlerName, eventName);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Event(6, Message = "Request is filtered out.", Level = EventLevel.Verbose)]
|
|
||||||
public void RequestIsFilteredOut(string eventName)
|
|
||||||
{
|
|
||||||
this.WriteEvent(6, eventName);
|
|
||||||
}
|
|
||||||
|
|
||||||
[NonEvent]
|
|
||||||
public void ExceptionInitializingInstrumentation(string instrumentationType, Exception ex)
|
|
||||||
{
|
{
|
||||||
if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
|
if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
|
||||||
{
|
{
|
||||||
this.ExceptionInitializingInstrumentation(instrumentationType, ToInvariantString(ex));
|
this.UnknownErrorProcessingEvent(handlerName, eventName, ToInvariantString(ex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Event(7, Message = "Error initializing instrumentation type {0}. Exception : {1}", Level = EventLevel.Error)]
|
[Event(2, Message = "Unknown error processing event '{1}' from handler '{0}', Exception: {2}", Level = EventLevel.Error)]
|
||||||
public void ExceptionInitializingInstrumentation(string instrumentationType, string ex)
|
public void UnknownErrorProcessingEvent(string handlerName, string eventName, string ex)
|
||||||
{
|
{
|
||||||
this.WriteEvent(7, instrumentationType, ex);
|
this.WriteEvent(2, handlerName, eventName, ex);
|
||||||
}
|
|
||||||
|
|
||||||
[Event(8, Message = "Payload is invalid in event '{1}' from handler '{0}', span will not be recorded.", Level = EventLevel.Warning)]
|
|
||||||
public void InvalidPayload(string handlerName, string eventName)
|
|
||||||
{
|
|
||||||
this.WriteEvent(8, handlerName, eventName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue