13

Wir verwenden Owin auf Azure für einen REST-Service und müssen Application Insights direkt melden. Wir möchten Ausnahmen und Anforderungen protokollieren. Im Moment haben wir diese:Wie Verknüpfen von Ausnahmen zu Anforderungen in Application Insights auf Azure?

using AppFunc = Func<IDictionary<string, object>, Task>; 
public class InsightsReportMiddleware 
{ 

    readonly AppFunc next; 
    readonly TelemetryClient telemetryClient; 

    public InsightsReportMiddleware(AppFunc next, TelemetryClient telemetryClient) 
    { 
     if (next == null) 
     { 
      throw new ArgumentNullException("next"); 
     } 

     this.telemetryClient = telemetryClient; 
     this.next = next; 
    } 

    public async Task Invoke(IDictionary<string, object> environment) 
    { 
     var sw = new Stopwatch(); 
     sw.Start(); 

     await next(environment); 
     sw.Stop(); 

     var ctx = new OwinContext(environment); 
     var rt = new RequestTelemetry(
      name: ctx.Request.Path.ToString(), 
      timestamp: DateTimeOffset.Now, 
      duration: sw.Elapsed, 
      responseCode: ctx.Response.StatusCode.ToString(), 
      success: 200 == ctx.Response.StatusCode 
      ); 

     rt.Url = ctx.Request.Uri; 
     rt.HttpMethod = ctx.Request.Method; 
     telemetryClient.TrackRequest(rt); 
    } 
} 


public class InsightsExceptionLogger : ExceptionLogger 
{ 
    readonly TelemetryClient telemetryClient; 

    public InsightsExceptionLogger(TelemetryClient telemetryClient) 
    { 
     this.telemetryClient = telemetryClient;    
    } 

    public override Task LogAsync(ExceptionLoggerContext context, System.Threading.CancellationToken cancellationToken) 
    { 
     telemetryClient.TrackException(context.Exception); 
     return Task.FromResult<object>(null); 
    } 

    public override void Log(ExceptionLoggerContext context) 
    { 
     telemetryClient.TrackException(context.Exception); 
    } 
} 

Sie registriert sind, auf unsere Anwendung wie folgt:

static void ConfigureInsights(IAppBuilder app, HttpConfiguration config) 
{ 
    var rtClient = new TelemetryClient(); 
    app.Use<InsightsReportMiddleware>(rtClient); 
    config.Services.Add(typeof (IExceptionLogger), new InsightsExceptionLogger(rtClient)); 
} 

Dies funktioniert, außer Ausnahmen und Anfragen sind nicht verbunden. Beide werden protokolliert, aber wenn auf eine fehlgeschlagene Anfrage geklickt wird, wird "Keine verwandten Ausnahmen gefunden" angezeigt. Umgekehrt können wir beim Öffnen einer Ausnahmeeigenschaft "Anforderungen, die von dieser Ausnahme betroffen sind: 0" lesen. Was ist der richtige Weg, das zu tun?

Antwort

7

Application Insights verknüpft Ausnahmen und Anforderungen durch Vergleichen von ExceptionTelemetry.Context.Operation.Id und RequestTelemetry.Id.

Ich habe kein Codebeispiel für OWIN, aber das ASP.NET 5 package des Application Insights SDK hat ähnliche Middlewarekomponenten zum Verfolgen von Ausnahmen und Anforderungen. Ich hoffe, Sie können diese Informationen verwenden, um eine Lösung für OWIN zu erstellen.

Wir erstellen eine RequestTelemetry Instanz und speichern sie in der Anforderungsverarbeitungsumgebung, bevor die nächste Middlewarekomponente aufgerufen wird, die die eigentliche Anforderungsverarbeitung ausführt. In ASP.NET 5 registrieren wir RequestTelemetry als anforderungsabhängigen Dienst. Mit OWIN würde ich mir vorstellen, dass Ihre Middleware-Komponente es erstellen und im environment Wörterbuch speichern würde.

Wir haben auch eine ITelemetryInitializer, genannt OperationIdTelemetryInitializer, die die ITelemetry.Context.Operation.Id mit der RequestTelemetry.Id extrahiert aus der Umgebung setzt. Dieser Initialisierer muss zu TelemetryConfiguration hinzugefügt werden, um die TelemetryClient Instanzen in Ihrer Anwendung zu erstellen. TelemetryConfiguration.Active wird standardmäßig verwendet.

