-
Notifications
You must be signed in to change notification settings - Fork 273
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implementation for private preview release of the Distributed Tracing feature.
- Loading branch information
1 parent
cf9f4c2
commit 49aac11
Showing
26 changed files
with
9,039 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 16 | ||
VisualStudioVersion = 16.0.29509.3 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunctionAppCorrelation", "FunctionAppCorrelation\FunctionAppCorrelation.csproj", "{F9428663-9742-4746-A434-D073CCD5395C}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{F9428663-9742-4746-A434-D073CCD5395C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{F9428663-9742-4746-A434-D073CCD5395C}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{F9428663-9742-4746-A434-D073CCD5395C}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{F9428663-9742-4746-A434-D073CCD5395C}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {6D2AE1B1-FA1A-4E46-B75D-B9B01E570B50} | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
local.settings.json |
8 changes: 8 additions & 0 deletions
8
samples/correlation-csharp/FunctionAppCorrelation/local.settings.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"IsEncrypted": false, | ||
"Values": { | ||
"AzureWebJobsStorage": "UseDevelopmentStorage=true", | ||
"FUNCTIONS_WORKER_RUNTIME": "dotnet", | ||
"APPINSIGHTS_INSTRUMENTATIONKEY": "<YOUR_APPLICATION_INSIGHTS_INSTRUMENTATION_KEY_HERE" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
319 changes: 319 additions & 0 deletions
319
src/WebJobs.Extensions.DurableTask/Correlation/DurableTaskCorrelationTelemetryInitializer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,319 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the MIT License. See LICENSE in the project root for license information. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.ComponentModel; | ||
using System.Diagnostics; | ||
using System.Diagnostics.CodeAnalysis; | ||
using DurableTask.Core; | ||
using DurableTask.Core.Settings; | ||
using Microsoft.ApplicationInsights.Channel; | ||
using Microsoft.ApplicationInsights.DataContracts; | ||
using Microsoft.ApplicationInsights.Extensibility; | ||
using Microsoft.ApplicationInsights.Extensibility.Implementation; | ||
|
||
namespace Microsoft.Azure.WebJobs.Extensions.DurableTask.Correlation | ||
{ | ||
/// <summary> | ||
/// Telemetry Initializer that sets correlation ids for W3C. | ||
/// This source is based on W3COperationCorrelationTelemetryInitializer.cs | ||
/// 1. Modified with CorrelationTraceContext.Current | ||
/// 2. Avoid to be overriden when it is RequestTelemetry | ||
/// Original Source is here https://github.com/microsoft/ApplicationInsights-dotnet-server/blob/2.8.0/Src/Common/W3C/W3COperationCorrelationTelemetryInitializer.cs. | ||
/// </summary> | ||
internal | ||
class DurableTaskCorrelationTelemetryInitializer : ITelemetryInitializer | ||
{ | ||
private const string RddDiagnosticSourcePrefix = "rdddsc"; | ||
private const string SqlRemoteDependencyType = "SQL"; | ||
|
||
/// These internal property is copied from W3CConstants | ||
/// <summary>Trace-Id tag name.</summary> | ||
internal const string TraceIdTag = "w3c_traceId"; | ||
|
||
/// <summary>Span-Id tag name.</summary> | ||
internal const string SpanIdTag = "w3c_spanId"; | ||
|
||
/// <summary>Parent span-Id tag name.</summary> | ||
internal const string ParentSpanIdTag = "w3c_parentSpanId"; | ||
|
||
/// <summary>Version tag name.</summary> | ||
internal const string VersionTag = "w3c_version"; | ||
|
||
/// <summary>Sampled tag name.</summary> | ||
internal const string SampledTag = "w3c_sampled"; | ||
|
||
/// <summary>Tracestate tag name.</summary> | ||
internal const string TracestateTag = "w3c_tracestate"; | ||
|
||
/// <summary>Default version value.</summary> | ||
internal const string DefaultVersion = "00"; | ||
|
||
/// <summary> | ||
/// Default sampled flag value: may be recorded, not requested. | ||
/// </summary> | ||
internal const string TraceFlagRecordedAndNotRequested = "02"; | ||
|
||
/// <summary>Recorded and requested sampled flag value.</summary> | ||
internal const string TraceFlagRecordedAndRequested = "03"; | ||
|
||
/// <summary>Requested trace flag.</summary> | ||
internal const byte RequestedTraceFlag = 1; | ||
|
||
/// <summary>Legacy root Id tag name.</summary> | ||
internal const string LegacyRootIdProperty = "ai_legacyRootId"; | ||
|
||
/// <summary>Legacy root Id tag name.</summary> | ||
internal const string LegacyRequestIdProperty = "ai_legacyRequestId"; | ||
|
||
/// <summary> | ||
/// Constructor. | ||
/// </summary> | ||
public DurableTaskCorrelationTelemetryInitializer() | ||
{ | ||
this.ExcludeComponentCorrelationHttpHeadersOnDomains = new HashSet<string>(); | ||
} | ||
|
||
/// <summary> | ||
/// Set of suppress telemetry tracking if you add Host name on this. | ||
/// </summary> | ||
public HashSet<string> ExcludeComponentCorrelationHttpHeadersOnDomains { get; set; } | ||
|
||
/// <summary> | ||
/// Initializes telemetry item. | ||
/// </summary> | ||
/// <param name="telemetry">Telemetry item.</param> | ||
public void Initialize(ITelemetry telemetry) | ||
{ | ||
if (this.IsSuppressedTelemetry(telemetry)) | ||
{ | ||
this.SuppressTelemetry(telemetry); | ||
return; | ||
} | ||
|
||
if (!(telemetry is RequestTelemetry)) | ||
{ | ||
Activity currentActivity = Activity.Current; | ||
if (telemetry is ExceptionTelemetry) | ||
{ | ||
Console.WriteLine("exception!"); | ||
} | ||
|
||
if (currentActivity == null) | ||
{ | ||
if (CorrelationTraceContext.Current != null) | ||
{ | ||
UpdateTelemetry(telemetry, CorrelationTraceContext.Current); | ||
} | ||
} | ||
else | ||
{ | ||
if (CorrelationTraceContext.Current != null) | ||
{ | ||
UpdateTelemetry(telemetry, CorrelationTraceContext.Current); | ||
} | ||
else if (CorrelationSettings.Current.Protocol == Protocol.W3CTraceContext) | ||
{ | ||
UpdateTelemetry(telemetry, currentActivity, false); | ||
} | ||
else if (CorrelationSettings.Current.Protocol == Protocol.HttpCorrelationProtocol | ||
&& telemetry is ExceptionTelemetry) | ||
{ | ||
UpdateTelemetryExceptionForHTTPCorrelationProtocol((ExceptionTelemetry)telemetry, currentActivity); | ||
} | ||
} | ||
} | ||
} | ||
|
||
internal static void UpdateTelemetry(ITelemetry telemetry, TraceContextBase contextBase) | ||
{ | ||
switch (contextBase) | ||
{ | ||
case NullObjectTraceContext nullObjectContext: | ||
return; | ||
case W3CTraceContext w3cContext: | ||
UpdateTelemetryW3C(telemetry, w3cContext); | ||
break; | ||
case HttpCorrelationProtocolTraceContext httpCorrelationProtocolTraceContext: | ||
UpdateTelemetryHttpCorrelationProtocol(telemetry, httpCorrelationProtocolTraceContext); | ||
break; | ||
default: | ||
return; | ||
} | ||
} | ||
|
||
internal static void UpdateTelemetryHttpCorrelationProtocol(ITelemetry telemetry, HttpCorrelationProtocolTraceContext context) | ||
{ | ||
OperationTelemetry opTelemetry = telemetry as OperationTelemetry; | ||
|
||
bool initializeFromCurrent = opTelemetry != null; | ||
|
||
if (initializeFromCurrent) | ||
{ | ||
initializeFromCurrent &= !(opTelemetry is DependencyTelemetry dependency && | ||
dependency.Type == SqlRemoteDependencyType && | ||
dependency.Context.GetInternalContext().SdkVersion | ||
.StartsWith(RddDiagnosticSourcePrefix, StringComparison.Ordinal)); | ||
} | ||
|
||
if (initializeFromCurrent) | ||
{ | ||
opTelemetry.Id = !string.IsNullOrEmpty(opTelemetry.Id) ? opTelemetry.Id : context.TelemetryId; | ||
telemetry.Context.Operation.ParentId = !string.IsNullOrEmpty(telemetry.Context.Operation.ParentId) ? telemetry.Context.Operation.ParentId : context.TelemetryContextOperationParentId; | ||
} | ||
else | ||
{ | ||
telemetry.Context.Operation.Id = !string.IsNullOrEmpty(telemetry.Context.Operation.Id) ? telemetry.Context.Operation.Id : context.TelemetryContextOperationId; | ||
if (telemetry is ExceptionTelemetry) | ||
{ | ||
telemetry.Context.Operation.ParentId = context.TelemetryId; | ||
} | ||
else | ||
{ | ||
telemetry.Context.Operation.ParentId = !string.IsNullOrEmpty(telemetry.Context.Operation.ParentId) ? telemetry.Context.Operation.ParentId : context.TelemetryContextOperationParentId; | ||
} | ||
} | ||
} | ||
|
||
internal static void UpdateTelemetryW3C(ITelemetry telemetry, W3CTraceContext context) | ||
{ | ||
OperationTelemetry opTelemetry = telemetry as OperationTelemetry; | ||
|
||
bool initializeFromCurrent = opTelemetry != null; | ||
|
||
if (initializeFromCurrent) | ||
{ | ||
initializeFromCurrent &= !(opTelemetry is DependencyTelemetry dependency && | ||
dependency.Type == SqlRemoteDependencyType && | ||
dependency.Context.GetInternalContext().SdkVersion | ||
.StartsWith(RddDiagnosticSourcePrefix, StringComparison.Ordinal)); | ||
} | ||
|
||
if (!string.IsNullOrEmpty(context.TraceState)) | ||
{ | ||
opTelemetry.Properties["w3c_tracestate"] = context.TraceState; | ||
} | ||
|
||
TraceParent traceParent = TraceParent.FromString(context.TraceParent); | ||
|
||
if (initializeFromCurrent) | ||
{ | ||
if (string.IsNullOrEmpty(opTelemetry.Id)) | ||
{ | ||
opTelemetry.Id = traceParent.SpanId; | ||
} | ||
|
||
if (string.IsNullOrEmpty(context.ParentSpanId)) | ||
{ | ||
telemetry.Context.Operation.ParentId = telemetry.Context.Operation.Id; | ||
} | ||
} | ||
else | ||
{ | ||
if (telemetry.Context.Operation.Id == null) | ||
{ | ||
telemetry.Context.Operation.Id = traceParent.TraceId; | ||
} | ||
|
||
if (telemetry.Context.Operation.ParentId == null) | ||
{ | ||
telemetry.Context.Operation.ParentId = traceParent.SpanId; | ||
} | ||
} | ||
} | ||
|
||
internal void SuppressTelemetry(ITelemetry telemetry) | ||
{ | ||
// TODO For suppressing Dependency, I make the Id as suppressed. This stragey increase the number of telemetery. | ||
// However, new implementation already supressed. Once it fully tested the logic, remove the suppression logic on this class. | ||
telemetry.Context.Operation.Id = "suppressed"; | ||
telemetry.Context.Operation.ParentId = "suppressed"; | ||
#pragma warning disable 618 | ||
|
||
// Context. Properties. ai_legacyRequestId , ai_legacyRequestId | ||
foreach (var key in telemetry.Context.Properties.Keys) | ||
{ | ||
if (key == "ai_legacyRootId" || | ||
key == "ai_legacyRequestId") | ||
{ | ||
telemetry.Context.Properties[key] = "suppressed"; | ||
} | ||
} | ||
#pragma warning restore 618 | ||
|
||
((OperationTelemetry)telemetry).Id = "suppressed"; | ||
} | ||
|
||
internal bool IsSuppressedTelemetry(ITelemetry telemetry) | ||
{ | ||
OperationTelemetry opTelemetry = telemetry as OperationTelemetry; | ||
if (telemetry is DependencyTelemetry) | ||
{ | ||
DependencyTelemetry dTelemetry = telemetry as DependencyTelemetry; | ||
#pragma warning disable 618 | ||
if (!string.IsNullOrEmpty(dTelemetry.CommandName)) | ||
{ | ||
var host = new Uri(dTelemetry.CommandName).Host; | ||
#pragma warning restore 618 | ||
if (this.ExcludeComponentCorrelationHttpHeadersOnDomains.Contains(host)) | ||
{ | ||
return true; | ||
} | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
internal static void UpdateTelemetryExceptionForHTTPCorrelationProtocol(ExceptionTelemetry telemetry, Activity activity) | ||
{ | ||
telemetry.Context.Operation.ParentId = activity.Id; | ||
telemetry.Context.Operation.Id = activity.RootId; | ||
} | ||
|
||
[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "This method has different code for Net45/NetCore")] | ||
internal static void UpdateTelemetry(ITelemetry telemetry, Activity activity, bool forceUpdate) | ||
{ | ||
if (activity == null) | ||
{ | ||
return; | ||
} | ||
|
||
// Requests and dependencies are initialized from the Activity.Current. | ||
// (i.e. telemetry.Id = current.Id). Activity is created for such requests specifically | ||
// Traces, exceptions, events on the other side are children of current activity | ||
// There is one exception - SQL DiagnosticSource where current Activity is a parent | ||
// for dependency calls. | ||
|
||
OperationTelemetry opTelemetry = telemetry as OperationTelemetry; | ||
bool initializeFromCurrent = opTelemetry != null; | ||
|
||
if (initializeFromCurrent) | ||
{ | ||
initializeFromCurrent &= !(opTelemetry is DependencyTelemetry dependency && | ||
dependency.Type == SqlRemoteDependencyType && | ||
dependency.Context.GetInternalContext().SdkVersion | ||
.StartsWith(RddDiagnosticSourcePrefix, StringComparison.Ordinal)); | ||
} | ||
|
||
if (telemetry is OperationTelemetry operation) | ||
{ | ||
operation.Properties[TracestateTag] = activity.TraceStateString; | ||
} | ||
|
||
if (initializeFromCurrent) | ||
{ | ||
opTelemetry.Id = activity.SpanId.ToHexString(); | ||
if (activity.ParentSpanId != null) | ||
{ | ||
opTelemetry.Context.Operation.ParentId = activity.ParentSpanId.ToHexString(); | ||
} | ||
} | ||
else | ||
{ | ||
telemetry.Context.Operation.ParentId = activity.SpanId.ToHexString(); | ||
} | ||
} | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/WebJobs.Extensions.DurableTask/Correlation/ITelemetryActivator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the MIT License. See LICENSE in the project root for license information. | ||
|
||
namespace Microsoft.Azure.WebJobs.Extensions.DurableTask.Correlation | ||
{ | ||
/// <summary> | ||
/// ITelemetryActivator is an interface. | ||
/// </summary> | ||
public interface ITelemetryActivator | ||
{ | ||
/// <summary> | ||
/// Initialize is initialize the telemetry client. | ||
/// </summary> | ||
void Initialize(); | ||
} | ||
} |
Oops, something went wrong.