/// <summary> /// OnAsyncMethodEnd callback /// </summary> /// <typeparam name="TTarget">Type of the target</typeparam> /// <typeparam name="TResponse">Type of the response, in an async scenario will be T of Task of T</typeparam> /// <param name="instance">Instance value, aka `this` of the instrumented method.</param> /// <param name="responseMessage">HttpResponse message instance</param> /// <param name="exception">Exception instance in case the original code threw an exception.</param> /// <param name="state">Calltarget state value</param> /// <returns>A response value, in an async scenario will be T of Task of T</returns> public static TResponse OnAsyncMethodEnd <TTarget, TResponse>(TTarget instance, TResponse responseMessage, Exception exception, CallTargetState state) { var scope = state.Scope; if (scope is null) { return(responseMessage); } var controllerContext = (IHttpControllerContext)state.State; // some fields aren't set till after execution, so populate anything missing AspNetWebApi2Integration.UpdateSpan(controllerContext, scope.Span, (AspNetTags)scope.Span.Tags, Enumerable.Empty <KeyValuePair <string, string> >()); if (exception != null) { scope.Span.SetException(exception); // We don't have access to the final status code at this point // Ask the HttpContext to call us back to that we can get it var httpContext = HttpContext.Current; if (httpContext != null) { // We don't know how long it'll take for ASP.NET to invoke the callback, // so we store the real finish time var now = scope.Span.Context.TraceContext.UtcNow; httpContext.AddOnRequestCompleted(h => OnRequestCompleted(h, scope, now)); } else { // Looks like we won't be able to get the final status code scope.Dispose(); } } else { var httpContext = HttpContext.Current; if (httpContext != null && HttpRuntime.UsingIntegratedPipeline) { scope.Span.SetHeaderTags <IHeadersCollection>(httpContext.Response.Headers.Wrap(), Tracer.Instance.Settings.HeaderTags, defaultTagPrefix: SpanContextPropagator.HttpResponseHeadersTagPrefix); } scope.Span.SetHttpStatusCode(responseMessage.DuckCast <HttpResponseMessageStruct>().StatusCode, isServer: true); scope.Dispose(); } return(responseMessage); }
/// <summary> /// OnMethodBegin callback /// </summary> /// <typeparam name="TTarget">Type of the target</typeparam> /// <typeparam name="TController">Type of the controller context</typeparam> /// <param name="instance">Instance value, aka `this` of the instrumented method.</param> /// <param name="controllerContext">The context of the controller</param> /// <param name="cancellationToken">The cancellation token</param> /// <returns>Calltarget state value</returns> public static CallTargetState OnMethodBegin <TTarget, TController>(TTarget instance, TController controllerContext, CancellationToken cancellationToken) where TController : IHttpControllerContext { // Make sure to box the controllerContext proxy only once var boxedControllerContext = (IHttpControllerContext)controllerContext; var scope = AspNetWebApi2Integration.CreateScope(boxedControllerContext, out _); if (scope != null) { return(new CallTargetState(scope, boxedControllerContext)); } return(CallTargetState.GetDefault()); }