21

我们在 Azure 上将 Owin 用于 REST 服务,并且必须直接向 Application Insights 报告。我们想要记录异常和请求。现在我们有这个:

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);
    }
}

它们像这样注册到我们的应用程序中:

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

这有效,除了异常和请求未连接。两者都被记录下来,但是当单击失败的请求时,它会显示“未找到相关异常”。相反,在打开异常属性时,我们可以读取“受此异常影响的请求:0”。这样做的正确方法是什么?

4

4 回答 4

11

ExceptionTelemetry.Context.Operation.IdApplication Insights 通过比较和来链接异常和请求RequestTelemetry.Id

我没有 OWIN 的代码示例,但是 Application Insights SDK 的ASP.NET 5 包具有用于跟踪异常和请求的类似中间件组件。我希望您可以使用此信息为 OWIN 构建解决方案。

在调用执行实际请求处理的下一个中间件组件之前,我们创建一个RequestTelemetry实例并将其存储在请求处理环境中。在 ASP.NET 5 中,我们将 RequestTelemetry 注册为请求范围的服务。使用 OWIN,我想您的中间件组件会创建它并将其存储在environment字典中。

我们还有一个ITelemetryInitializer名为OperationIdTelemetryInitializer的,它设置从环境ITelemetry.Context.Operation.IdRequestTelemetry.Id提取的 。需要将此初始化程序添加到用于在应用程序TelemetryConfiguration中创建实例的方法中。默认使用。TelemetryClientTelemetryConfiguration.Active

于 2015-06-03T20:13:00.763 回答
11

我最终做了什么:

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);
    }
}
于 2015-06-12T10:38:25.630 回答
2

有一个TelemetryClient.TrackException接受属性字典的方法重载。它专门用于分类和搜索异常。这允许生成错误 ID,并将错误链接到 AppInsights。

错误处理示例:

var errorId = GenerateErrorId();

var trackProperties = new Dictionary<string, string>();
trackProperties.Add("ErrorId", errorId);

var ai = new TelemetryClient();
ai.TrackException(exception, trackProperties);

JObject resp = new JObject();
resp["message"] = exception.Message + " - " + errorId;

await context.Response.WriteAsync(resp.ToString());
于 2019-01-04T15:46:52.037 回答
1

对于我目前的客户,我们还没有完成 OWIN。

DelegatingHandler我使用 WebAPI注册了一个,它将当前请求粘贴到线程的SynchronizationContextviaCallContext.LogicalSetData中,并在请求完成后将其删除。

在我现有的日志系统中,必须用 Application Insights 的东西进行改造,然后我从线程中获取请求,CallContext.LogicalSetData并开始获取HttpContext框架放置到请求属性中的请求,然后从 中HttpContext.Items,我得到RequestTelemetry实例。

最终,这一切都是必需的,因为我无法从正在更新服务的 IoC 容器中访问请求或操作或任何内容。

最终,我们可能会重写其中的一些内容,以允许改进创建和在堆栈中向下流动OperationContextInstrumentationContext样式对象,并摆脱处理程序和CallContext有趣的业务。

于 2015-11-11T17:51:06.643 回答