Skip to content
This repository was archived by the owner on Dec 18, 2023. It is now read-only.

Commit 81e1cc1

Browse files
Make span.Name settable, update it with the route info for ASP.NET Core (#80)
* better name * make it work * revert wrong addition * addressed code review * fix build failure and added comment for the sampler * added changelog entry * added route into the attributs as well
1 parent 4a8ddf6 commit 81e1cc1

File tree

14 files changed

+106
-27
lines changed

14 files changed

+106
-27
lines changed

CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,18 @@ the release.
77

88
## Unreleased
99

10+
- ASP.NET Core collector now uses `http.route` for the span name.
11+
1012
## 0.1.0-alpha-33381
1113

12-
Released [12/18/2018](https://github.com/census-instrumentation/opencensus-csharp/releases/tag/0.1.0-alpha-33381).
14+
Released
15+
[12/18/2018](https://github.com/census-instrumentation/opencensus-csharp/releases/tag/0.1.0-alpha-33381).
1316

1417
- Collectors for ASP.NET Core and .NET Core HttpClient.
1518
- Initial version of Ocagent exporter implemented.
1619
- Initial version of StackDriver exporter implemented.
17-
- Support double attributes according to the [spec change](https://github.com/census-instrumentation/opencensus-specs/issues/172).
20+
- Support double attributes according to the [spec
21+
change](https://github.com/census-instrumentation/opencensus-specs/issues/172).
1822
- Initial implementation of Prometheus exporter.
1923
- Initial version of Application Insights exporter implemented.
2024
- Zipkin exporter implemented.

src/OpenCensus.Abstractions/Trace/ISampler.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ public interface ISampler
3535
/// <param name="hasRemoteParent">Indicates whether it was a remote parent.</param>
3636
/// <param name="traceId">Trace ID of a span to be created.</param>
3737
/// <param name="spanId">Span ID of a span to be created.</param>
38-
/// <param name="name">Name of a span to be created.</param>
38+
/// <param name="name"> Name of a span to be created. Note, that the name of the span is settable.
39+
/// So this name can be changed later and <see cref="ISampler"/> implementation should assume that.
40+
/// Typical example of a name change is when <see cref="ISpan"/> representing incoming http request
41+
/// has a name of url path and then being updated with route name when rouing complete.
42+
/// </param>
3943
/// <param name="parentLinks">Links associated with the parent span.</param>
4044
/// <returns>True of span needs to be created. False otherwise.</returns>
4145
bool ShouldSample(ISpanContext parentContext, bool hasRemoteParent, ITraceId traceId, ISpanId spanId, string name, IList<ISpan> parentLinks);

src/OpenCensus.Abstractions/Trace/ISpan.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ namespace OpenCensus.Trace
2727
/// </summary>
2828
public interface ISpan
2929
{
30+
/// <summary>
31+
/// Gets or sets the span name.
32+
/// </summary>
33+
string Name { get; set; }
34+
3035
/// <summary>
3136
/// Gets the span context.
3237
/// </summary>

src/OpenCensus.Abstractions/Trace/SpanBase.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ protected SpanBase(ISpanContext context, SpanOptions options = SpanOptions.None)
5353
this.Options = options;
5454
}
5555

56+
public abstract string Name { get; set; }
57+
5658
/// <inheritdoc/>
5759
public virtual ISpanContext Context { get; }
5860

@@ -65,11 +67,6 @@ protected SpanBase(ISpanContext context, SpanOptions options = SpanOptions.None)
6567
/// <inheritdoc/>
6668
public abstract SpanKind? Kind { get; set; }
6769

68-
/// <summary>
69-
/// Gets the name of the span.
70-
/// </summary>
71-
public abstract string Name { get; }
72-
7370
/// <inheritdoc/>
7471
public SpanBase Next { get; set; }
7572

src/OpenCensus.Abstractions/Trace/SpanExtensions.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,23 @@ public static ISpan PutHttpHostAttribute(this ISpan span, string hostName, int p
108108
return span;
109109
}
110110

111+
/// <summary>
112+
/// Helper method that populates span properties from route
113+
/// to https://github.com/census-instrumentation/opencensus-specs/blob/4954074adf815f437534457331178194f6847ff9/trace/HTTP.md.
114+
/// </summary>
115+
/// <param name="span">Span to fill out.</param>
116+
/// <param name="route">Route used to resolve url to controller.</param>
117+
/// <returns>Span with populated route properties.</returns>
118+
public static ISpan PutHttpRouteAttribute(this ISpan span, string route)
119+
{
120+
if (!string.IsNullOrEmpty(route))
121+
{
122+
span.PutAttribute(SpanAttributeConstants.HttpRouteKey, AttributeValue.StringAttributeValue(route));
123+
}
124+
125+
return span;
126+
}
127+
111128
/// <summary>
112129
/// Helper method that populates span properties from host and port
113130
/// to https://github.com/census-instrumentation/opencensus-specs/blob/4954074adf815f437534457331178194f6847ff9/trace/HTTP.md.

src/OpenCensus.Collector.AspNetCore/Implementation/HttpInListener.cs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
namespace OpenCensus.Collector.AspNetCore.Implementation
1818
{
19-
using System;
2019
using System.Diagnostics;
2120
using System.Linq;
2221
using System.Text;
@@ -31,6 +30,9 @@ internal class HttpInListener : ListenerHandler
3130
private const string UnknownHostName = "UNKNOWN-HOST";
3231
private readonly PropertyFetcher startContextFetcher = new PropertyFetcher("HttpContext");
3332
private readonly PropertyFetcher stopContextFetcher = new PropertyFetcher("HttpContext");
33+
private readonly PropertyFetcher beforeActionActionDescriptorFetcher = new PropertyFetcher("actionDescriptor");
34+
private readonly PropertyFetcher beforeActionAttributeRouteInfoFetcher = new PropertyFetcher("AttributeRouteInfo");
35+
private readonly PropertyFetcher beforeActionTemplateFetcher = new PropertyFetcher("Template");
3436
private readonly IPropagationComponent propagationComponent;
3537

3638
public HttpInListener(ITracer tracer, ISampler sampler, IPropagationComponent propagationComponent)
@@ -84,15 +86,16 @@ public override void OnStopActivity(Activity activity, object payload)
8486

8587
if (context == null)
8688
{
87-
// Debug.WriteLine("context is null");
89+
// TODO: Debug.WriteLine("context is null");
8890
return;
8991
}
9092

9193
var span = this.Tracer.CurrentSpan;
9294

9395
if (span == null)
9496
{
95-
// report lost span
97+
// TODO: report lost span
98+
return;
9699
}
97100

98101
var response = context.Response;
@@ -101,6 +104,41 @@ public override void OnStopActivity(Activity activity, object payload)
101104
span.End();
102105
}
103106

107+
public override void OnCustom(string name, Activity activity, object payload)
108+
{
109+
if (name == "Microsoft.AspNetCore.Mvc.BeforeAction")
110+
{
111+
var span = this.Tracer.CurrentSpan;
112+
113+
if (span == null)
114+
{
115+
// TODO: report lost span
116+
return;
117+
}
118+
119+
// See https://github.com/aspnet/Mvc/blob/2414db256f32a047770326d14d8b0e2afd49ba49/src/Microsoft.AspNetCore.Mvc.Core/MvcCoreDiagnosticSourceExtensions.cs#L36-L44
120+
// Reflection accessing: ActionDescriptor.AttributeRouteInfo.Template
121+
// The reason to use reflection is to avoid a reference on MVC package.
122+
// This package can be used with non-MVC apps and this logic simply wouldn't run.
123+
// Taking reference on MVC will increase size of deployment for non-MVC apps.
124+
var actionDescriptor = this.beforeActionActionDescriptorFetcher.Fetch(payload);
125+
var attributeRouteInfo = this.beforeActionAttributeRouteInfoFetcher.Fetch(actionDescriptor);
126+
var template = this.beforeActionTemplateFetcher.Fetch(attributeRouteInfo) as string;
127+
128+
if (!string.IsNullOrEmpty(template))
129+
{
130+
// override the span name that was previously set to the path part of URL.
131+
span.Name = template;
132+
133+
span.PutHttpRouteAttribute(template);
134+
}
135+
136+
// TODO: Should we get values from RouteData?
137+
// private readonly PropertyFetcher beforActionRouteDataFetcher = new PropertyFetcher("routeData");
138+
// var routeData = this.beforActionRouteDataFetcher.Fetch(payload) as RouteData;
139+
}
140+
}
141+
104142
private static string GetUri(HttpRequest request)
105143
{
106144
var builder = new StringBuilder();

src/OpenCensus.Collector.AspNetCore/RequestsCollector.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ public RequestsCollector(RequestsCollectorOptions options, ITracer tracer, ISamp
4141
{
4242
this.diagnosticSourceSubscriber = new DiagnosticSourceSubscriber(
4343
new Dictionary<string, Func<ITracer, ISampler, ListenerHandler>>()
44-
{ { "Microsoft.AspNetCore", (t, s) => new HttpInListener(t, s, propagationComponent) } },
44+
{
45+
{ "Microsoft.AspNetCore", (t, s) => new HttpInListener(t, s, propagationComponent) },
46+
},
4547
tracer,
4648
sampler);
4749
this.diagnosticSourceSubscriber.Subscribe();

src/OpenCensus.Collector.Implementation.Common/DiagnosticSourceListener.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ public void OnNext(KeyValuePair<string, object> value)
6363
{
6464
this.handler.OnException(Activity.Current, value.Value);
6565
}
66+
else
67+
{
68+
this.handler.OnCustom(value.Key, Activity.Current, value.Value);
69+
}
6670
}
6771
catch (Exception e)
6872
{

src/OpenCensus.Collector.Implementation.Common/ListenerHandler.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,10 @@ public virtual void OnException(Activity activity, object payload)
6161

6262
// TODO: gather exception information
6363
}
64+
65+
public virtual void OnCustom(string name, Activity activity, object payload)
66+
{
67+
// if custom handler needs to react on other events - this method should be overridden
68+
}
6469
}
6570
}

src/OpenCensus.Collector.Implementation.Common/PropertyFetcher.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,14 @@ public object Fetch(object obj)
3333
{
3434
if (this.innerFetcher == null)
3535
{
36-
this.innerFetcher = PropertyFetch.FetcherForProperty(obj.GetType().GetTypeInfo().GetDeclaredProperty(this.propertyName));
36+
var type = obj.GetType().GetTypeInfo();
37+
var property = type.GetDeclaredProperty(this.propertyName);
38+
if (property == null)
39+
{
40+
property = type.GetProperty(this.propertyName);
41+
}
42+
43+
this.innerFetcher = PropertyFetch.FetcherForProperty(property);
3744
}
3845

3946
return this.innerFetcher?.Fetch(obj);

0 commit comments

Comments
 (0)