Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements in http in and out auto-collectors #162

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions OpenTelemetry.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28407.52
# Visual Studio 15
VisualStudioVersion = 15.0.28307.705
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry", "src\OpenTelemetry\OpenTelemetry.csproj", "{AE3E3DF5-4083-4C6E-A840-8271B0ACDE7E}"
EndProject
Expand Down Expand Up @@ -80,9 +80,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LoggingTracer.Demo.ConsoleA
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LoggingTracer.Demo.AspNetCore", "samples\LoggingTracer\LoggingTracer.Demo.AspNetCore\LoggingTracer.Demo.AspNetCore.csproj", "{1EB74FCE-55C5-476A-8BB0-C46B77FE1070}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTelemetry.Exporter.Jaeger", "src\OpenTelemetry.Exporter.Jaeger\OpenTelemetry.Exporter.Jaeger.csproj", "{8D47E3CF-9AE3-42FE-9084-FEB72D9AD769}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Jaeger", "src\OpenTelemetry.Exporter.Jaeger\OpenTelemetry.Exporter.Jaeger.csproj", "{8D47E3CF-9AE3-42FE-9084-FEB72D9AD769}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTelemetry.Exporter.Jaeger.Tests", "test\OpenTelemetry.Exporter.Jaeger.Tests\OpenTelemetry.Exporter.Jaeger.Tests.csproj", "{21E69213-72D5-453F-BD00-75EF36AC4965}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenTelemetry.Exporter.Jaeger.Tests", "test\OpenTelemetry.Exporter.Jaeger.Tests\OpenTelemetry.Exporter.Jaeger.Tests.csproj", "{21E69213-72D5-453F-BD00-75EF36AC4965}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thrift", "lib\Thrift\Thrift.csproj", "{ED179037-DDB3-4780-A24F-F56278623EBB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{9D2D6933-C28C-4541-9A25-FDAE0DA5A5D4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -182,6 +186,10 @@ Global
{21E69213-72D5-453F-BD00-75EF36AC4965}.Debug|Any CPU.Build.0 = Debug|Any CPU
{21E69213-72D5-453F-BD00-75EF36AC4965}.Release|Any CPU.ActiveCfg = Release|Any CPU
{21E69213-72D5-453F-BD00-75EF36AC4965}.Release|Any CPU.Build.0 = Release|Any CPU
{ED179037-DDB3-4780-A24F-F56278623EBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ED179037-DDB3-4780-A24F-F56278623EBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ED179037-DDB3-4780-A24F-F56278623EBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ED179037-DDB3-4780-A24F-F56278623EBB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -193,6 +201,7 @@ Global
{1EEF77DF-7552-4265-B64C-FA13BC40C256} = {D9C14CDA-5182-4DEA-8606-98FF1A388BD3}
{607B3861-4D69-43EF-84CE-19F18CD5339A} = {D9C14CDA-5182-4DEA-8606-98FF1A388BD3}
{1EB74FCE-55C5-476A-8BB0-C46B77FE1070} = {D9C14CDA-5182-4DEA-8606-98FF1A388BD3}
{ED179037-DDB3-4780-A24F-F56278623EBB} = {9D2D6933-C28C-4541-9A25-FDAE0DA5A5D4}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {55639B5C-0770-4A22-AB56-859604650521}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ public void ExceptionInCustomSampler(Exception ex)
}
}

[Event(1, Message = "Context is NULL in end callback. Span will not be recorded.", Level = EventLevel.Warning)]
public void NullContext()
[Event(1, Message = "Http Context is NULL in '{0}' callback. Span will not be recorded.", Level = EventLevel.Warning)]
public void NullHttpContext(string eventName)
{
this.WriteEvent(1);
this.WriteEvent(1, eventName);
}

[Event(2, Message = "Error getting custom sampler, the default sampler will be used. Exception : {0}", Level = EventLevel.Warning)]
Expand All @@ -50,6 +50,12 @@ public void ExceptionInCustomSampler(string ex)
this.WriteEvent(2, ex);
}

[Event(3, Message = "Current Span is null or blank in '{0}' callback. Span will not be recorded.", Level = EventLevel.Warning)]
public void NullOrBlankSpan(string callbackName)
{
this.WriteEvent(3, callbackName);
}

