【问题标题】:Structured Logging in Azure FunctionsAzure Functions 中的结构化日志记录
【发布时间】:2021-03-25 08:25:39
【问题描述】:

我正在尝试让结构化日志记录在 Azure 函数中运行,但它在我这边不起作用。

我写了一个这样的简单应用程序

[FunctionName("Dummy")]
public IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous)]HttpRequest request, ILogger log)
{
    var instance = new User
    {
        Name1 = "foo",
        Name2 = "bar"
    };
    log.LogInformation("Test1: {$Test}", instance);
    log.LogInformation("Test2: {@Name}", instance);
    log.LogInformation("Test3: {@Name}", new { Name1 = "abc", Name2 = "def" });
    log.LogInformation("Test4: {Vorname} {Nachname}", instance.Name1, instance.Name2);
    return new OkResult();
}

public class User
{
    public string Name1 { get; set; }
    public string Name2 { get; set; }
}

输出如下所示:

Test1: Company.FunctionApp1.Function+User
Test2: Company.FunctionApp1.Function+User
Test3: { Name1 = abc, Name2 = def }
Test4: foo bar

我不知道为什么解构对动态类型起作用,但对定义的类不起作用。我发现了很多没有破坏对象结构的正常日志记录示例,但我认为它应该开箱即用。

我错过了什么吗?

【问题讨论】:

  • 你想要什么结果?
  • 我想要 Test2 和 Test3 之间相同的结果。就像在这个例子中一样 => github.com/messagetemplates/messagetemplates-csharp 我认为这将是 .Net Core Logger 的默认模板
  • 此代码:log.LogInformation("Test1: {$Test}", JsonConvert.SerializeObject(instance)); 是否满足您的要求?
  • 是的,这会起作用,但我认为这种行为是在默认记录器中实现的。
  • 我不确定 Application Insights 提供商是否支持它。注意 - SeriLog 在记录时提供解构对象。目前,您可以使用的解决方法是在 User 对象上定义 ToString。或者你可以编写一个扩展方法,使用反射来解构对象。

标签: logging azure-functions structured-logging


【解决方案1】:

测试 3 打印为 { Name1 = abc, Name2 = def },因为定义的类型是匿名对象,编译器为其生成 ToString() 方法以返回具有属性和值映射的字符串。

签入this讨论。

您可以通过反编译来验证。

因为,Test2 和 Test1 使用对象并且没有覆盖 ToString() 定义,这就是返回 TypeName 的原因。

正确的方法是使用 Test4,以便将 VornameNachname 记录为自定义属性并可用于过滤。

【讨论】:

  • 动态类型的优点,我错过了。我确实希望它成为应用程序洞察力中的自定义属性。它确实适用于 JsonConvert.SerializeObject,但在我看来,它应该在名称前面带有 @ 的情况下开箱即用。我以为默认实现是按照这个messagetemplates.org
【解决方案2】:

user1672994 的回答是对的,你可以这样做:

using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace FunctionApp96
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            var instance = new User
            {
                Name1 = "foo",
                Name2 = "bar"
            };
            log.LogInformation("Test1: {$Test}", instance);
            log.LogInformation("Test2: {@Name}", instance);
            log.LogInformation("Test3: {@Name}", new { Name1 = "abc", Name2 = "def" });
            log.LogInformation("Test4: {Vorname} {Nachname}", instance.Name1, instance.Name2);
            return new OkObjectResult("");
        }
    }
    public class User
    {
        public override string ToString()
        {
            string str = "{ Name1 = " + Name1 + ", Name2 =" + Name2 + " }";
            return str;
        }
        public string Name1 { get; set; }
        public string Name2 { get; set; }
    }
}

你会得到:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-24
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 2018-12-18
    • 1970-01-01
    相关资源
    最近更新 更多