/// <summary> /// Creates an operation object with a given telemetry item. /// </summary> /// <typeparam name="T">Type of the telemetry item.</typeparam> /// <param name="telemetryClient">Telemetry client object.</param> /// <param name="operationTelemetry">Operation to start.</param> /// <returns>Operation item object with a new telemetry item having current start time and timestamp.</returns> public static IOperationHolder <T> StartOperation <T>(this TelemetryClient telemetryClient, T operationTelemetry) where T : OperationTelemetry { if (telemetryClient == null) { throw new ArgumentNullException("Telemetry client cannot be null."); } if (operationTelemetry == null) { throw new ArgumentNullException("operationTelemetry cannot be null."); } // 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 refactored to work without ikey in Start event (or ikey is set) // and does not require other properties in telemetry telemetryClient.Initialize(operationTelemetry); var telemetryContext = operationTelemetry.Context.Operation; // 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 and id as a context (root) operation name and id if (string.IsNullOrEmpty(telemetryContext.Id)) { telemetryContext.Id = operationTelemetry.Id; } if (string.IsNullOrEmpty(telemetryContext.Name)) { telemetryContext.Name = operationTelemetry.Name; } bool isActivityAvailable = false; 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 (parentActivity == null) { // telemetryContext.Id is always set: if it was null, it is set to opTelemetry.Id and opTelemetry.Id is never null operationActivity.SetParentId(telemetryContext.Id); } operationActivity.Start(); operationTelemetry.Id = operationActivity.Id; }); var operationHolder = new OperationHolder <T>(telemetryClient, operationTelemetry); if (!isActivityAvailable) { // Parent context store is assigned to operation that is used to restore call context. operationHolder.ParentContext = CallContextHelpers.GetCurrentOperationContext(); } 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); }
/// <summary> /// Initializes/Adds operation id to the existing telemetry item. /// </summary> /// <param name="telemetryItem">Target telemetry item to add operation id.</param> public void Initialize(ITelemetry telemetryItem) { var itemContext = telemetryItem.Context.Operation; var telemetryProp = telemetryItem as ISupportProperties; bool isActivityAvailable = false; isActivityAvailable = ActivityExtensions.TryRun(() => { var currentActivity = Activity.Current; if (currentActivity != null) { if (string.IsNullOrEmpty(itemContext.Id)) { itemContext.Id = currentActivity.RootId; if (string.IsNullOrEmpty(itemContext.ParentId)) { itemContext.ParentId = currentActivity.Id; } foreach (var baggage in currentActivity.Baggage) { if (telemetryProp != null && !telemetryProp.Properties.ContainsKey(baggage.Key)) { telemetryProp.Properties.Add(baggage); } } } string operationName = currentActivity.GetOperationName(); if (string.IsNullOrEmpty(itemContext.Name) && !string.IsNullOrEmpty(operationName)) { itemContext.Name = operationName; } } }); if (!isActivityAvailable) { if (string.IsNullOrEmpty(itemContext.ParentId) || string.IsNullOrEmpty(itemContext.Id) || string.IsNullOrEmpty(itemContext.Name)) { var parentContext = CallContextHelpers.GetCurrentOperationContext(); if (parentContext != null) { if (string.IsNullOrEmpty(itemContext.ParentId) && !string.IsNullOrEmpty(parentContext.ParentOperationId)) { itemContext.ParentId = parentContext.ParentOperationId; } if (string.IsNullOrEmpty(itemContext.Id) && !string.IsNullOrEmpty(parentContext.RootOperationId)) { itemContext.Id = parentContext.RootOperationId; } if (string.IsNullOrEmpty(itemContext.Name) && !string.IsNullOrEmpty(parentContext.RootOperationName)) { itemContext.Name = parentContext.RootOperationName; } if (parentContext.CorrelationContext != null) { foreach (var item in parentContext.CorrelationContext) { if (telemetryProp != null && !telemetryProp.Properties.ContainsKey(item.Key)) { telemetryProp.Properties.Add(item); } } } } } } }
/// <summary> /// Creates an operation object with a given telemetry item. /// </summary> /// <typeparam name="T">Type of the telemetry item.</typeparam> /// <param name="telemetryClient">Telemetry client object.</param> /// <param name="operationTelemetry">Operation to start.</param> /// <returns>Operation item object with a new telemetry item having current start time and timestamp.</returns> 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(); } // ID takes the form |TraceID.SpanId. // TelemetryContext.Id used instead of TraceID.ToHexString() for perf. operationTelemetry.Id = W3CUtilities.FormatTelemetryId(telemetryContext.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); }
public void StartDependencyTrackingStoresTheArgumentOperationNameInContext() { var operation = this.telemetryClient.StartOperation <DependencyTelemetry>("TestOperationName"); Assert.AreEqual("TestOperationName", CallContextHelpers.GetCurrentOperationContext().RootOperationName); }
/// <summary> /// Creates an operation object with a given telemetry item. /// </summary> /// <typeparam name="T">Type of the telemetry item.</typeparam> /// <param name="telemetryClient">Telemetry client object.</param> /// <param name="operationTelemetry">Operation to start.</param> /// <returns>Operation item object with a new telemetry item having current start time and timestamp.</returns> public static IOperationHolder <T> StartOperation <T>(this TelemetryClient telemetryClient, T operationTelemetry) where T : OperationTelemetry { if (telemetryClient == null) { throw new ArgumentNullException("Telemetry client cannot be null."); } if (operationTelemetry == null) { throw new ArgumentNullException("operationTelemetry cannot be null."); } telemetryClient.Initialize(operationTelemetry); var telemetryContext = operationTelemetry.Context.Operation; // 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 and id as a context (root) operation name and id if (string.IsNullOrEmpty(telemetryContext.Id)) { telemetryContext.Id = operationTelemetry.Id; } if (string.IsNullOrEmpty(telemetryContext.Name)) { telemetryContext.Name = operationTelemetry.Name; } bool isActivityAvailable = false; #if !NET40 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 (parentActivity == null) { // telemetryContext.Id is always set: if it was null, it is set to opTelemetry.Id and opTelemetry.Id is never null operationActivity.SetParentId(telemetryContext.Id); } operationActivity.Start(); operationTelemetry.Id = operationActivity.Id; }); #endif var operationHolder = new OperationHolder <T>(telemetryClient, operationTelemetry); if (!isActivityAvailable) { // Parent context store is assigned to operation that is used to restore call context. operationHolder.ParentContext = CallContextHelpers.GetCurrentOperationContext(); } 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); }
/// <summary> /// Initializes/Adds operation context to the existing telemetry item. /// </summary> /// <param name="telemetryItem">Target telemetry item to add operation context.</param> public void Initialize(ITelemetry telemetryItem) { var itemOperationContext = telemetryItem.Context.Operation; var telemetryProp = telemetryItem as ISupportProperties; bool isActivityAvailable = false; isActivityAvailable = ActivityExtensions.TryRun(() => { var currentActivity = Activity.Current; if (currentActivity != null) { // we are going to set tracestate property on requests and dependencies only if (currentActivity.IdFormat == ActivityIdFormat.W3C && !string.IsNullOrEmpty(currentActivity.TraceStateString) && telemetryItem is OperationTelemetry && telemetryProp != null && !telemetryProp.Properties.ContainsKey(TracestatePropertyKey)) { telemetryProp.Properties.Add(TracestatePropertyKey, currentActivity.TraceStateString); } // update proactive sampling decision if Activity is recorded // sampling processor may change the decision if (currentActivity.Recorded && telemetryItem is ISupportAdvancedSampling supportSamplingTelemetry && supportSamplingTelemetry.ProactiveSamplingDecision == SamplingDecision.None) { supportSamplingTelemetry.ProactiveSamplingDecision = SamplingDecision.SampledIn; } if (string.IsNullOrEmpty(itemOperationContext.Id)) { if (currentActivity.IdFormat == ActivityIdFormat.W3C) { // Set OperationID to Activity.TraceId // itemOperationContext.Id = currentActivity.RootId; // check if this can be used itemOperationContext.Id = currentActivity.TraceId.ToHexString(); // Set OperationParentID to ID of parent, constructed as !traceid.spanid. // ID for auto collected Request,Dependency are constructed as !traceid.spanid, so parentid must be set to the same format. // While it is possible to set SpanID as the ID for auto collected Request,Dependency we have to stick to this format // to maintain compatibility. This limitation may go away in the future. if (string.IsNullOrEmpty(itemOperationContext.ParentId)) { itemOperationContext.ParentId = W3CUtilities.FormatTelemetryId(itemOperationContext.Id, currentActivity.SpanId.ToHexString()); } } else { itemOperationContext.Id = currentActivity.RootId; if (string.IsNullOrEmpty(itemOperationContext.ParentId)) { itemOperationContext.ParentId = currentActivity.Id; } } foreach (var baggage in currentActivity.Baggage) { if (telemetryProp != null && !telemetryProp.Properties.ContainsKey(baggage.Key)) { telemetryProp.Properties.Add(baggage); } } if (string.IsNullOrEmpty(itemOperationContext.Name)) { string operationName = currentActivity.GetOperationName(); if (!string.IsNullOrEmpty(operationName)) { itemOperationContext.Name = operationName; } } } } }); if (!isActivityAvailable) { if (string.IsNullOrEmpty(itemOperationContext.ParentId) || string.IsNullOrEmpty(itemOperationContext.Id) || string.IsNullOrEmpty(itemOperationContext.Name)) { var parentContext = CallContextHelpers.GetCurrentOperationContext(); if (parentContext != null) { if (string.IsNullOrEmpty(itemOperationContext.ParentId) && !string.IsNullOrEmpty(parentContext.ParentOperationId)) { itemOperationContext.ParentId = parentContext.ParentOperationId; } if (string.IsNullOrEmpty(itemOperationContext.Id) && !string.IsNullOrEmpty(parentContext.RootOperationId)) { itemOperationContext.Id = parentContext.RootOperationId; } if (string.IsNullOrEmpty(itemOperationContext.Name) && !string.IsNullOrEmpty(parentContext.RootOperationName)) { itemOperationContext.Name = parentContext.RootOperationName; } if (parentContext.CorrelationContext != null) { foreach (var item in parentContext.CorrelationContext) { if (telemetryProp != null && !telemetryProp.Properties.ContainsKey(item.Key)) { telemetryProp.Properties.Add(item); } } } } } } }
/// <summary> /// Initializes/Adds operation id to the existing telemetry item. /// </summary> /// <param name="telemetryItem">Target telemetry item to add operation id.</param> public void Initialize(ITelemetry telemetryItem) { try { var itemContext = telemetryItem.Context.Operation; var telemetryProp = telemetryItem as ISupportProperties; bool isActivityAvailable = false; isActivityAvailable = ActivityExtensions.TryRun(() => { var currentActivity = Activity.Current; if (currentActivity != null) { if (string.IsNullOrEmpty(itemContext.Id)) { itemContext.Id = currentActivity.RootId; if (string.IsNullOrEmpty(itemContext.ParentId)) { itemContext.ParentId = currentActivity.Id; } foreach (var baggage in currentActivity.Baggage) { if (telemetryProp != null && !telemetryProp.Properties.ContainsKey(baggage.Key)) { telemetryProp.Properties.Add(baggage); } } } string operationName = currentActivity.GetOperationName(); if (string.IsNullOrEmpty(itemContext.Name) && !string.IsNullOrEmpty(operationName)) { itemContext.Name = operationName; } } }); if (!isActivityAvailable) { if (string.IsNullOrEmpty(itemContext.ParentId) || string.IsNullOrEmpty(itemContext.Id) || string.IsNullOrEmpty(itemContext.Name)) { var parentContext = CallContextHelpers.GetCurrentOperationContext(); if (parentContext != null) { if (string.IsNullOrEmpty(itemContext.ParentId) && !string.IsNullOrEmpty(parentContext.ParentOperationId)) { itemContext.ParentId = parentContext.ParentOperationId; } if (string.IsNullOrEmpty(itemContext.Id) && !string.IsNullOrEmpty(parentContext.RootOperationId)) { itemContext.Id = parentContext.RootOperationId; } if (string.IsNullOrEmpty(itemContext.Name) && !string.IsNullOrEmpty(parentContext.RootOperationName)) { itemContext.Name = parentContext.RootOperationName; } if (parentContext.CorrelationContext != null) { foreach (var item in parentContext.CorrelationContext) { if (telemetryProp != null && !telemetryProp.Properties.ContainsKey(item.Key)) { telemetryProp.Properties.Add(item); } } } } } } } catch (Exception ex) { TelemetryDebugWriter.WriteError( "Something went wrong when initializing [" + this.GetType().Name + "]. This initializer will be ignored." + ex); } }
/// <summary> /// Initializes/Adds operation context to the existing telemetry item. /// </summary> /// <param name="telemetryItem">Target telemetry item to add operation context.</param> public void Initialize(ITelemetry telemetryItem) { if (telemetryItem == null) { throw new ArgumentNullException(nameof(telemetryItem)); } var itemOperationContext = telemetryItem.Context.Operation; var telemetryProp = telemetryItem as ISupportProperties; bool isActivityAvailable = false; isActivityAvailable = ActivityExtensions.TryRun(() => { var currentActivity = Activity.Current; if (currentActivity != null) { // we are going to set tracestate property on requests and dependencies only if (currentActivity.IdFormat == ActivityIdFormat.W3C && !string.IsNullOrEmpty(currentActivity.TraceStateString) && telemetryItem is OperationTelemetry && telemetryProp != null && !telemetryProp.Properties.ContainsKey(TracestatePropertyKey)) { telemetryProp.Properties.Add(TracestatePropertyKey, currentActivity.TraceStateString); } // update proactive sampling decision if Activity is recorded // sampling processor may change the decision if (currentActivity.Recorded && telemetryItem is ISupportAdvancedSampling supportSamplingTelemetry && supportSamplingTelemetry.ProactiveSamplingDecision == SamplingDecision.None) { supportSamplingTelemetry.ProactiveSamplingDecision = SamplingDecision.SampledIn; } if (string.IsNullOrEmpty(itemOperationContext.Id)) { if (currentActivity.IdFormat == ActivityIdFormat.W3C) { // Set OperationID to Activity.TraceId // itemOperationContext.Id = currentActivity.RootId; // check if this can be used itemOperationContext.Id = currentActivity.TraceId.ToHexString(); if (string.IsNullOrEmpty(itemOperationContext.ParentId)) { itemOperationContext.ParentId = currentActivity.SpanId.ToHexString(); } } else { itemOperationContext.Id = currentActivity.RootId; if (string.IsNullOrEmpty(itemOperationContext.ParentId)) { itemOperationContext.ParentId = currentActivity.Id; } } foreach (var baggage in currentActivity.Baggage) { if (telemetryProp != null && !telemetryProp.Properties.ContainsKey(baggage.Key)) { telemetryProp.Properties.Add(baggage); } } if (string.IsNullOrEmpty(itemOperationContext.Name)) { string operationName = currentActivity.GetOperationName(); if (!string.IsNullOrEmpty(operationName)) { itemOperationContext.Name = operationName; } } } } }); if (!isActivityAvailable) { if (string.IsNullOrEmpty(itemOperationContext.ParentId) || string.IsNullOrEmpty(itemOperationContext.Id) || string.IsNullOrEmpty(itemOperationContext.Name)) { var parentContext = CallContextHelpers.GetCurrentOperationContext(); if (parentContext != null) { if (string.IsNullOrEmpty(itemOperationContext.ParentId) && !string.IsNullOrEmpty(parentContext.ParentOperationId)) { itemOperationContext.ParentId = parentContext.ParentOperationId; } if (string.IsNullOrEmpty(itemOperationContext.Id) && !string.IsNullOrEmpty(parentContext.RootOperationId)) { itemOperationContext.Id = parentContext.RootOperationId; } if (string.IsNullOrEmpty(itemOperationContext.Name) && !string.IsNullOrEmpty(parentContext.RootOperationName)) { itemOperationContext.Name = parentContext.RootOperationName; } if (parentContext.CorrelationContext != null) { foreach (var item in parentContext.CorrelationContext) { if (telemetryProp != null && !telemetryProp.Properties.ContainsKey(item.Key)) { telemetryProp.Properties.Add(item); } } } } } } }