in WEB/Src/DependencyCollector/DependencyCollector/Implementation/HttpProcessing.cs [82:264]
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(OperationDetailConstants.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;
}