From de265dcb1f4808ae64c27b9886829117182bd35f Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Wed, 26 Apr 2023 20:11:34 +0200 Subject: [PATCH] Add logging to IHttpModule.EndRequest if transaction is null (#2060) --- .../ElasticApmModule.cs | 40 +++++++++++++------ ...ontextCurrentExecutionSegmentsContainer.cs | 2 +- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/Elastic.Apm.AspNetFullFramework/ElasticApmModule.cs b/src/Elastic.Apm.AspNetFullFramework/ElasticApmModule.cs index 2f360eb02..127c6ebd7 100644 --- a/src/Elastic.Apm.AspNetFullFramework/ElasticApmModule.cs +++ b/src/Elastic.Apm.AspNetFullFramework/ElasticApmModule.cs @@ -36,7 +36,10 @@ public class ElasticApmModule : IHttpModule private readonly string _dbgInstanceName; private HttpApplication _application; private IApmLogger _logger; - private readonly Lazy _httpRouteDataInterfaceType = new Lazy(() => Type.GetType("System.Web.Http.Routing.IHttpRouteData,System.Web.Http")); + + private readonly Lazy _httpRouteDataInterfaceType = + new Lazy(() => Type.GetType("System.Web.Http.Routing.IHttpRouteData,System.Web.Http")); + private Func _routeDataTemplateGetter; private Func _routePrecedenceGetter; @@ -256,7 +259,7 @@ private static Dictionary ConvertHeaders(NameValueCollection hea { var value = headers.Get(key); if (value != null) - convertedHeaders.Add(key,value); + convertedHeaders.Add(key, value); } return convertedHeaders; } @@ -279,17 +282,30 @@ private void ProcessError(object sender) private void ProcessEndRequest(object sender) { - var transaction = Agent.Instance.Tracer.CurrentTransaction; - if (transaction is null) return; - var application = (HttpApplication)sender; var context = application.Context; + var request = context.Request; + var transaction = Agent.Instance.Tracer.CurrentTransaction; + + if (transaction is null) + { + // We expect transaction to be null if `TransactionIgnoreUrls` matches + if (WildcardMatcher.IsAnyMatch(Agent.Instance.ConfigurationReader.TransactionIgnoreUrls, request.Unvalidated.Path)) + return; + + var hasHttpContext = HttpContext.Current?.Items[HttpContextCurrentExecutionSegmentsContainer.CurrentTransactionKey] is not null; + _logger.Warning() + ?.Log( + $"{nameof(ITracer.CurrentTransaction)} is null in {nameof(ProcessEndRequest)}. HttpContext for transaction: {hasHttpContext}" + ); + return; + } + var response = context.Response; // update the transaction name based on route values, if applicable if (transaction is Transaction t && !t.HasCustomName) { - var request = application.Request; var values = request.RequestContext?.RouteData?.Values; if (values?.Count > 0) { @@ -335,7 +351,9 @@ private void ProcessEndRequest(object sender) var precedence = _routePrecedenceGetter(subRoute); if (precedence < minPrecedence) { - _logger?.Trace()?.Log($"Calculating transaction name from web api attribute routing (route precedence: {precedence})"); + _logger?.Trace() + ?.Log( + $"Calculating transaction name from web api attribute routing (route precedence: {precedence})"); minPrecedence = precedence; name = _routeDataTemplateGetter(subRoute); } @@ -367,8 +385,8 @@ private void ProcessEndRequest(object sender) var realTransaction = transaction as Transaction; realTransaction?.SetOutcome(response.StatusCode >= 500 - ? Outcome.Failure - : Outcome.Success); + ? Outcome.Failure + : Outcome.Success); // Try and update transaction name with SOAP action if applicable. if (realTransaction == null || !realTransaction.HasCustomName) @@ -391,9 +409,7 @@ private void ProcessEndRequest(object sender) private static void FillSampledTransactionContextResponse(HttpResponse response, ITransaction transaction) => transaction.Context.Response = new Response { - Finished = true, - StatusCode = response.StatusCode, - Headers = _isCaptureHeadersEnabled ? ConvertHeaders(response.Headers) : null + Finished = true, StatusCode = response.StatusCode, Headers = _isCaptureHeadersEnabled ? ConvertHeaders(response.Headers) : null }; private void FillSampledTransactionContextUser(HttpContext context, ITransaction transaction) diff --git a/src/Elastic.Apm.AspNetFullFramework/HttpContextCurrentExecutionSegmentsContainer.cs b/src/Elastic.Apm.AspNetFullFramework/HttpContextCurrentExecutionSegmentsContainer.cs index 494d5ccdf..7a843c8db 100644 --- a/src/Elastic.Apm.AspNetFullFramework/HttpContextCurrentExecutionSegmentsContainer.cs +++ b/src/Elastic.Apm.AspNetFullFramework/HttpContextCurrentExecutionSegmentsContainer.cs @@ -20,7 +20,7 @@ internal sealed class HttpContextCurrentExecutionSegmentsContainer : ICurrentExe private readonly AsyncLocal _currentTransaction = new AsyncLocal(); private const string CurrentSpanKey = "Elastic.Apm.Agent.CurrentSpan"; - private const string CurrentTransactionKey = "Elastic.Apm.Agent.CurrentTransaction"; + internal const string CurrentTransactionKey = "Elastic.Apm.Agent.CurrentTransaction"; public ISpan CurrentSpan {