/// <summary>
/// Returns a culture-independent string representation of the given <paramref name="exception"/> object,
/// appropriate for diagnostics tracing.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@ internal class HttpInListener : ListenerHandler
private readonly PropertyFetcher beforeActionActionDescriptorFetcher = new PropertyFetcher("actionDescriptor");
private readonly PropertyFetcher beforeActionAttributeRouteInfoFetcher = new PropertyFetcher("AttributeRouteInfo");
private readonly PropertyFetcher beforeActionTemplateFetcher = new PropertyFetcher("Template");
private readonly bool hostingSupportsW3C = false;

public HttpInListener(ITracer tracer, Func<HttpRequest, ISampler> samplerFactory)
: base("Microsoft.AspNetCore", tracer, samplerFactory)
{
this.hostingSupportsW3C = typeof(HttpRequest).Assembly.GetName().Version.Major >= 3;
}

public override void OnStartActivity(Activity activity, object payload)
Expand All @@ -51,48 +53,65 @@ public override void OnStartActivity(Activity activity, object payload)

var request = context.Request;

var ctx = this.Tracer.TextFormat.Extract<HttpRequest>(
request,
(r, name) => r.Headers[name]);
SpanContext ctx = null;
if (!this.hostingSupportsW3C)
{
ctx = this.Tracer.TextFormat.Extract<HttpRequest>(
request,
(r, name) => r.Headers[name]);
}

// see the spec https://github.com/open-telemetry/OpenTelemetry-specs/blob/master/trace/HTTP.md

var path = (request.PathBase.HasValue || request.Path.HasValue) ? (request.PathBase + request.Path).ToString() : "/";

ISpan span = this.Tracer.SpanBuilder(path)
var spanBuilder = this.Tracer.SpanBuilder(path)
.SetSpanKind(SpanKind.Server)
.SetParent(ctx)
.SetSampler(this.SamplerFactory(request))
.StartSpan();
.SetSampler(this.SamplerFactory(request));

this.Tracer.WithSpan(span);

// Note, route is missing at this stage. It will be available later
if (this.hostingSupportsW3C)
{
spanBuilder.SetCreateChild(false);
}
else
{
spanBuilder.SetParent(ctx);
}

span.PutHttpHostAttribute(request.Host.Host, request.Host.Port ?? 80);
span.PutHttpMethodAttribute(request.Method);
span.PutHttpPathAttribute(path);
var span = spanBuilder.StartSpan();
this.Tracer.WithSpan(span);

var userAgent = request.Headers["User-Agent"].FirstOrDefault();
span.PutHttpUserAgentAttribute(userAgent);
span.PutHttpRawUrlAttribute(GetUri(request));
if (span.IsRecordingEvents)
{
// Note, route is missing at this stage. It will be available later
span.PutHttpHostAttribute(request.Host.Host, request.Host.Port ?? 80);
span.PutHttpMethodAttribute(request.Method);
span.PutHttpPathAttribute(path);

var userAgent = request.Headers["User-Agent"].FirstOrDefault();
span.PutHttpUserAgentAttribute(userAgent);
span.PutHttpRawUrlAttribute(GetUri(request));
}
}

