public void BeginWebTrackingReturnsOperationItemWithTelemetryItem() { var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); Assert.AreEqual(telemetry.StartTime, telemetry.StartTime); Assert.AreEqual(telemetry.Timestamp, telemetry.Timestamp); }
/// <summary> /// On begin callback from Framework event source. /// </summary> /// <param name="id">Identifier of SQL connection object.</param> /// <param name="dataSource">Data source name.</param> /// <param name="database">Database name.</param> /// <param name="commandText">Command text.</param> public void OnBeginExecuteCallback(long id, string dataSource, string database, string commandText) { try { var resourceName = this.GetResourceName(dataSource, database, commandText); DependencyCollectorEventSource.Log.BeginCallbackCalled(id, resourceName); if (string.IsNullOrEmpty(resourceName)) { DependencyCollectorEventSource.Log.NotExpectedCallback(id, "OnBeginSql", "resourceName is empty"); return; } var telemetryTuple = this.TelemetryTable.Get(id); if (telemetryTuple == null) { bool isCustomCreated = false; var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); telemetry.Name = resourceName; telemetry.DependencyKind = RemoteDependencyKind.SQL.ToString(); this.TelemetryTable.Store(id, new Tuple <DependencyTelemetry, bool>(telemetry, isCustomCreated)); } } catch (Exception exception) { DependencyCollectorEventSource.Log.CallbackError(id, "OnBeginSql", exception); } }
public void EndTrackingComputesTheDurationOfTelemetryItem() { var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); ClientServerDependencyTracker.EndTracking(this.telemetryClient, telemetry); var telemetryItem = this.sendItems[0] as DependencyTelemetry; this.ValidateSentTelemetry(telemetryItem); }
/// <summary> /// On begin callback from Framework event source. /// </summary> /// <param name="id">This object.</param> /// <param name="resourceName">URI of the web request.</param> public void OnBeginHttpCallback(long id, string resourceName) { try { DependencyCollectorEventSource.Log.BeginCallbackCalled(id, resourceName); if (string.IsNullOrEmpty(resourceName)) { DependencyCollectorEventSource.Log.NotExpectedCallback(id, "OnBeginHttp", "resourceName is empty"); return; } if (this.applicationInsightsUrlFilter.IsApplicationInsightsUrl(resourceName)) { return; } Uri url; try { url = new Uri(resourceName); } catch (UriFormatException) { DependencyCollectorEventSource.Log.NotExpectedCallback(id, "OnBeginHttp", "resourceName is not a URL " + resourceName); return; } var telemetryTuple = this.TelemetryTable.Get(id); if (telemetryTuple != null) { // this operation is already being tracked. We will not restart operation if (telemetryTuple.Item1 != null) { DependencyCollectorEventSource.Log.TrackingAnExistingTelemetryItemVerbose(); return; } } bool isCustomCreated = false; var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); telemetry.Type = RemoteDependencyConstants.HTTP; telemetry.Name = url.AbsolutePath; telemetry.Target = url.Host; telemetry.Data = url.OriginalString; this.TelemetryTable.Store(id, new Tuple <DependencyTelemetry, bool>(telemetry, isCustomCreated)); } catch (Exception exception) { DependencyCollectorEventSource.Log.CallbackError(id, "OnBeginHttp", exception); } }
/// <summary> /// Common helper for all Begin Callbacks. /// </summary> /// <param name="thisObj">This object.</param> /// <param name="isAsyncCall">Is Async Invocation.</param> /// <returns>The context for end callback.</returns> private object OnBegin(object thisObj, bool isAsyncCall) { try { if (thisObj == null) { DependencyCollectorEventSource.Log.NotExpectedCallback(0, "OnBeginSql", "thisObj == null"); return(null); } string resourceName = this.GetResourceName(thisObj); DependencyCollectorEventSource.Log.BeginCallbackCalled(thisObj.GetHashCode(), resourceName); if (string.IsNullOrEmpty(resourceName)) { DependencyCollectorEventSource.Log.NotExpectedCallback(thisObj.GetHashCode(), "OnBeginSql", "resourceName is empty"); return(null); } var telemetryTuple = this.TelemetryTable.Get(thisObj); if (telemetryTuple != null) { // The BeginExecuteReader method returns immediately, but until the code executes the corresponding EndExecuteReader method call, // it must not execute any other calls that start a synchronous or asynchronous execution against the same SqlCommand object. // howeever if customer tries to execute such call we need clean the watch state as command execution is incorrect to not report the wrong data. // note: This particular case is not dealt with in HTTP case. if (telemetryTuple.Item1 != null) { DependencyCollectorEventSource.Log.TrackingAnExistingTelemetryItemVerbose(); return(null); } } string commandText = this.GetCommandName(thisObj); // Try to begin if sampling this operation bool isCustomCreated = false; var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); telemetry.Name = resourceName; telemetry.DependencyKind = RemoteDependencyKind.SQL.ToString(); telemetry.CommandName = commandText; // We use weaktables to store the thisObj for correlating begin with end call. this.TelemetryTable.Store(thisObj, new Tuple <DependencyTelemetry, bool>(telemetry, isCustomCreated)); return(null); } catch (Exception exception) { DependencyCollectorEventSource.Log.CallbackError(thisObj == null ? 0 : thisObj.GetHashCode(), "OnBeginSql", exception); } return(null); }
/// <summary> /// Common helper for all Begin Callbacks. /// </summary> /// <param name="thisObj">This object.</param> /// <param name="isAsyncCall">Indicates if the method used is async or not.</param> /// <returns>Null object as all context is maintained in this class via weak tables.</returns> private object OnBegin(object thisObj, bool isAsyncCall) { try { if (thisObj == null) { DependencyCollectorEventSource.Log.NotExpectedCallback(0, "OnBeginHttp", "thisObj == null"); return(null); } string resourceName = this.GetResourceName(thisObj); DependencyCollectorEventSource.Log.BeginCallbackCalled(thisObj.GetHashCode(), resourceName); if (string.IsNullOrEmpty(resourceName)) { DependencyCollectorEventSource.Log.NotExpectedCallback(thisObj.GetHashCode(), "OnBeginHttp", "resourceName is empty"); return(null); } if (this.applicationInsightsUrlFilter.IsApplicationInsightsUrl(resourceName)) { // Not logging as we will be logging for all outbound AI calls return(null); } // If the object already exists, dont add again. This happens because either GetResponse or GetRequestStream could // be the starting point for the outbound call. var telemetryTuple = this.TelemetryTable.Get(thisObj); if (telemetryTuple != null) { if (telemetryTuple.Item1 != null) { DependencyCollectorEventSource.Log.TrackingAnExistingTelemetryItemVerbose(); return(null); } } bool isCustomCreated = false; var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); telemetry.Name = resourceName; telemetry.DependencyKind = RemoteDependencyKind.Http.ToString(); this.TelemetryTable.Store(thisObj, new Tuple <DependencyTelemetry, bool>(telemetry, isCustomCreated)); } catch (Exception exception) { DependencyCollectorEventSource.Log.CallbackError(thisObj == null ? 0 : thisObj.GetHashCode(), "OnBeginHttp", exception); } return(null); }
public void BeginWebTrackingReturnsOperationItemWithTelemetryItem() { var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); Assert.AreEqual(telemetry.Timestamp, telemetry.Timestamp); Assert.IsNull(telemetry.Context.Operation.ParentId); Assert.IsNotNull(telemetry.Context.Operation.Id); Assert.IsTrue(telemetry.Id.StartsWith('|' + telemetry.Context.Operation.Id, StringComparison.Ordinal)); Assert.AreEqual(0, telemetry.Context.Properties.Count); }
public void EndTrackingSendsTelemetryItemOnSuccess() { var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); ClientServerDependencyTracker.EndTracking(this.telemetryClient, telemetry); Assert.AreEqual(1, this.sendItems.Count); telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); ClientServerDependencyTracker.EndTracking(this.telemetryClient, telemetry); Assert.AreEqual(2, this.sendItems.Count); }
/// <summary> /// Common helper for all Begin Callbacks. /// </summary> /// <param name="thisObj">This object.</param> /// <returns>The context for end callback.</returns> private object OnBegin(object thisObj) { try { if (thisObj == null) { DependencyCollectorEventSource.Log.NotExpectedCallback(0, "OnBeginSql", "thisObj == null"); return(null); } string resourceName = this.GetDependencyName(thisObj); DependencyCollectorEventSource.Log.BeginCallbackCalled(thisObj.GetHashCode(), resourceName); if (string.IsNullOrEmpty(resourceName)) { DependencyCollectorEventSource.Log.NotExpectedCallback(thisObj.GetHashCode(), "OnBeginSql", "resourceName is empty"); return(null); } var telemetryTuple = this.TelemetryTable.Get(thisObj); if (telemetryTuple != null) { // We are already tracking this item if (telemetryTuple.Item1 != null) { DependencyCollectorEventSource.Log.TrackingAnExistingTelemetryItemVerbose(); return(null); } } string commandText = this.GetCommandName(thisObj); // Try to begin if sampling this operation bool isCustomCreated = false; var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); telemetry.Name = resourceName; telemetry.Type = RemoteDependencyConstants.SQL; telemetry.Target = this.GetDependencyTarget(thisObj); telemetry.Data = commandText; telemetry.SetOperationDetail(RemoteDependencyConstants.SqlCommandOperationDetailName, thisObj); // We use weaktables to store the thisObj for correlating begin with end call. this.TelemetryTable.Store(thisObj, new Tuple <DependencyTelemetry, bool>(telemetry, isCustomCreated)); return(null); } catch (Exception exception) { DependencyCollectorEventSource.Log.CallbackError(thisObj == null ? 0 : thisObj.GetHashCode(), "OnBeginSql", exception); } return(null); }
public void EndTrackingTracksTelemetryItemWithInitializedContent() { var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); ClientServerDependencyTracker.EndTracking(this.telemetryClient, telemetry); var telemetryItem = this.sendItems[0] as DependencyTelemetry; Assert.IsNotNull(telemetryItem.Context.User.Id); Assert.IsNotNull(telemetryItem.Context.Session.Id); Assert.AreEqual(telemetryItem.Context.User.Id, "UserID"); Assert.AreEqual(telemetryItem.Context.Session.Id, "SessionID"); }
/// <summary> /// On begin callback from Framework event source. /// </summary> /// <param name="id">Identifier of SQL connection object.</param> /// <param name="dataSource">Data source name.</param> /// <param name="database">Database name.</param> /// <param name="commandText">Command text.</param> public void OnBeginExecuteCallback(long id, string dataSource, string database, string commandText) { try { var resourceName = this.GetResourceName(dataSource, database, commandText); DependencyCollectorEventSource.Log.BeginCallbackCalled(id, resourceName); if (string.IsNullOrEmpty(resourceName)) { DependencyCollectorEventSource.Log.NotExpectedCallback(id, "OnBeginSql", "resourceName is empty"); return; } var telemetryTuple = this.TelemetryTable.Get(id); if (telemetryTuple == null) { bool isCustomCreated = false; var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); telemetry.Name = resourceName; telemetry.DependencyKind = RemoteDependencyKind.SQL.ToString(); this.TelemetryTable.Store(id, new Tuple <DependencyTelemetry, bool>(telemetry, isCustomCreated)); } else { // The BeginExecuteReader method returns immediately, but until the code executes the corresponding EndExecuteReader method call, // it must not execute any other calls that start a synchronous or asynchronous execution against the same SqlCommand object. // howeever if customer tries to execute such call we need clean the watch state as command execution is incorrect to not report the wrong data. // note: This particular case is not dealt with in HTTP case. if (!telemetryTuple.Item2) { this.TelemetryTable.Remove(id); } DependencyCollectorEventSource.Log.RemoteDependencyModuleVerbose("SqlProcessingFramework.OnBegin removed the entry from cache to prevent incorrect information for " + resourceName); } } catch (Exception exception) { DependencyCollectorEventSource.Log.CallbackError(id, "OnBeginSql", exception); } }
/// <summary> /// On begin callback from Framework event source. /// </summary> /// <param name="id">This object.</param> /// <param name="resourceName">URI of the web request.</param> public void OnBeginHttpCallback(long id, string resourceName) { try { DependencyCollectorEventSource.Log.BeginCallbackCalled(id, resourceName); if (string.IsNullOrEmpty(resourceName)) { DependencyCollectorEventSource.Log.NotExpectedCallback(id, "OnBeginHttp", "resourceName is empty"); return; } if (this.applicationInsightsUrlFilter.IsApplicationInsightsUrl(resourceName)) { return; } var telemetryTuple = this.TelemetryTable.Get(id); if (telemetryTuple != null) { // this operation is already being tracked. We will not restart operation if (telemetryTuple.Item1 != null) { DependencyCollectorEventSource.Log.TrackingAnExistingTelemetryItemVerbose(); return; } } bool isCustomCreated = false; var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); telemetry.Name = resourceName; this.TelemetryTable.Store(id, new Tuple <DependencyTelemetry, bool>(telemetry, isCustomCreated)); } catch (Exception exception) { DependencyCollectorEventSource.Log.CallbackError(id, "OnBeginHttp", exception); } }
public void BeginWebTrackingWithParentActivityReturnsOperationItemWithTelemetryItem() { var parentActivity = new Activity("test"); parentActivity.SetParentId("|guid.1234_"); parentActivity.AddBaggage("k", "v"); parentActivity.Start(); var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); Assert.AreEqual(parentActivity.Id, telemetry.Context.Operation.ParentId); Assert.AreEqual(parentActivity.RootId, telemetry.Context.Operation.Id); var properties = telemetry.Context.Properties; Assert.AreEqual(1, properties.Count); Assert.AreEqual("v", properties["k"]); parentActivity.Stop(); }
public void BeginWebTrackingWithParentCallContextReturnsOperationItemWithTelemetryItem() { var requestTelemetry = new RequestTelemetry { Id = "|guid.1234_" }; var correlationContext = new Dictionary <string, string> { ["k"] = "v" }; CorrelationHelper.SetOperationContext(requestTelemetry, correlationContext); var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); Assert.AreEqual("|guid.1234_", telemetry.Context.Operation.ParentId); Assert.AreEqual("guid", telemetry.Context.Operation.Id); var properties = telemetry.Context.Properties; Assert.AreEqual(1, properties.Count); Assert.AreEqual("v", properties["k"]); CorrelationHelper.CleanOperationContext(); }
/// <summary> /// On begin callback from Framework event source. /// </summary> /// <param name="id">Identifier of SQL connection object.</param> /// <param name="dataSource">Data source name.</param> /// <param name="database">Database name.</param> /// <param name="commandText">Command text.</param> public void OnBeginExecuteCallback(long id, string dataSource, string database, string commandText) { try { var resourceName = GetResourceName(dataSource, database); DependencyCollectorEventSource.Log.BeginCallbackCalled(id, resourceName); if (string.IsNullOrEmpty(resourceName)) { DependencyCollectorEventSource.Log.NotExpectedCallback(id, "OnBeginSql", "resourceName is empty"); return; } var telemetryTuple = this.TelemetryTable.Get(id); if (telemetryTuple == null) { var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); telemetry.Name = resourceName; telemetry.Target = string.Join(" | ", dataSource, database); telemetry.Type = RemoteDependencyConstants.SQL; telemetry.Data = commandText; this.TelemetryTable.Store(id, new Tuple <DependencyTelemetry, bool>(telemetry, false)); } } catch (Exception exception) { DependencyCollectorEventSource.Log.CallbackError(id, "OnBeginSql", exception); } finally { Activity current = Activity.Current; if (current?.OperationName == ClientServerDependencyTracker.DependencyActivityName) { current.Stop(); } } }
/// <summary> /// Common helper for all Begin Callbacks. /// </summary> /// <param name="thisObj">This object.</param> /// <param name="isAsyncCall">Indicates if the method used is async or not.</param> /// <returns>Null object as all context is maintained in this class via weak tables.</returns> private object OnBegin(object thisObj, bool isAsyncCall) { try { if (thisObj == null) { DependencyCollectorEventSource.Log.NotExpectedCallback(0, "OnBeginHttp", "thisObj == null"); return(null); } WebRequest webRequest = thisObj as WebRequest; if (webRequest == null) { DependencyCollectorEventSource.Log.UnexpectedCallbackParameter("WebRequest"); } var url = this.GetUrl(webRequest); if (url == null) { DependencyCollectorEventSource.Log.NotExpectedCallback(thisObj.GetHashCode(), "OnBeginHttp", "resourceName is empty"); return(null); } string httMethod = webRequest.Method; string resourceName = url.AbsolutePath; if (!string.IsNullOrEmpty(httMethod)) { resourceName = httMethod + " " + resourceName; } DependencyCollectorEventSource.Log.BeginCallbackCalled(thisObj.GetHashCode(), resourceName); if (this.applicationInsightsUrlFilter.IsApplicationInsightsUrl(url.ToString())) { // Not logging as we will be logging for all outbound AI calls return(null); } // If the object already exists, dont add again. This happens because either GetResponse or GetRequestStream could // be the starting point for the outbound call. var telemetryTuple = this.TelemetryTable.Get(thisObj); if (telemetryTuple != null) { if (telemetryTuple.Item1 != null) { DependencyCollectorEventSource.Log.TrackingAnExistingTelemetryItemVerbose(); return(null); } } bool isCustomCreated = false; var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); telemetry.Name = resourceName; telemetry.Target = url.Host; telemetry.Type = RemoteDependencyConstants.HTTP; telemetry.Data = url.OriginalString; this.TelemetryTable.Store(thisObj, new Tuple <DependencyTelemetry, bool>(telemetry, isCustomCreated)); } catch (Exception exception) { DependencyCollectorEventSource.Log.CallbackError(thisObj == null ? 0 : thisObj.GetHashCode(), "OnBeginHttp", exception); } return(null); }
/// <summary> /// Common helper for all Begin Callbacks. /// </summary> /// <param name="thisObj">This object.</param> /// <param name="isAsyncCall">Indicates if the method used is async or not.</param> /// <returns>Null object as all context is maintained in this class via weak tables.</returns> private object OnBegin(object thisObj, bool isAsyncCall) { try { if (thisObj == null) { DependencyCollectorEventSource.Log.NotExpectedCallback(0, "OnBeginHttp", "thisObj == null"); return(null); } WebRequest webRequest = thisObj as WebRequest; if (webRequest == null) { DependencyCollectorEventSource.Log.UnexpectedCallbackParameter("WebRequest"); } var url = this.GetUrl(webRequest); if (url == null) { DependencyCollectorEventSource.Log.NotExpectedCallback(thisObj.GetHashCode(), "OnBeginHttp", "resourceName is empty"); return(null); } string httMethod = webRequest.Method; string resourceName = url.AbsolutePath; if (!string.IsNullOrEmpty(httMethod)) { resourceName = httMethod + " " + resourceName; } DependencyCollectorEventSource.Log.BeginCallbackCalled(thisObj.GetHashCode(), resourceName); if (this.applicationInsightsUrlFilter.IsApplicationInsightsUrl(url.ToString())) { // Not logging as we will be logging for all outbound AI calls return(null); } // If the object already exists, don't add again. This happens because either GetResponse or GetRequestStream could // be the starting point for the outbound call. var telemetryTuple = this.TelemetryTable.Get(thisObj); if (telemetryTuple != null) { if (telemetryTuple.Item1 != null) { DependencyCollectorEventSource.Log.TrackingAnExistingTelemetryItemVerbose(); return(null); } } bool isCustomCreated = false; var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); telemetry.Name = resourceName; telemetry.Target = DependencyTargetNameHelper.GetDependencyTargetName(url); telemetry.Type = RemoteDependencyConstants.HTTP; telemetry.Data = url.OriginalString; this.TelemetryTable.Store(thisObj, new Tuple <DependencyTelemetry, bool>(telemetry, isCustomCreated)); if (string.IsNullOrEmpty(telemetry.Context.InstrumentationKey)) { // Instrumentation key is probably empty, because the context has not yet had a chance to associate the requestTelemetry to the telemetry client yet. // and get they instrumentation key from all possible sources in the process. Let's do that now. this.telemetryClient.Initialize(telemetry); } // Add the source instrumentation key header if collection is enabled, the request host is not in the excluded list and the same header doesn't already exist if (this.setCorrelationHeaders && !this.correlationDomainExclusionList.Contains(url.Host)) { if (!string.IsNullOrEmpty(telemetry.Context.InstrumentationKey) && webRequest.Headers[RequestResponseHeaders.SourceInstrumentationKeyHeader] == null) { webRequest.Headers.Add(RequestResponseHeaders.SourceInstrumentationKeyHeader, InstrumentationKeyHashLookupHelper.GetInstrumentationKeyHash(telemetry.Context.InstrumentationKey)); } // Add the root ID var rootId = telemetry.Context.Operation.Id; if (!string.IsNullOrEmpty(rootId) && webRequest.Headers[RequestResponseHeaders.StandardRootIdHeader] == null) { webRequest.Headers.Add(RequestResponseHeaders.StandardRootIdHeader, rootId); } // Add the parent ID var parentId = telemetry.Id; if (!string.IsNullOrEmpty(parentId) && webRequest.Headers[RequestResponseHeaders.StandardParentIdHeader] == null) { webRequest.Headers.Add(RequestResponseHeaders.StandardParentIdHeader, parentId); } } } catch (Exception exception) { DependencyCollectorEventSource.Log.CallbackError(thisObj == null ? 0 : thisObj.GetHashCode(), "OnBeginHttp", exception); } return(null); }
/// <summary> /// Common helper for all Begin Callbacks. /// </summary> /// <param name="thisObj">This object.</param> /// <param name="injectCorrelationHeaders">Flag that enables Request-Id and Correlation-Context headers injection. /// Should be set to true only for profiler and old versions of DiagnosticSource Http hook events.</param> /// <returns>Null object as all context is maintained in this class via weak tables.</returns> internal object OnBegin(object thisObj, bool injectCorrelationHeaders = true) { try { if (thisObj == null) { DependencyCollectorEventSource.Log.NotExpectedCallback(0, "OnBeginHttp", "thisObj == null"); return(null); } WebRequest webRequest = thisObj as WebRequest; if (webRequest == null) { DependencyCollectorEventSource.Log.UnexpectedCallbackParameter("WebRequest"); } var url = GetUrl(webRequest); if (url == null) { DependencyCollectorEventSource.Log.NotExpectedCallback(thisObj.GetHashCode(), "OnBeginHttp", "resourceName is empty"); return(null); } string httpMethod = webRequest.Method; string resourceName = url.AbsolutePath; if (!string.IsNullOrEmpty(httpMethod)) { resourceName = httpMethod + " " + resourceName; } DependencyCollectorEventSource.Log.BeginCallbackCalled(thisObj.GetHashCode(), resourceName); if (this.applicationInsightsUrlFilter.IsApplicationInsightsUrl(url)) { // Not logging as we will be logging for all outbound AI calls return(null); } if (webRequest.Headers[W3C.W3CConstants.TraceParentHeader] != null && Activity.DefaultIdFormat == ActivityIdFormat.W3C) { DependencyCollectorEventSource.Log.HttpRequestAlreadyInstrumented(); return(null); } // If the object already exists, don't add again. This happens because either GetResponse or GetRequestStream could // be the starting point for the outbound call. DependencyTelemetry telemetry = null; var telemetryTuple = this.GetTupleForWebDependencies(webRequest); if (telemetryTuple?.Item1 != null) { DependencyCollectorEventSource.Log.TrackingAnExistingTelemetryItemVerbose(); return(null); } // Create and initialize a new telemetry object telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); this.AddTupleForWebDependencies(webRequest, telemetry, false); if (string.IsNullOrEmpty(telemetry.Context.InstrumentationKey)) { // Instrumentation key is probably empty, because the context has not yet had a chance to associate the requestTelemetry to the telemetry client yet. // and get they instrumentation key from all possible sources in the process. Let's do that now. this.telemetryClient.InitializeInstrumentationKey(telemetry); } telemetry.Name = resourceName; telemetry.Target = DependencyTargetNameHelper.GetDependencyTargetName(url); telemetry.Type = RemoteDependencyConstants.HTTP; telemetry.Data = url.OriginalString; telemetry.SetOperationDetail(RemoteDependencyConstants.HttpRequestOperationDetailName, webRequest); Activity currentActivity = Activity.Current; // Add the source instrumentation key header if collection is enabled, the request host is not in the excluded list and the same header doesn't already exist if (this.setCorrelationHeaders && !this.correlationDomainExclusionList.Contains(url.Host)) { string applicationId = null; try { if (!string.IsNullOrEmpty(telemetry.Context.InstrumentationKey) && webRequest.Headers.GetNameValueHeaderValue(RequestResponseHeaders.RequestContextHeader, RequestResponseHeaders.RequestContextCorrelationSourceKey) == null && (this.configuration.ApplicationIdProvider?.TryGetApplicationId( telemetry.Context.InstrumentationKey, out applicationId) ?? false)) { webRequest.Headers.SetNameValueHeaderValue(RequestResponseHeaders.RequestContextHeader, RequestResponseHeaders.RequestContextCorrelationSourceKey, applicationId); } } catch (Exception ex) { AppMapCorrelationEventSource.Log.SetCrossComponentCorrelationHeaderFailed( ex.ToInvariantString()); } if (this.injectLegacyHeaders) { // Add the root ID var rootId = telemetry.Context.Operation.Id; if (!string.IsNullOrEmpty(rootId) && webRequest.Headers[RequestResponseHeaders.StandardRootIdHeader] == null) { webRequest.Headers.Add(RequestResponseHeaders.StandardRootIdHeader, rootId); } // Add the parent ID var parentId = telemetry.Id; if (!string.IsNullOrEmpty(parentId)) { if (webRequest.Headers[RequestResponseHeaders.StandardParentIdHeader] == null) { webRequest.Headers.Add(RequestResponseHeaders.StandardParentIdHeader, parentId); } } } if (currentActivity != null) { // ApplicationInsights only needs to inject W3C, potentially Request-Id and Correlation-Context // headers for profiler instrumentation. // in case of Http Desktop DiagnosticSourceListener they are injected in // DiagnosticSource (with the System.Net.Http.Desktop.HttpRequestOut.Start event) if (injectCorrelationHeaders) { if (currentActivity.IdFormat == ActivityIdFormat.W3C) { if (webRequest.Headers[W3C.W3CConstants.TraceParentHeader] == null) { webRequest.Headers.Add(W3C.W3CConstants.TraceParentHeader, currentActivity.Id); } if (webRequest.Headers[W3C.W3CConstants.TraceStateHeader] == null && !string.IsNullOrEmpty(currentActivity.TraceStateString)) { webRequest.Headers.Add(W3C.W3CConstants.TraceStateHeader, currentActivity.TraceStateString); } } else { // Request-Id format if (webRequest.Headers[RequestResponseHeaders.RequestIdHeader] == null) { webRequest.Headers.Add(RequestResponseHeaders.RequestIdHeader, telemetry.Id); } } InjectCorrelationContext(webRequest.Headers, currentActivity); } } } // Active bug in .NET Fx diagnostics hook: https://github.com/dotnet/corefx/pull/40777 // Application Insights has to inject Request-Id to work it around if (currentActivity?.IdFormat == ActivityIdFormat.W3C) { // if (this.injectRequestIdInW3CMode) { if (webRequest.Headers[RequestResponseHeaders.RequestIdHeader] == null) { webRequest.Headers.Add(RequestResponseHeaders.RequestIdHeader, string.Concat('|', telemetry.Context.Operation.Id, '.', telemetry.Id, '.')); } } } } catch (Exception exception) { DependencyCollectorEventSource.Log.CallbackError(thisObj == null ? 0 : thisObj.GetHashCode(), "OnBeginHttp", exception); } finally { Activity current = Activity.Current; if (current?.OperationName == ClientServerDependencyTracker.DependencyActivityName) { current.Stop(); } } return(null); }
/// <summary> /// Common helper for all Begin Callbacks. /// </summary> /// <param name="thisObj">This object.</param> /// <param name="injectCorrelationHeaders">Flag that enables Request-Id and Correlation-Context headers injection. /// Should be set to true only for profiler and old versions of DiagnosticSource Http hook events.</param> /// <returns>Null object as all context is maintained in this class via weak tables.</returns> internal object OnBegin(object thisObj, bool injectCorrelationHeaders = true) { try { if (thisObj == null) { DependencyCollectorEventSource.Log.NotExpectedCallback(0, "OnBeginHttp", "thisObj == null"); return(null); } WebRequest webRequest = thisObj as WebRequest; if (webRequest == null) { DependencyCollectorEventSource.Log.UnexpectedCallbackParameter("WebRequest"); } var url = this.GetUrl(webRequest); if (url == null) { DependencyCollectorEventSource.Log.NotExpectedCallback(thisObj.GetHashCode(), "OnBeginHttp", "resourceName is empty"); return(null); } string httpMethod = webRequest.Method; string resourceName = url.AbsolutePath; if (!string.IsNullOrEmpty(httpMethod)) { resourceName = httpMethod + " " + resourceName; } DependencyCollectorEventSource.Log.BeginCallbackCalled(thisObj.GetHashCode(), resourceName); if (this.applicationInsightsUrlFilter.IsApplicationInsightsUrl(url)) { // Not logging as we will be logging for all outbound AI calls return(null); } // If the object already exists, don't add again. This happens because either GetResponse or GetRequestStream could // be the starting point for the outbound call. DependencyTelemetry telemetry = null; var telemetryTuple = this.GetTupleForWebDependencies(webRequest); if (telemetryTuple != null) { if (telemetryTuple.Item1 != null) { telemetry = telemetryTuple.Item1; DependencyCollectorEventSource.Log.TrackingAnExistingTelemetryItemVerbose(); return(null); } } // Create and initialize a new telemetry object if needed if (telemetry == null) { bool isCustomCreated = false; telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); this.AddTupleForWebDependencies(webRequest, telemetry, isCustomCreated); if (string.IsNullOrEmpty(telemetry.Context.InstrumentationKey)) { // Instrumentation key is probably empty, because the context has not yet had a chance to associate the requestTelemetry to the telemetry client yet. // and get they instrumentation key from all possible sources in the process. Let's do that now. this.telemetryClient.Initialize(telemetry); } } telemetry.Name = resourceName; telemetry.Target = DependencyTargetNameHelper.GetDependencyTargetName(url); telemetry.Type = RemoteDependencyConstants.HTTP; telemetry.Data = url.OriginalString; // Add the source instrumentation key header if collection is enabled, the request host is not in the excluded list and the same header doesn't already exist if (this.setCorrelationHeaders && !this.correlationDomainExclusionList.Contains(url.Host)) { try { if (!string.IsNullOrEmpty(telemetry.Context.InstrumentationKey) && webRequest.Headers.GetNameValueHeaderValue(RequestResponseHeaders.RequestContextHeader, RequestResponseHeaders.RequestContextCorrelationSourceKey) == null) { string appId; if (this.correlationIdLookupHelper.TryGetXComponentCorrelationId(telemetry.Context.InstrumentationKey, out appId)) { webRequest.Headers.SetNameValueHeaderValue(RequestResponseHeaders.RequestContextHeader, RequestResponseHeaders.RequestContextCorrelationSourceKey, appId); } } } catch (Exception ex) { AppMapCorrelationEventSource.Log.SetCrossComponentCorrelationHeaderFailed(ex.ToInvariantString()); } // Add the root ID var rootId = telemetry.Context.Operation.Id; if (!string.IsNullOrEmpty(rootId) && webRequest.Headers[RequestResponseHeaders.StandardRootIdHeader] == null) { webRequest.Headers.Add(RequestResponseHeaders.StandardRootIdHeader, rootId); } // Add the parent ID var parentId = telemetry.Id; if (!string.IsNullOrEmpty(parentId)) { if (webRequest.Headers[RequestResponseHeaders.StandardParentIdHeader] == null) { webRequest.Headers.Add(RequestResponseHeaders.StandardParentIdHeader, parentId); } } // ApplicationInsights only need to inject Request-Id and Correlation-Context headers // for profiler instrumentation, in case of Http Desktop DiagnosticSourceListener // they are injected in DiagnosticSource (with the System.Net.Http.Desktop.HttpRequestOut.Start event) if (injectCorrelationHeaders) { if (webRequest.Headers[RequestResponseHeaders.RequestIdHeader] == null) { webRequest.Headers.Add(RequestResponseHeaders.RequestIdHeader, telemetry.Id); } if (webRequest.Headers[RequestResponseHeaders.CorrelationContextHeader] == null) { var currentActivity = Activity.Current; if (currentActivity != null && currentActivity.Baggage.Any()) { webRequest.Headers.SetHeaderFromNameValueCollection(RequestResponseHeaders.CorrelationContextHeader, currentActivity.Baggage); } } } } } catch (Exception exception) { DependencyCollectorEventSource.Log.CallbackError(thisObj == null ? 0 : thisObj.GetHashCode(), "OnBeginHttp", exception); } return(null); }