/// <summary> /// Common helper for all End Callbacks. /// </summary> /// <param name="request">The HttpWebRequest instance.</param> /// <param name="response">The HttpWebResponse instance.</param> internal void OnEndResponse(object request, object response) { try { if (this.TryGetPendingTelemetry(request, out DependencyTelemetry telemetry)) { if (response is HttpWebResponse responseObj) { int statusCode = -1; try { statusCode = (int)responseObj.StatusCode; this.SetTarget(telemetry, responseObj.Headers); // Set the operation details for the response telemetry.SetOperationDetail(RemoteDependencyConstants.HttpResponseOperationDetailName, responseObj); } catch (ObjectDisposedException) { // ObjectDisposedException is expected here in the following sequence: httpWebRequest.GetResponse().Dispose() -> httpWebRequest.GetResponse() // on the second call to GetResponse() we cannot determine the statusCode. } SetStatusCode(telemetry, statusCode); } ClientServerDependencyTracker.EndTracking(this.telemetryClient, telemetry); } } catch (Exception ex) { DependencyCollectorEventSource.Log.CallbackError(request == null ? 0 : request.GetHashCode(), "OnEndResponse", ex); } }
/// <summary> /// Common helper for all End Callbacks. /// </summary> /// <param name="request">WebRequest object.</param> /// <param name="statusCode">HttpStatusCode from response.</param> /// <param name="responseHeaders">Response headers.</param> internal void OnEndResponse(object request, object statusCode, object responseHeaders) { try { if (this.TryGetPendingTelemetry(request, out DependencyTelemetry telemetry)) { if (statusCode != null) { SetStatusCode(telemetry, (int)statusCode); } this.SetTarget(telemetry, (WebHeaderCollection)responseHeaders); if (this.injectW3CHeaders && request is HttpWebRequest httpRequest) { // this.SetLegacyId(telemetry, httpRequest.Headers); } telemetry.SetOperationDetail(RemoteDependencyConstants.HttpResponseHeadersOperationDetailName, responseHeaders); ClientServerDependencyTracker.EndTracking(this.telemetryClient, telemetry); } } catch (Exception ex) { DependencyCollectorEventSource.Log.CallbackError(request == null ? 0 : request.GetHashCode(), "OnEndResponse", ex); } }
public void RddTestHttpProcessingFrameworkNoDuplication() { Stopwatch stopwatch = Stopwatch.StartNew(); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.testUrl); var id = ClientServerDependencyTracker.GetIdForRequestObject(request); var returnObject = TestUtils.GenerateHttpWebResponse(HttpStatusCode.BadRequest); this.httpProcessingFramework.OnRequestSend(request); this.httpProcessingFramework.OnRequestSend(request); this.httpProcessingFramework.OnBeginHttpCallback(id, this.testUrl.OriginalString); this.httpProcessingFramework.OnRequestSend(request); this.httpProcessingFramework.OnRequestSend(request); this.httpProcessingFramework.OnBeginHttpCallback(id, this.testUrl.OriginalString); this.httpProcessingFramework.OnBeginHttpCallback(id, this.testUrl.OriginalString); this.httpProcessingFramework.OnRequestSend(request); Thread.Sleep(this.sleepTimeMsecBetweenBeginAndEnd); Assert.AreEqual(0, this.sendItems.Count, "No telemetry item should be processed without calling End"); this.httpProcessingFramework.OnResponseReceive(request, returnObject); this.httpProcessingFramework.OnEndHttpCallback(id, false, false, 409); this.httpProcessingFramework.OnEndHttpCallback(id, true, false, 304); this.httpProcessingFramework.OnResponseReceive(request, returnObject); this.httpProcessingFramework.OnEndHttpCallback(id, true, false, 200); this.httpProcessingFramework.OnResponseReceive(request, returnObject); this.httpProcessingFramework.OnEndHttpCallback(id, false, false, 400); stopwatch.Stop(); Assert.AreEqual(1, this.sendItems.Count, "Only one telemetry item should be sent"); ValidateTelemetryPacketForOnRequestSend(this.sendItems[0] as DependencyTelemetry, this.testUrl, RemoteDependencyConstants.HTTP, false, stopwatch.Elapsed.TotalMilliseconds, "409"); }
/// <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); } }
/// <summary> /// On end callback from Framework event source. /// </summary> /// <param name="id">The id.</param> /// <param name="success">The success to indicate if the dependency call completed successfully or not.</param> /// <param name="synchronous">The synchronous flag to indicate if the dependency call was synchronous or not.</param> /// <param name="statusCode">The HTTP status code of the response.</param> public void OnEndHttpCallback(long id, bool?success, bool synchronous, int?statusCode) { DependencyCollectorEventSource.Log.EndCallbackCalled(id); var telemetryTuple = this.TelemetryTable.Get(id); if (telemetryTuple == null) { DependencyCollectorEventSource.Log.EndCallbackWithNoBegin(id); return; } if (!telemetryTuple.Item2) { this.TelemetryTable.Remove(id); DependencyTelemetry telemetry = telemetryTuple.Item1; telemetry.DependencyKind = RemoteDependencyKind.Http.ToString(); if (!statusCode.HasValue) { statusCode = -1; } telemetry.ResultCode = statusCode.Value > 0 ? statusCode.Value.ToString(CultureInfo.InvariantCulture) : string.Empty; // We calculate success on the base of http code and do not use the 'success' method argument // because framework returns true all the time if you use HttpClient to create a request // statusCode == -1 if there is no Response telemetry.Success = (statusCode > 0) && (statusCode < 400); ClientServerDependencyTracker.EndTracking(this.telemetryClient, telemetry); } }
public void BeginWebTrackingReturnsOperationItemWithTelemetryItem() { var telemetry = ClientServerDependencyTracker.BeginTracking(this.telemetryClient); Assert.AreEqual(telemetry.StartTime, telemetry.StartTime); Assert.AreEqual(telemetry.Timestamp, telemetry.Timestamp); }
/// <summary> /// This method gets called once for each event from the Http DiagnosticSource. /// </summary> /// <param name="value">The pair containing the event name, and an object representing the payload. The payload /// is essentially a dynamic object that contain different properties depending on the event.</param> public void OnNext(KeyValuePair <string, object> value) { try { switch (value.Key) { case "System.Net.Http.Desktop.HttpRequestOut.Start": { var request = (HttpWebRequest)this.requestFetcherRequestEvent.Fetch(value.Value); DependencyCollectorEventSource.Log.HttpDesktopBeginCallbackCalled(ClientServerDependencyTracker.GetIdForRequestObject(request), request.RequestUri.ToString()); // With this event, DiagnosticSource injects headers himself (after the event) // ApplicationInsights must not do this this.httpDesktopProcessing.OnBegin(request, false); break; } case "System.Net.Http.Desktop.HttpRequestOut.Stop": { // request is never null var request = this.requestFetcherResponseEvent.Fetch(value.Value); DependencyCollectorEventSource.Log.HttpDesktopEndCallbackCalled(ClientServerDependencyTracker.GetIdForRequestObject(request)); var response = this.responseFetcher.Fetch(value.Value); this.httpDesktopProcessing.OnEndResponse(request, response); break; } case "System.Net.Http.Desktop.HttpRequestOut.Ex.Stop": { // request is never null var request = this.requestFetcherResponseExEvent.Fetch(value.Value); DependencyCollectorEventSource.Log.HttpDesktopEndCallbackCalled(ClientServerDependencyTracker.GetIdForRequestObject(request)); object statusCode = this.responseExStatusFetcher.Fetch(value.Value); object headers = this.responseExHeadersFetcher.Fetch(value.Value); this.httpDesktopProcessing.OnEndResponse(request, statusCode, headers); break; } case "System.Net.Http.InitializationFailed": { DependencyTableStore.IsDesktopHttpDiagnosticSourceActivated = false; Exception ex = (Exception)value.Value.GetType().GetProperty("Exception")?.GetValue(value.Value); DependencyCollectorEventSource.Log.HttpHandlerDiagnosticListenerFailedToInitialize(ex?.ToInvariantString()); break; } default: { DependencyCollectorEventSource.Log.NotExpectedCallback(value.GetHashCode(), value.Key, "unknown key"); break; } } } catch (Exception exc) { DependencyCollectorEventSource.Log.CallbackError(0, "OnNext", exc); } }
public void AddTupleForWebDependenciesThrowsExceptionIfExists() { var telemetry = new DependencyTelemetry(); var falseTelemetry = new DependencyTelemetry(); ClientServerDependencyTracker.AddTupleForWebDependencies(this.webRequest, falseTelemetry, false); ClientServerDependencyTracker.AddTupleForWebDependencies(this.webRequest, telemetry, false); }
/// <summary> /// Common helper for all End Callbacks. /// </summary> /// <param name="exception">The exception object if any.</param> /// <param name="thisObj">This object.</param> /// <param name="returnValue">Return value of the function if any.</param> private void OnEnd(object exception, object thisObj, object returnValue) { try { if (thisObj == null) { DependencyCollectorEventSource.Log.NotExpectedCallback(0, "OnBeginHttp", "thisObj == null"); return; } DependencyCollectorEventSource.Log.EndCallbackCalled(thisObj.GetHashCode()); Tuple <DependencyTelemetry, bool> telemetryTuple = this.TelemetryTable.Get(thisObj); if (telemetryTuple == null) { DependencyCollectorEventSource.Log.EndCallbackWithNoBegin(thisObj.GetHashCode()); return; } if (telemetryTuple.Item1 == null) { DependencyCollectorEventSource.Log.EndCallbackWithNoBegin(thisObj.GetHashCode()); return; } if (!telemetryTuple.Item2) { this.TelemetryTable.Remove(thisObj); DependencyTelemetry telemetry = telemetryTuple.Item1; var responseObj = returnValue as HttpWebResponse; int statusCode = -1; if (responseObj != null) { try { statusCode = (int)responseObj.StatusCode; } catch (ObjectDisposedException) { // ObjectDisposedException is expected here in the following sequence: httpWebRequest.GetResponse().Dispose() -> httpWebRequest.GetResponse() // on the second call to GetResponse() we cannot determine the statusCode. } } telemetry.ResultCode = statusCode > 0 ? statusCode.ToString(CultureInfo.InvariantCulture) : string.Empty; telemetry.Success = (statusCode > 0) && (statusCode < 400); ClientServerDependencyTracker.EndTracking(this.telemetryClient, telemetry); } } catch (Exception ex) { DependencyCollectorEventSource.Log.CallbackError(thisObj == null ? 0 : thisObj.GetHashCode(), "OnBeginHttp", ex); } }
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> /// Common helper for all End Callbacks. /// </summary> /// <param name="exceptionObj">The exception object if any.</param> /// <param name="thisObj">This object.</param> /// <param name="sendTelemetryItem">True if telemetry item should be sent, otherwise it only stops the telemetry item.</param> private void OnEndInternal(object exceptionObj, object thisObj, bool sendTelemetryItem = true) { if (thisObj == null) { DependencyCollectorEventSource.Log.NotExpectedCallback(0, "OnEndSql", "thisObj == null"); return; } DependencyCollectorEventSource.Log.EndCallbackCalled(thisObj.GetHashCode().ToString(CultureInfo.InvariantCulture)); DependencyTelemetry telemetry = null; Tuple <DependencyTelemetry, bool> telemetryTuple = null; bool isCustomGenerated = false; telemetryTuple = this.TelemetryTable.Get(thisObj); if (telemetryTuple != null) { telemetry = telemetryTuple.Item1; isCustomGenerated = telemetryTuple.Item2; } if (telemetry == null) { DependencyCollectorEventSource.Log.EndCallbackWithNoBegin(thisObj.GetHashCode().ToString(CultureInfo.InvariantCulture)); return; } if (!isCustomGenerated) { this.TelemetryTable.Remove(thisObj); if (sendTelemetryItem) { var exception = exceptionObj as Exception; if (exception != null) { telemetry.Success = false; telemetry.Properties.Add("ErrorMessage", exception.Message); var sqlEx = exception as SqlException; telemetry.ResultCode = sqlEx != null?sqlEx.Number.ToString(CultureInfo.InvariantCulture) : "0"; } else { telemetry.Success = true; } DependencyCollectorEventSource.Log.AutoTrackingDependencyItem(telemetry.Name); ClientServerDependencyTracker.EndTracking(this.telemetryClient, telemetry); } else { DependencyCollectorEventSource.Log.EndOperationNoTracking(telemetry.Name); ClientServerDependencyTracker.EndOperation(telemetry); } } }
/// <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); } }
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> /// <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); }
public void AddTupleForSqlDependenciesAddsTelemteryTupleToTheTable() { var telemetry = new DependencyTelemetry(); ClientServerDependencyTracker.AddTupleForSqlDependencies(this.sqlRequest, telemetry, false); var tuple = ClientServerDependencyTracker.GetTupleForSqlDependencies(this.sqlRequest); Assert.IsNotNull(tuple); Assert.IsNotNull(tuple.Item1); Assert.AreEqual(telemetry, tuple.Item1); }
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); }
/// <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 FrameworkHttpProcessingIsDisabledWhenHttpDesktopDiagSourceIsEnabled() { DependencyTableStore.IsDesktopHttpDiagnosticSourceActivated = true; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.testUrl); var id = ClientServerDependencyTracker.GetIdForRequestObject(request); this.httpProcessingFramework.OnBeginHttpCallback(id, this.testUrl.ToString()); this.httpProcessingFramework.OnEndHttpCallback(id, null, false, 200); Assert.AreEqual(0, this.sendItems.Count, "No telemetry item should be sent"); }
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> /// 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 RddTestHttpProcessingFrameworkOnEndHttpCallbackInvalidId() { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.testUrl); var id1 = ClientServerDependencyTracker.GetIdForRequestObject(request); var id2 = 200; this.httpProcessingFramework.OnBeginHttpCallback(id1, this.testUrl.ToString()); Thread.Sleep(this.sleepTimeMsecBetweenBeginAndEnd); Assert.AreEqual(0, this.sendItems.Count, "No telemetry item should be processed without calling End"); this.httpProcessingFramework.OnEndHttpCallback(id2, true, true, null); Assert.AreEqual(0, this.sendItems.Count, "No telemetry item should be processed as invalid id is passed"); }
/// <summary> /// Common helper for all End Callbacks. /// </summary> /// <param name="exception">The exception object if any.</param> /// <param name="request">HttpWebRequest instance.</param> internal void OnEndException(object exception, object request) { try { if (this.TryGetPendingTelemetry(request, out DependencyTelemetry telemetry)) { var webException = exception as WebException; if (webException?.Response is HttpWebResponse responseObj) { int statusCode = -1; try { statusCode = (int)responseObj.StatusCode; this.SetTarget(telemetry, responseObj.Headers); if (this.injectW3CHeaders && request is HttpWebRequest httpRequest) { // this.SetLegacyId(telemetry, httpRequest.Headers); } // Set the operation details for the response telemetry.SetOperationDetail(RemoteDependencyConstants.HttpResponseOperationDetailName, responseObj); } catch (ObjectDisposedException) { // ObjectDisposedException is expected here in the following sequence: httpWebRequest.GetResponse().Dispose() -> httpWebRequest.GetResponse() // on the second call to GetResponse() we cannot determine the statusCode. } SetStatusCode(telemetry, statusCode); } else if (exception != null) { if (webException != null) { telemetry.ResultCode = webException.Status.ToString(); } telemetry.Success = false; } ClientServerDependencyTracker.EndTracking(this.telemetryClient, telemetry); } } catch (Exception ex) { DependencyCollectorEventSource.Log.CallbackError(request == null ? 0 : request.GetHashCode(), "OnEndException", ex); } }
public void HttpProcessorSetsTargetForNonStandardPort() { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.testUrlNonStandardPort); var id = ClientServerDependencyTracker.GetIdForRequestObject(request); this.httpProcessingFramework.OnBeginHttpCallback(id, this.testUrlNonStandardPort.ToString()); this.httpProcessingFramework.OnEndHttpCallback(id, null, false, 500); Assert.AreEqual(1, this.sendItems.Count, "Exactly one telemetry item should be sent"); DependencyTelemetry receivedItem = (DependencyTelemetry)this.sendItems[0]; string expectedTarget = this.testUrlNonStandardPort.Host + ":" + this.testUrlNonStandardPort.Port; Assert.AreEqual(expectedTarget, receivedItem.Target, "HttpProcessingFramework returned incorrect target for non standard port."); }
public void OnEndHttpCallbackSetsSuccessToTrueForLessThan400() { int statusCode = 399; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.testUrl); var id = ClientServerDependencyTracker.GetIdForRequestObject(request); this.httpProcessingFramework.OnBeginHttpCallback(id, this.testUrl.ToString()); this.httpProcessingFramework.OnEndHttpCallback(id, null, false, statusCode); Assert.AreEqual(1, this.sendItems.Count, "Only one telemetry item should be sent"); var actual = this.sendItems[0] as DependencyTelemetry; Assert.IsTrue(actual.Success.Value); }
/// <summary> /// On end callback from Framework event source. /// </summary> /// <param name="id">The id.</param> /// <param name="success">The success to indicate if the dependency call completed successfully or not.</param> /// <param name="synchronous">The synchronous flag to indicate if the dependency call was synchronous or not.</param> /// <param name="statusCode">The HTTP status code of the response.</param> public void OnEndHttpCallback(long id, bool?success, bool synchronous, int?statusCode) { DependencyCollectorEventSource.Log.EndCallbackCalled(id.ToString(CultureInfo.InvariantCulture)); var telemetryTuple = this.TelemetryTable.Get(id); if (telemetryTuple == null) { DependencyCollectorEventSource.Log.EndCallbackWithNoBegin(id.ToString(CultureInfo.InvariantCulture)); return; } if (!telemetryTuple.Item2) { DependencyTelemetry telemetry = telemetryTuple.Item1; if (statusCode.HasValue) { if (DependencyTableStore.IsDesktopHttpDiagnosticSourceActivated && statusCode.Value > 0) { // HttpDesktopDiagnosticSourceListener do not get notifications about exceptions during requests processing. // We will report them here, and we will let HttpDesktopDiagnosticSourceListener track the dependency for successful response DependencyCollectorEventSource.Log.SkipTrackingTelemetryItemWithEventSource(id); return; } // We calculate success on the base of http code and do not use the 'success' method argument // because framework returns true all the time if you use HttpClient to create a request // statusCode == -1 if there is no Response telemetry.Success = (statusCode > 0) && (statusCode < 400); telemetry.ResultCode = statusCode.Value > 0 ? statusCode.Value.ToString(CultureInfo.InvariantCulture) : string.Empty; this.TelemetryTable.Remove(id); ClientServerDependencyTracker.EndTracking(this.telemetryClient, telemetry); } else { // This case is for 4.5.2 // We never collected statusCode or success before 2.1.0-beta4 // We also had duplicates if runtime is also 4.5.2 (4.6 runtime has no such problem) // So starting with 2.1.0-beta4 we are cutting support for HTTP dependencies in .NET 4.5.2. // But we will let DesktopDiagnosticSourceListener collect dependency if it is activated if (!DependencyTableStore.IsDesktopHttpDiagnosticSourceActivated) { this.TelemetryTable.Remove(id); } } } }
public void OnEndHttpCallbackSetsSuccessToFalseForNegativeStatusCode() { // -1 StatusCode is returned in case of no response int statusCode = -1; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.testUrl); var id = ClientServerDependencyTracker.GetIdForRequestObject(request); this.httpProcessingFramework.OnBeginHttpCallback(id, this.testUrl.ToString()); this.httpProcessingFramework.OnEndHttpCallback(id, null, false, statusCode); Assert.AreEqual(1, this.sendItems.Count, "Only one telemetry item should be sent"); var actual = this.sendItems[0] as DependencyTelemetry; Assert.IsFalse(actual.Success.Value); }
/// <summary> /// Common helper for all End Callbacks. /// </summary> /// <param name="context">The context.</param> /// <param name="exception">The exception object if any.</param> /// <param name="thisObj">This object.</param> /// <param name="isAsync">Whether the End is for an async invocation.</param> private void OnEnd(object context, object exception, object thisObj, bool isAsync) { try { if (thisObj == null) { DependencyCollectorEventSource.Log.NotExpectedCallback(0, "OnEndSql", "thisObj == null"); return; } DependencyCollectorEventSource.Log.EndCallbackCalled(thisObj.GetHashCode().ToString(CultureInfo.InvariantCulture)); DependencyTelemetry telemetry = null; Tuple <DependencyTelemetry, bool> telemetryTuple = null; bool isCustomGenerated = false; telemetryTuple = this.TelemetryTable.Get(thisObj); if (telemetryTuple != null) { telemetry = telemetryTuple.Item1; isCustomGenerated = telemetryTuple.Item2; } if (telemetry == null) { DependencyCollectorEventSource.Log.EndCallbackWithNoBegin(thisObj.GetHashCode().ToString(CultureInfo.InvariantCulture)); return; } if (!isCustomGenerated) { this.TelemetryTable.Remove(thisObj); telemetry.Success = exception == null; var sqlEx = exception as SqlException; if (sqlEx != null) { telemetry.ResultCode = sqlEx.Number.ToString(CultureInfo.InvariantCulture); } ClientServerDependencyTracker.EndTracking(this.telemetryClient, telemetry); } } catch (Exception ex) { DependencyCollectorEventSource.Log.CallbackError(thisObj == null ? 0 : thisObj.GetHashCode(), "OnEndSql", ex); } }
public void RddTestHttpProcessingFrameworkOnEndHttpCallback() { var request = WebRequest.Create(this.testUrl); var returnObjectPassed = TestUtils.GenerateHttpWebResponse(HttpStatusCode.OK); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); this.httpProcessingFramework.OnRequestSend(request); Thread.Sleep(this.sleepTimeMsecBetweenBeginAndEnd); Assert.AreEqual(0, this.sendItems.Count, "No telemetry item should be processed without calling End"); this.httpProcessingFramework.OnResponseReceive(request, returnObjectPassed); this.httpProcessingFramework.OnEndHttpCallback(ClientServerDependencyTracker.GetIdForRequestObject(request), true, true, 200); stopwatch.Stop(); Assert.AreEqual(1, this.sendItems.Count, "Only one telemetry item should be sent"); ValidateTelemetryPacketForOnRequestSend(this.sendItems[0] as DependencyTelemetry, this.testUrl, RemoteDependencyConstants.HTTP, true, stopwatch.Elapsed.TotalMilliseconds, "200"); }
public void RddTestHttpProcessingFrameworkStartTimeFromGetRequestStreamAsync() { Stopwatch stopwatch = Stopwatch.StartNew(); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.testUrl); var id1 = ClientServerDependencyTracker.GetIdForRequestObject(request); this.httpProcessingFramework.OnBeginHttpCallback(id1, this.testUrl.ToString()); Thread.Sleep(this.sleepTimeMsecBetweenBeginAndEnd); this.httpProcessingFramework.OnBeginHttpCallback(id1, this.testUrl.ToString()); Thread.Sleep(this.sleepTimeMsecBetweenBeginAndEnd); Assert.AreEqual(0, this.sendItems.Count, "No telemetry item should be processed without calling End"); this.httpProcessingFramework.OnEndHttpCallback(id1, true, false, 200); stopwatch.Stop(); Assert.AreEqual(1, this.sendItems.Count, "Exactly one telemetry item should be sent"); ValidateTelemetryPacketForOnBeginHttpCallback(this.sendItems[0] as DependencyTelemetry, this.testUrl, RemoteDependencyConstants.HTTP, true, stopwatch.Elapsed.TotalMilliseconds, "200"); }
private void SimulateWebRequestResponseWithAppId(string appId) { var request = WebRequest.Create(this.testUrl); Dictionary <string, string> headers = new Dictionary <string, string>(); headers.Add(RequestResponseHeaders.RequestContextHeader, this.GetCorrelationIdHeaderValue(appId)); var returnObjectPassed = TestUtils.GenerateHttpWebResponse(HttpStatusCode.OK, headers); this.httpProcessingFramework.OnBeginHttpCallback(ClientServerDependencyTracker.GetIdForRequestObject(request), this.testUrl.OriginalString); this.httpProcessingFramework.OnRequestSend(request); this.httpProcessingFramework.OnResponseReceive(request, returnObjectPassed); this.httpProcessingFramework.OnEndHttpCallback( ClientServerDependencyTracker.GetIdForRequestObject(request), true, true, (int)HttpStatusCode.OK); }