13

Stiamo utilizzando Owin su Azure per un servizio REST e dobbiamo segnalare direttamente a Application Insights. Vogliamo registrare eccezioni e richieste. In questo momento abbiamo questo:Come collegare le eccezioni alle richieste in Application Insights su 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); 
    } 
} 

sono registrati alla nostra applicazione in questo modo:

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

Questo funziona, tranne le eccezioni e le richieste non sono collegati. Entrambe vengono registrate, ma quando si fa clic su una richiesta non riuscita si dice "Non sono state trovate eccezioni correlate". Al contrario, quando si aprono le proprietà di un'eccezione, è possibile leggere "Richieste interessate da questa eccezione: 0". Qual è il modo corretto per farlo?

risposta

7

Application Insights collega eccezioni e richieste confrontando ExceptionTelemetry.Context.Operation.Id e RequestTelemetry.Id.

Non ho un codice di esempio per OWIN, tuttavia lo ASP.NET 5 package di Application Insights SDK ha componenti middleware simili per il tracciamento di eccezioni e richieste. Spero che tu possa usare queste informazioni per costruire una soluzione per OWIN.

Creiamo un'istanza RequestTelemetry e la memorizziamo nell'ambiente di elaborazione della richiesta prima di richiamare il componente del middleware successivo che esegue l'elaborazione della richiesta effettiva. In ASP.NET 5, registriamo RequestTelemetry come servizio con scope di richiesta. Con OWIN, immagino che il tuo componente middleware lo crei e lo memorizzi nel dizionario environment.

Abbiamo inoltre un ITelemetryInitializer, chiamato OperationIdTelemetryInitializer, che imposta la ITelemetry.Context.Operation.Id con il RequestTelemetry.Id estratta dall'ambiente. Questo inizializzatore deve essere aggiunto allo TelemetryConfiguration utilizzato per creare le istanze TelemetryClient nell'applicazione. TelemetryConfiguration.Active è utilizzato di default.

+0

"OperationIdTelemetryInitializer, che imposta ITelemetry.Context.Operation.Id con RequestTelemetry.Id estratto dall'ambiente" hai un'idea di come farlo in OWIN?L'implementazione di AspNet alla fine fa 'httpContextAccessor.HttpContext.RequestServices.GetService ()'. Come può accedere ad un ambito, contesto locale da un singleton globale? Come può supportare richieste asincrone simultanee? – trethaller

7

Quello che ho finito per fare-:

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

per il mio cliente attuale, non siamo ancora OWIN-ed up.

Ho registrato un DelegatingHandler con WebAPI che attacca la richiesta corrente nel SynchronizationContext del thread tramite CallContext.LogicalSetData e lo rimuove dopo che la richiesta è stata completata.

Nel mio sistema di registrazione esistente, che doveva essere l'ammodernamento dei veicoli con la roba applicazione Insights, ho poi afferro la richiesta dal thread via CallContext.LogicalSetData e impostare su come ottenere il HttpContext che si trova nelle proprietà delle richieste dal quadro, quindi dallo HttpContext.Items, ottengo l'istanza RequestTelemetry.

In definitiva, tutto ciò è necessario perché non riesco ad accedere alla richiesta o all'azione o altro dal contenitore IoC che sta riavviando i servizi.

Alla fine potremmo riscrivere una parte di questo per permettere una migliore creazione e fluente di un oggetto di stile OperationContext o InstrumentationContext giù pila e sbarazzarsi del conduttore e CallContext divertente attività.

Problemi correlati