in BASE/src/Microsoft.ApplicationInsights/TelemetryClientExtensions.cs [101:231]
public static IOperationHolder<T> StartOperation<T>(this TelemetryClient telemetryClient, T operationTelemetry) where T : OperationTelemetry
{
if (telemetryClient == null)
{
throw new ArgumentNullException(nameof(telemetryClient));
}
if (operationTelemetry == null)
{
throw new ArgumentNullException(nameof(operationTelemetry));
}
var telemetryContext = operationTelemetry.Context.Operation;
bool idsAssignedByUser = !string.IsNullOrEmpty(telemetryContext.Id);
// We initialize telemetry here AND in Track method because of RichPayloadEventSource.
// It sends Start and Stop events for OperationTelemetry. During Start event telemetry
// has to contain essential telemetry properties such as correlations ids and ikey.
// Also, examples in our documentation rely on the fact that correlation Ids are set
// after StartOperation call and before operation is stopped.
// Before removing this call (for optimization), make sure:
// 1) correlation ids are set before method leaves
// 2) RichPayloadEventSource is re-factored to work without ikey in Start event (or ikey is set)
// and does not require other properties in telemetry
telemetryClient.Initialize(operationTelemetry);
// Initialize operation id if it wasn't initialized by telemetry initializers
if (string.IsNullOrEmpty(operationTelemetry.Id))
{
operationTelemetry.GenerateOperationId();
}
// If the operation is not executing in the context of any other operation
// set its name as a context (root) operation name.
if (string.IsNullOrEmpty(telemetryContext.Name))
{
telemetryContext.Name = operationTelemetry.Name;
}
OperationHolder<T> operationHolder = null;
var isActivityAvailable = ActivityExtensions.TryRun(() =>
{
var parentActivity = Activity.Current;
var operationActivity = new Activity(ChildActivityName);
string operationName = telemetryContext.Name;
if (string.IsNullOrEmpty(operationName))
{
operationName = parentActivity?.GetOperationName();
}
if (!string.IsNullOrEmpty(operationName))
{
operationActivity.SetOperationName(operationName);
}
if (idsAssignedByUser)
{
if (Activity.DefaultIdFormat == ActivityIdFormat.W3C)
{
if (W3CUtilities.IsCompatibleW3CTraceId(telemetryContext.Id))
{
// If the user provided operationId is W3C Compatible, use it.
operationActivity.SetParentId(ActivityTraceId.CreateFromString(telemetryContext.Id.AsSpan()),
default(ActivitySpanId), ActivityTraceFlags.None);
}
else
{
// If user provided operationId is not W3C compatible, generate a new one instead.
// and store supplied value inside custom property.
operationTelemetry.Properties.Add(W3CConstants.LegacyRootIdProperty, telemetryContext.Id);
telemetryContext.Id = null;
}
}
else
{
operationActivity.SetParentId(telemetryContext.Id);
}
}
operationActivity.Start();
if (operationActivity.IdFormat == ActivityIdFormat.W3C)
{
if (string.IsNullOrEmpty(telemetryContext.Id))
{
telemetryContext.Id = operationActivity.TraceId.ToHexString();
}
operationTelemetry.Id = operationActivity.SpanId.ToHexString();
}
else
{
if (string.IsNullOrEmpty(telemetryContext.Id))
{
telemetryContext.Id = operationActivity.RootId;
}
operationTelemetry.Id = operationActivity.Id;
}
operationHolder = new OperationHolder<T>(telemetryClient, operationTelemetry, parentActivity == operationActivity.Parent ? null : parentActivity);
});
if (!isActivityAvailable)
{
// Parent context store is assigned to operation that is used to restore call context.
operationHolder = new OperationHolder<T>(telemetryClient, operationTelemetry)
{
ParentContext = CallContextHelpers.GetCurrentOperationContext(),
};
telemetryContext.Id = operationTelemetry.Id;
}
operationTelemetry.Start();
if (!isActivityAvailable)
{
// Update the call context to store certain fields that can be used for subsequent operations.
var operationContext = new OperationContextForCallContext
{
ParentOperationId = operationTelemetry.Id,
RootOperationId = operationTelemetry.Context.Operation.Id,
RootOperationName = operationTelemetry.Context.Operation.Name,
};
CallContextHelpers.SaveOperationContext(operationContext);
}
return operationHolder;
}