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
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
Improvements in http in and out auto-collectors
Liudmila Molkova committed Jul 25, 2019
commit 08599b639300ae7428159a7a6ff61dc5b6208378
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
@@ -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
@@ -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
@@ -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}
Original file line number Diff line number Diff line change
@@ -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)]
@@ -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.
Original file line number Diff line number Diff line change
@@ -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)
@@ -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;
}

@@ -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;
}
}

Original file line number Diff line number Diff line change
@@ -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();
}
Original file line number Diff line number Diff line change
@@ -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();
}
Original file line number Diff line number Diff line change
@@ -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)]
@@ -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.
Loading