+0

"OperationIdTelemetryInitializer, die die ITelemetry.Context.Operation.Id mit der RequestTelemetry.Id aus der Umgebung extrahiert" haben Sie eine Idee, wie in OWIN?Die AspNet-Implementierung führt schließlich 'httpContextAccessor.HttpContext.RequestServices.GetService ()' durch. Wie kann es von einem globalen Singleton auf einen lokalen Bereichskontext zugreifen? Wie kann dies gleichzeitige asynchrone Anforderungen unterstützen? – trethaller

7

Was ich am Ende-up zu tun:

using AppFunc = Func<IDictionary<string, object>, Task>; 
public class InsightsReportMiddleware 
{ 
    readonly AppFunc next; 
    readonly TelemetryClient telemetryClient; 

    public InsightsReportMiddleware(AppFunc next, TelemetryClient telemetryClient) 
    { 
     if (next == null) 
     { 
      throw new ArgumentNullException("next"); 
     } 

     this.telemetryClient = telemetryClient; 
     this.next = next; 
    } 

    public async Task Invoke(IDictionary<string, object> environment) 
    { 
     var ctx = new OwinContext(environment); 
     var rt = new RequestTelemetry() 
     { 
      Url = ctx.Request.Uri, 
      HttpMethod = ctx.Request.Method, 
      Name = ctx.Request.Path.ToString(), 
      Timestamp = DateTimeOffset.Now 
     }; 
     environment.Add("requestTelemetry", rt); 

     var sw = new Stopwatch(); 
     sw.Start(); 
     await next(environment); 
     sw.Stop(); 

     rt.ResponseCode = ctx.Response.StatusCode.ToString(); 
     rt.Success = ctx.Response.StatusCode < 400; 
     rt.Duration = sw.Elapsed; 
     telemetryClient.TrackRequest(rt); 
    } 
} 

public class InsightsExceptionLogger : ExceptionLogger 
{ 
    readonly TelemetryClient telemetryClient; 

    public InsightsExceptionLogger(TelemetryClient telemetryClient) 
    { 
     this.telemetryClient = telemetryClient;    
    } 

    public override Task LogAsync(ExceptionLoggerContext context, System.Threading.CancellationToken cancellationToken) 
    { 
     var owinContext = context.Request.GetOwinEnvironment(); 
     ExceptionTelemetry exceptionTelemetry = null; 
     if (owinContext != null) 
     { 
      object obj; 
      if (owinContext.TryGetValue("requestTelemetry", out obj)) 
      { 
       var requestTelemetry = obj as RequestTelemetry; 
       exceptionTelemetry = new ExceptionTelemetry(context.Exception) 
       { 
        Timestamp = DateTimeOffset.Now 
       }; 
       exceptionTelemetry.Context.Operation.Id = requestTelemetry.Id; 
      } 
     } 

     if (exceptionTelemetry != null) 
     { 
      telemetryClient.TrackException(exceptionTelemetry); 
     } 
     else 
     { 
      telemetryClient.TrackException(context.Exception);     
     } 

     return Task.FromResult<object>(null); 
    } 

    public override void Log(ExceptionLoggerContext context) 
    { 
     telemetryClient.TrackException(context.Exception); 
    } 
} 
1

Für mein aktuelles Client, sind wir noch nicht OWIN-ed up.

Ich registrierte eine mit WebAPI, die die aktuelle Anforderung in SynchronizationContext des Threads über CallContext.LogicalSetData hält und entfernt, nachdem die Anforderung abgeschlossen ist.

In meinem bestehenden Logging-System, das mit dem Application Insights Sachen ausgestattet retro sein musste, habe ich dann die Anfrage von dem Faden greifen über CallContext.LogicalSetData zu machen und eine HttpContext bekommen, die in die Anfrage Eigenschaften von Rahmen platziert wird, dann von der HttpContext.Items, bekomme ich die RequestTelemetry Instanz.

Letztendlich ist dies alles erforderlich, weil ich keinen Zugriff auf die Anfrage oder Aktion oder irgendetwas aus dem IoC-Container bekommen kann, der die Dienste neu erstellt.

Schließlich könnten wir einige diese umschreiben verbesserte Schöpfung zu ermöglichen und Fließen eines OperationContext oder InstrumentationContext Stil Objekt nach unten dem Stapel und werden den Handler und CallContext lustigen Geschäft loszuwerden.

Verwandte Themen