【问题标题】:Application Insights - ILogger arguments rendered as name of the object in custom dimensionsApplication Insights - ILogger 参数呈现为自定义维度中的对象名称
【发布时间】:2020-06-20 07:14:45
【问题描述】:

当作为参数传递给 ilogger 时,对象在 Application Insights 自定义维度中呈现为字符串(对象的名称)。实际值未显示。

注册 Application Insights

services.AddApplicationInsightsTelemetry();

新日志

public class HealthController : ControllerBase
{
    private readonly ILogger<HealthController> _logger;

    public HealthController(ILogger<HealthController> logger)
    {
        _logger = logger;
    }

    [HttpGet]
    public IActionResult Get()
    {
        var health = new HealthViewModel()
        {
             ok = false
        };

        _logger.LogInformation("Hlep me pls {health}", health);

        return Ok(health);
    }
}

结果

我不想对每个日志都这样:

var health = new HealthViewModel()
{
     ok = false
};

_logger.LogInformation("Hlep me pls {health}", JsonConvert.SerializeObject(health));

我尝试为应用程序洞察创建中间件,但值仍然是对象的名称..

为什么参数不呈现为 json?

编辑

好像

var health = new
{
     ok = false
};

_logger.LogInformation("HEJ2 {health}", health);

有效但无效

var health = new HealthViewModel
{
     ok = false
};

_logger.LogInformation("HEJ2 {health}", health);

【问题讨论】:

    标签: c# azure .net-core azure-application-insights ilogger


    【解决方案1】:

    不支持

    引用https://github.com/microsoft/ApplicationInsights-dotnet/issues/1722

    我认为您对记录器的期望过高。它不知道 JSON 格式,它只是在属性上调用 Convert.ToString

    Convert.ToString 通常调用 ToString() 并且新类的默认 ToString 实现只是返回类型名称

    你能做什么

    对记录到 ILogger 的对象使用 ToJson(),并为应用程序洞察创建中间件,并修改日志名称和自定义维度。

    中间件

    public class ProcessApiTraceFilter : ITelemetryProcessor
    {
        private ITelemetryProcessor Next { get; set; }
        private readonly IIdentity _identity;
        private readonly IHostEnvironment _hostEnvironment;
    
        public ProcessApiTraceFilter(ITelemetryProcessor next, IHostEnvironment hostEnvironment, IIdentity identity)
        {
            Next = next;
            _identity = identity;
            _hostEnvironment = hostEnvironment;
        }
    
        public void Process(ITelemetry item)
        {
            item.Process(_hostEnvironment, _identity);
    
            Next.Process(item);
        }
    }
    

    实施

    public static class ApplicationInsightsExtensions
    {
        public static void Process(this ITelemetry item, IHostEnvironment hostEnvironment, IIdentity identity)
        {
            if (item is TraceTelemetry)
            {
                var traceTelemetry = item as TraceTelemetry;
                var originalMessage = traceTelemetry.Properties.FirstOrDefault(x => x.Key == "{OriginalFormat}");
    
                if (!string.IsNullOrEmpty(originalMessage.Key))
                {
                    var reg = new Regex("{([A-z]*)*}", RegexOptions.Compiled);
                    var match = reg.Matches(originalMessage.Value);
                    var formattedMessage = originalMessage.Value;
                    foreach (Match arg in match)
                    {
                        var parameterName = arg.Value.Replace("{", "").Replace("}", "");
                        var parameterValue = traceTelemetry.Properties.FirstOrDefault(x => x.Key == parameterName);
                        formattedMessage = formattedMessage.Replace(arg.Value, "");
                    }
    
                    traceTelemetry.Message = formattedMessage.Trim();
                }
    
                if (identity != null)
                {
                    var isAuthenticated = identity.IsAuthenticated();
                    const string customerKey = "customer";
    
                    if (isAuthenticated && !traceTelemetry.Properties.ContainsKey(customerKey))
                    {
                        var customer = identity.Customer();
    
                        if (customer != null)
                        {
                            traceTelemetry.Properties.Add(customerKey, customer.ToJson());
                        }
                    }
    
                    var request = identity.Request();
                    const string requestKey = "request";
    
                    if (request != null && !traceTelemetry.Properties.ContainsKey(requestKey))
                    {
                        traceTelemetry.Properties.Add(requestKey, request.ToJson());
                    }
                }
    
                var applicationNameKey = "applicationName";
    
                if (hostEnvironment != null && !string.IsNullOrEmpty(hostEnvironment.ApplicationName) && !traceTelemetry.Properties.ContainsKey(applicationNameKey))
                {
                    traceTelemetry.Properties.Add(applicationNameKey, hostEnvironment.ApplicationName);
                }
            }
        }
    }
    

    在启动时注册应用洞察和中间件

    services.AddApplicationInsightsTelemetry();
    services.AddApplicationInsightsTelemetryProcessor<ProcessApiTraceFilter>();
    

    ToJson

    public static class ObjectExtensions
    {
        private static readonly string Null = "null";
        private static readonly string Exception = "Could not serialize object to json";
    
        public static string ToJson(this object value, Formatting formatting = Formatting.None)
        {
            if (value == null) return Null;
    
            try
            {
                string json = JsonConvert.SerializeObject(value, formatting);
    
                return json;
            }
            catch (Exception ex)
            {
                return $"{Exception} - {ex?.Message}";
            }
        }
    }
    

    日志

    //Log object? _smtpAppSettings.ToJson()
    
    _logger.LogInformation("Email sent {to} {from} {subject}", to, _smtpAppSettings.From, subject)
    

    结果

    【讨论】:

      【解决方案2】:

      从您的自定义维度中,我可以看到它没有将健康 obj 参数视为额外数据

      _logger.LogInformation("Hlep me pls {health}", health);
      

      尝试在字符串本身中使用 jsonConverter。

      _logger.LogInformation($"Hlep me pls {JsonConvert.SerializeObject(health)}");
      

      【讨论】:

      • 是的,将其转换为 json 字符串是可行的,但我不想对每个日志都这样做,我在问题中提到了这一点。可以在中间件中执行此操作,但那里的值已经不正确
      • 我认为记录的值是 *.Api.Models.Health ... 等是您的对象的 .ToString() 的值 尝试在您的类中覆盖 .ToString() 并检查。
      • 我不建议按照此处的建议预先组合字符串,因为无法查询参数本身的值。需要解析日志消息,这可能并不容易。最好按照问题中的建议将该值作为单独的参数传递给 ILogger 方法。
      猜你喜欢
      • 2021-09-19
      • 2019-07-14
      • 1970-01-01
      • 2021-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多