public override void OnStopActivity(Activity activity, object payload)
{
var context = this.stopContextFetcher.Fetch(payload) as HttpContext;
var span = this.Tracer.CurrentSpan;

if (context == null)
if (span == null || span == BlankSpan.Instance)
{
AspNetCoreCollectorEventSource.Log.NullContext();
AspNetCoreCollectorEventSource.Log.NullOrBlankSpan("HttpInListener.OnStopActivity");
return;
}

var span = this.Tracer.CurrentSpan;
if (!span.IsRecordingEvents)
{
span.End();
return;
}

if (span == null)
if (!(this.stopContextFetcher.Fetch(payload) is HttpContext context))
{
// TODO: report lost span
AspNetCoreCollectorEventSource.Log.NullHttpContext("HttpInListener.OnStopActivity");
return;
}

Expand All @@ -110,30 +129,33 @@ public override void OnCustom(string name, Activity activity, object payload)

if (span == null)
{
// TODO: report lost span
AspNetCoreCollectorEventSource.Log.NullOrBlankSpan(name);
return;
}

// See https://github.com/aspnet/Mvc/blob/2414db256f32a047770326d14d8b0e2afd49ba49/src/Microsoft.AspNetCore.Mvc.Core/MvcCoreDiagnosticSourceExtensions.cs#L36-L44
// Reflection accessing: ActionDescriptor.AttributeRouteInfo.Template
// 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.
// Taking reference on MVC will increase size of deployment for non-MVC apps.
var actionDescriptor = this.beforeActionActionDescriptorFetcher.Fetch(payload);
var attributeRouteInfo = this.beforeActionAttributeRouteInfoFetcher.Fetch(actionDescriptor);
var template = this.beforeActionTemplateFetcher.Fetch(attributeRouteInfo) as string;

if (!string.IsNullOrEmpty(template))
if (span.IsRecordingEvents)
{
// override the span name that was previously set to the path part of URL.
span.UpdateName(template);

span.PutHttpRouteAttribute(template);
// See https://github.com/aspnet/Mvc/blob/2414db256f32a047770326d14d8b0e2afd49ba49/src/Microsoft.AspNetCore.Mvc.Core/MvcCoreDiagnosticSourceExtensions.cs#L36-L44
// Reflection accessing: ActionDescriptor.AttributeRouteInfo.Template
// 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.
// Taking reference on MVC will increase size of deployment for non-MVC apps.
var actionDescriptor = this.beforeActionActionDescriptorFetcher.Fetch(payload);
var attributeRouteInfo = this.beforeActionAttributeRouteInfoFetcher.Fetch(actionDescriptor);
var template = this.beforeActionTemplateFetcher.Fetch(attributeRouteInfo) as string;

if (!string.IsNullOrEmpty(template))
{
// override the span name that was previously set to the path part of URL.
span.UpdateName(template);

span.PutHttpRouteAttribute(template);
}

// TODO: Should we get values from RouteData?
// private readonly PropertyFetcher beforActionRouteDataFetcher = new PropertyFetcher("routeData");
// var routeData = this.beforActionRouteDataFetcher.Fetch(payload) as RouteData;
}

// TODO: Should we get values from RouteData?
// private readonly PropertyFetcher beforActionRouteDataFetcher = new PropertyFetcher("routeData");
// var routeData = this.beforActionRouteDataFetcher.Fetch(payload) as RouteData;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public RequestsCollector(RequestsCollectorOptions options, ITracer tracer, ISamp
AspNetCoreCollectorEventSource.Log.ExceptionInCustomSampler(e);
}

return s == null ? sampler : s;
return s ?? sampler;
});
this.diagnosticSourceSubscriber.Subscribe();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public DependenciesCollector(DependenciesCollectorOptions options, ITracer trace
DependenciesCollectorEventSource.Log.ExceptionInCustomSampler(e);
}

return s == null ? sampler : s;
return s ?? sampler;
});
this.diagnosticSourceSubscriber.Subscribe();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ public void ExceptionInCustomSampler(Exception ex)
}
}

[Event(1, Message = "Context is NULL in end callback. Span will not be recorded.", Level = EventLevel.Warning)]
public void NullContext()
[Event(1, Message = "Span is NULL or blank in the '{0}' callback. Span will not be recorded.", Level = EventLevel.Warning)]
public void NullOrBlankSpan(string eventName)
{
this.WriteEvent(1);
this.WriteEvent(1, eventName);
}

[Event(2, Message = "Error getting custom sampler, the default sampler will be used. Exception : {0}", Level = EventLevel.Warning)]
Expand All @@ -50,6 +50,18 @@ 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)
{
this.WriteEvent(3, eventName);
}

[Event(4, Message = "Unknown error processing event '{0}' from handler '{1}', Exception: {2}", Level = EventLevel.Error)]
public void UnknownErrorProcessingEvent(string handlerName, string eventName, Exception ex)
{
this.WriteEvent(4, handlerName, eventName, ToInvariantString(ex));
}

/// <summary>
/// Returns a culture-independent string representation of the given <paramref name="exception"/> object,
/// appropriate for diagnostics tracing.
Expand Down
Loading