【问题标题】:Logging approach in Azure WebApp for Containers [closed]Azure WebApp for Containers 中的日志记录方法 [关闭]
【发布时间】:2020-08-15 17:22:29
【问题描述】:

我正在设计一个 ASP.NET Core 应用程序以作为容器的 WebApp 运行。我正在将应用程序异常记录在一个文本文件中。我还使用 Application Insight 包来捕获遥测数据。我已经在 WebAapp for Container 中托管了应用程序。

在哪里可以找到和下载日志文本文件?

另外,当应用程序被设计为容器的 WebApp 时,上述方法是否适用于日志记录?如果不是,那么正确的方法是什么?

此外,Application Insight 主要生成遥测信息。我可以将我的应用程序的文本日志与 Application Insight 集成以实现更好的应用程序日志分析吗?

【问题讨论】:

    标签: azure asp.net-core containers azure-web-app-service


    【解决方案1】:

    我正在设计一个 ASP.NET Core 应用程序以作为容器的 WebApp 运行。我正在将应用程序异常记录在一个文本文件中。我还使用 Application Insight 包来捕获遥测数据。我已经在 WebAapp for Container 中托管了应用程序。

    我也会将异常记录到 Application Insights (AI)。如果您使用 SDK,未处理的异常将最终出现在 AI 中。此外,您可以手动跟踪它们:

    try
    {
        ....
    }
    catch(Exception ex)
    {
       telemetryClient.TrackException(ex);
    }
    

    此外,Application Insight 主要生成遥测信息。我可以将我的应用程序的文本日志与 Application Insight 集成以更好地分析应用程序日志吗?

    是的,你可以。使用 AI SDK,您可以发送多种类型的遥测数据,请参阅the docs。对于文本记录,我建议使用TrackTrace:

    telemetry.trackTrace("a message", SeverityLevel.Information);

    您也可以使用 TrackEvent,但它可以存储更少的数据 (source)

    现在,除了使用TrackTrace 进行自定义文本日志记录之外,您还可以使用ILogger 接口并像the usual .net core way 一样进行日志记录。它有support for AI 并将日志写入AI 作为跟踪。

    在所有情况下,请注意sampling 可能会导致并非所有遥测都在 AI 中可用,因此要么关闭它,要么接受它。

    【讨论】:

      【解决方案2】:

      这是一个用于在 Application Insight 上记录请求和响应的中间件。您也可以创建一个日志记录服务,以便在应用程序 Insight 中记录异常。

      中间件

      public class LoggingMiddleware
      {
          private static readonly TelemetryConfiguration telemetryConfiguration = TelemetryConfiguration.CreateDefault();
          private readonly TelemetryClient telemetryClient;
          private IConfiguration configuration;
          private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
          private readonly string appName;
          private readonly bool loggingEnabled;
      
          private readonly RequestDelegate _next;
      
          public LoggingMiddleware(RequestDelegate next, IConfiguration config)
          {
              _next = next;
              configuration = config;
              _recyclableMemoryStreamManager = new RecyclableMemoryStreamManager();
              telemetryConfiguration.InstrumentationKey =  configuration.GetValue<string>("ApplicationInsights:InstrumentationKey");
              telemetryClient = new TelemetryClient(telemetryConfiguration);
              appName = configuration.GetValue<string>("AppName");
              loggingEnabled = configuration.GetValue<bool>("Logging:LogRequestResponse"); 
          }
      
          public async Task Invoke(HttpContext httpContext)
          {
              if(loggingEnabled)
              {
                  await LogRequest(httpContext);
                  await LogResponse(httpContext);
              }
          }
      
          private async Task LogRequest(HttpContext context)
          {
              context.Request.EnableBuffering();
      
              await using var requestStream = _recyclableMemoryStreamManager.GetStream();
              await context.Request.Body.CopyToAsync(requestStream);
      
              string correlationId = context.Request.Headers.Keys.FirstOrDefault(h => h.ToLower() == "correlationid");
              if (correlationId == null) correlationId = string.Empty;
              if (context.Request.Path != "/")
              {
                  telemetryClient.TrackEvent($"{appName}-RequestMiddleware", new Dictionary<string, string>
                  {
                      { "AppName", appName },
                      { "CorrelationId" , correlationId },
                      { "Method" , context.Request.Method },
                      { "Scheme", context.Request.Scheme},
                      { "Host", context.Request.Host.Value },
                      { "Path", context.Request.Path },
                      { "QueryString", context.Request.QueryString.Value },
                      { "Request Body", ReadStreamInChunks(requestStream) }
      
                  });
              }
              context.Request.Body.Position = 0;
          }
      
          private static string ReadStreamInChunks(Stream stream)
          {
              const int readChunkBufferLength = 4096;
      
              stream.Seek(0, SeekOrigin.Begin);
      
              using var textWriter = new StringWriter();
              using var reader = new StreamReader(stream);
      
              var readChunk = new char[readChunkBufferLength];
              int readChunkLength;
      
              do
              {
                  readChunkLength = reader.ReadBlock(readChunk,
                                                     0,
                                                     readChunkBufferLength);
                  textWriter.Write(readChunk, 0, readChunkLength);
              } while (readChunkLength > 0);
      
              return textWriter.ToString();
          }
      
          private async Task LogResponse(HttpContext context)
          {
              var originalBodyStream = context.Response.Body;
      
              await using var responseBody = _recyclableMemoryStreamManager.GetStream();
              context.Response.Body = responseBody;
      
              await _next(context);
      
              context.Response.Body.Seek(0, SeekOrigin.Begin);
              var text = await new StreamReader(context.Response.Body).ReadToEndAsync();
              context.Response.Body.Seek(0, SeekOrigin.Begin);
              if (context.Request.Path != "/")
              {
                  telemetryClient.TrackEvent($"{appName}-ResponseMiddleware", new Dictionary<string, string> {
                      {"Scheme", context.Request.Scheme},
                      { "AppName", appName },
                      {"Host", context.Request.Host.Value},
                      {"Path" , context.Request.Path},
                      {"QueryString", context.Request.QueryString.Value},
                      {"Response Body" , text}
                      });
              }
             await responseBody.CopyToAsync(originalBodyStream);
          }
      }
      
      
      // Extension method used to add the middleware to the HTTP request pipeline.
      public static class LoggingMiddlewareExtensions
      {
          public static IApplicationBuilder UseLoggingMiddleware(this IApplicationBuilder builder)
          {
              return builder.UseMiddleware<LoggingMiddleware>();
          }
      }
      

      【讨论】:

        【解决方案3】:

        您不必将应用程序异常明确写入文件。将 Application Insights 与应用程序集成时,将记录所有异常。您可以在 AI 实例的 Failures 刀片中查看异常

        更新1:

        在下面的屏幕截图中,您可以查看前 3 种异常类型。而且,500 响应代码还会向您显示异常。所有这些都不需要太多代码。您可以查看我的文章 here,了解有关如何将 Application Insights 集成到 asp.net 核心应用程序的分步详细说明。

        【讨论】:

        • 感谢您的回复。但故障刀片将仅显示 HTTP 调用失败。我相信我们应该始终在日志文件中记录应用程序错误异常。如果应用程序作为容器的 Webapp 托管,我如何查看或下载该日志?我们可以将该日志与 Application Insight 集成吗?
        • 非常感谢您的回复。
        猜你喜欢
        • 2015-09-08
        • 1970-01-01
        • 1970-01-01
        • 2018-12-08
        • 2019-02-02
        • 2017-03-21
        • 1970-01-01
        • 2011-04-25
        • 2012-10-23
        相关资源
        最近更新 更多