Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ internal static class QylHttpActivityPolicy
public static Activity? StartClientActivity(
string instrumentationDomain,
string method,
string? methodOriginal,
Uri? requestUri,
string? rawRequestUri)
{
Expand All @@ -18,7 +19,7 @@ internal static class QylHttpActivityPolicy
if (activity is null)
return null;

SetRequestMethod(activity, method);
SetRequestMethod(activity, method, methodOriginal);
if (requestUri is not null)
SetClientUrl(activity, requestUri, rawRequestUri);

Expand All @@ -27,9 +28,11 @@ internal static class QylHttpActivityPolicy

public static Activity? StartServerActivity(
string method,
string? methodOriginal,
string? route,
string? path,
string? query)
string? query,
string? scheme)
{
var activity = QylActivityFactory.StartTraceActivity(
QylAutoInstrumentationIds.AspNetCore,
Expand All @@ -39,7 +42,9 @@ internal static class QylHttpActivityPolicy
if (activity is null)
return null;

SetRequestMethod(activity, method);
SetRequestMethod(activity, method, methodOriginal);
if (!string.IsNullOrEmpty(scheme))
activity.SetTag(QylSemanticAttributes.UrlScheme, scheme);
if (path is not null)
activity.SetTag(QylSemanticAttributes.UrlPath, path);
if (!string.IsNullOrEmpty(query))
Expand Down Expand Up @@ -73,8 +78,12 @@ public static void SetResponseStatus(Activity activity, int statusCode, int erro
public static void SetResponseStatus(Activity activity, int statusCode)
=> activity.SetTag(QylSemanticAttributes.HttpResponseStatusCode, statusCode);

private static void SetRequestMethod(Activity activity, string method)
=> activity.SetTag(QylSemanticAttributes.HttpRequestMethod, method);
private static void SetRequestMethod(Activity activity, string method, string? methodOriginal)
{
activity.SetTag(QylSemanticAttributes.HttpRequestMethod, method);
if (!string.IsNullOrEmpty(methodOriginal))
activity.SetTag(QylSemanticAttributes.HttpRequestMethodOriginal, methodOriginal);
}

private static void SetClientUrl(Activity activity, Uri requestUri, string? rawRequestUri)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#nullable enable
const Qyl.OpenTelemetry.AutoInstrumentation.QylSemanticAttributes.CodeFunctionName = "code.function.name" -> string!
const Qyl.OpenTelemetry.AutoInstrumentation.QylSemanticAttributes.UrlScheme = "url.scheme" -> string!
const Qyl.OpenTelemetry.AutoInstrumentation.QylMetricMeters.AspNetCoreAuthenticationMeterName = "Microsoft.AspNetCore.Authentication" -> string!
const Qyl.OpenTelemetry.AutoInstrumentation.QylMetricMeters.AspNetCoreAuthorizationMeterName = "Microsoft.AspNetCore.Authorization" -> string!
const Qyl.OpenTelemetry.AutoInstrumentation.QylMetricMeters.AspNetCoreDiagnosticsMeterName = "Microsoft.AspNetCore.Diagnostics" -> string!
Expand Down
15 changes: 15 additions & 0 deletions src/Qyl.OpenTelemetry.AutoInstrumentation/QylHttpMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,19 @@ public static string Normalize(string? method)

return QylSemanticAttributes.HttpRequestMethodOther;
}

/// <summary>
/// Normalizes <paramref name="method"/> and reports the raw value as <paramref name="original"/> when it
/// is non-standard. Per OTel, http.request.method_original MUST be set whenever http.request.method is
/// <c>_OTHER</c>; <paramref name="original"/> is null for the standard methods.
/// </summary>
Comment on lines +40 to +44
public static string Normalize(string? method, out string? original)
{
var normalized = Normalize(method);
original = !string.IsNullOrEmpty(method)
&& string.Equals(normalized, QylSemanticAttributes.HttpRequestMethodOther, StringComparison.Ordinal)
? method
: null;
return normalized;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,15 @@ public static Task InvokeAsync(RequestDelegate requestDelegate, HttpContext cont
if (!options.IsInstrumentationEnabled(QylAutoInstrumentationSignal.Traces, QylAutoInstrumentationIds.AspNetCore))
return null;

var method = QylHttpMethod.Normalize(context.Request.Method);
var method = QylHttpMethod.Normalize(context.Request.Method, out var methodOriginal);
var route = GetRoute(context);
var activity = QylHttpActivityPolicy.StartServerActivity(
method,
methodOriginal,
route,
context.Request.Path.Value,
context.Request.QueryString.HasValue ? context.Request.QueryString.Value![1..] : null);
context.Request.QueryString.HasValue ? context.Request.QueryString.Value![1..] : null,
context.Request.Scheme);
if (activity is null)
return null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ public static class QylInterceptedAzure
/// <summary>Runs the Start Activity runtime helper used by source-generated qyl interceptors.</summary>
public static Activity? StartActivity(string methodName)
{
return QylActivityFactory.StartTraceActivity(
var activity = QylActivityFactory.StartTraceActivity(
QylAutoInstrumentationIds.Azure,
QylActivityNames.AzureSdk,
ActivityKind.Client,
QylInstrumentationDomains.AzureSdk);
// Record the intercepted operation so Azure spans are distinguishable. The span name stays the
// stable low-cardinality "Azure SDK"; the specific method goes on code.function.name (CODE RED #9:
// the methodName parameter was previously received and dropped).
if (activity is not null && !string.IsNullOrEmpty(methodName))
activity.SetTag(QylSemanticAttributes.CodeFunctionName, methodName);
return activity;
}

/// <summary>Runs the Record Exception runtime helper used by source-generated qyl interceptors.</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ private static HttpClientObservation StartHttpClientObservation(
Uri? requestUri,
string? rawRequestUri)
{
method = QylHttpMethod.Normalize(method);
method = QylHttpMethod.Normalize(method, out var methodOriginal);
var startTimeUtc = QylDurationMetrics.GetHttpClientStartTimeUtc(metricsEnabled);
Activity? activity = null;

Expand All @@ -594,6 +594,7 @@ private static HttpClientObservation StartHttpClientObservation(
activity = QylHttpActivityPolicy.StartClientActivity(
QylInstrumentationDomains.HttpClient,
method,
methodOriginal,
requestUri,
rawRequestUri);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@ public static DateTime GetStartTimeUtc()
if (!options.IsInstrumentationEnabled(QylAutoInstrumentationSignal.Traces, QylAutoInstrumentationIds.HttpClient))
return null;

var method = QylHttpMethod.Normalize(request.Method);
var method = QylHttpMethod.Normalize(request.Method, out var methodOriginal);
var activity = QylHttpActivityPolicy.StartClientActivity(
QylInstrumentationDomains.HttpWebRequest,
method,
methodOriginal,
request.RequestUri,
request.RequestUri?.ToString());
if (activity is null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ public static class QylSemanticAttributes
public const string UrlQuery = UrlAttributes.Query;
/// <summary>Well-known Url Full value used by qyl auto-instrumentation.</summary>
public const string UrlFull = UrlAttributes.Full;
/// <summary>Well-known Url Scheme value used by qyl auto-instrumentation.</summary>
public const string UrlScheme = "url.scheme";
/// <summary>Well-known Code Function Name value used by qyl auto-instrumentation.</summary>
public const string CodeFunctionName = "code.function.name";

/// <summary>Well-known Dotnet Gc Heap Generation value used by qyl auto-instrumentation.</summary>
public const string DotnetGcHeapGeneration = DotnetAttributes.GcHeapGeneration;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ private static IReadOnlyDictionary<string, string> Canonicalize(IReadOnlyDiction
"qyl.instrumentation.domain",
"http.request.method",
"http.route",
"url.scheme",
"http.response.status_code",
"server.address",
"server.port",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@
"http.request.method": "GET",
"http.response.status_code": "204",
"http.route": "/probe/{id:int}",
"qyl.instrumentation.domain": "aspnetcore.server"
"qyl.instrumentation.domain": "aspnetcore.server",
"url.scheme": "http"
}
},
{
Expand Down Expand Up @@ -101,7 +102,8 @@
"http.request.method": "GET",
"http.response.status_code": "204",
"http.route": "/probe/{id:int}",
"qyl.instrumentation.domain": "aspnetcore.server"
"qyl.instrumentation.domain": "aspnetcore.server",
"url.scheme": "http"
}
},
{
Expand Down
Loading