【问题标题】:Add metadata to traces in Azure functions将元数据添加到 Azure 函数中的跟踪
【发布时间】:2019-11-05 10:49:00
【问题描述】:

我有一个 Azure 函数(.NET core 2.0),它在 ADO 存储库中的每个 PR 上运行。 我想将 PR-ID 作为元数据添加到 Azure 函数记录的每个跟踪。 (我正在使用 Azure 应用程序洞察实例中的 traces 表查看日志)

Azure 函数通过以下方式记录跟踪:

public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestMessage req, ILogger log, ExecutionContext context)
{
  logger.LogInformation("Trace Message");
}

如何向每个跟踪添加额外的元数据?

【问题讨论】:

  • 这个 PR id 在传入的 http 请求中如何/存储在哪里?
  • 是的。我还想记录传入的 HTTP 请求中的其他元数据。

标签: azure azure-functions azure-application-insights azure-function-app .net-core-2.0


【解决方案1】:

是的,这是可能的。

选项 1:AsyncLocal 的帮助下使用遥测初始化器:

    public class CustomTelemetryInitializer : ITelemetryInitializer
    {
        public static AsyncLocal<string> MyValue = new AsyncLocal<string>();

        public void Initialize(ITelemetry telemetry)
        {
            if (telemetry is ISupportProperties propertyItem)
            {
                propertyItem.Properties["myProp"] = MyValue.Value;
            }
        }
    }

您可以像这样在函数中设置 AsyncLocal 的值:

        [FunctionName("Function")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]
            HttpRequest req,
            ILogger log)
        {
            var name = req.Query["name"];

            CustomTelemetryInitializer.MyValue.Value = name;

            log.LogInformation("C# HTTP trigger function processed a request.");

            return new OkObjectResult($"Hello, {name}");
        }

运行该函数时,您可以在门户中看到信息:

你可以在this repo找到完整的代码

现在,向您的 cmets 讲话。是的,你需要一些额外的东西。 ITelemetryInitializer 实例需要使用依赖注入来注册。这是在Startup 类中完成的,如documentation 中所述:

    using Microsoft.ApplicationInsights.Extensibility;
    using Microsoft.Azure.Functions.Extensions.DependencyInjection;
    using Microsoft.Extensions.DependencyInjection;

    [assembly: FunctionsStartup(typeof(FunctionApp.Startup))]

    namespace FunctionApp
    {
        public class Startup : FunctionsStartup
        {
            public override void Configure(IFunctionsHostBuilder builder)
            {
                builder.Services.AddSingleton<ITelemetryInitializer, CustomTelemetryInitializer>();
                builder.Services.AddLogging();
            }
        }
    }

注册后,Application Insights SDK 将使用CustomTelemetryInitializer

选项 2 另一个选项不涉及任何 TelemetryInitializer,但您只能将属性添加到由 Azure Function App Insights 集成添加的生成的 RequestTelemetry。这是通过利用当前TelemetryRequest 存储在HttpContext 中的事实来完成的:

       [FunctionName("Function")]
        public static IActionResult Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]
            HttpRequest req,
            ILogger log)
        {
            var name = req.Query["name"];

            CustomTelemetryInitializer.MyValue.Value = name;

            log.LogInformation("C# HTTP trigger function processed a request.");

            var telemetryItem = req.HttpContext.Features.Get<RequestTelemetry>();
            telemetryItem.Properties["SetInFunc"] = name;

            return new OkObjectResult($"Hello, {name}");
        }

这也会显示在门户中:

上下文只添加到Request中是否有问题?可能,但请注意,您可以查询所有相关的遥测数据并了解所涉及的上下文,例如:

union (traces), (requests), (dependencies), (customEvents), (exceptions)
| extend itemType = iif(itemType == 'availabilityResult',itemType,iif(itemType == 'customEvent',itemType,iif(itemType == 'dependency',itemType,iif(itemType == 'pageView',itemType,iif(itemType == 'request',itemType,iif(itemType == 'trace',itemType,iif(itemType == 'exception',itemType,"")))))))
| extend prop = customDimensions.SetInFunc
| where ((itemType == 'trace' or (itemType == 'request' or (itemType == 'pageView' or (itemType == 'customEvent' or (itemType == 'exception' or (itemType == 'dependency' or itemType == 'availabilityResult')))))))
| top 101 by timestamp desc

将显示:

来自同一调用的所有遥测数据将具有相同的operation_Id

【讨论】:

  • 谢谢!我是否需要做一些额外的事情才能调用CustomTelemetryInitializer.Initialize
  • 在第一个答案中,我看到这是由定义 public class MyStartup : IWebJobsStartup ` 和 [assembly: WebJobsStartup(typeof(FunctionApp54.MyStartup))] 的组合调用的
  • @Nishant 添加了一个侵入性较小的替代方案。
【解决方案2】:

这可以使用 ITelemetry Initializer 来实现,您可以将自定义维度添加到指定的遥测数据中,例如仅用于请求。

1.安装以下nuget包:

Microsoft.ApplicationInsights, version 2.11.0

Microsoft.NET.Sdk.Functions, version 1.0.29

2.下面是我的测试代码。

[assembly: WebJobsStartup(typeof(FunctionApp54.MyStartup))]
namespace FunctionApp54
{

    internal class MyTelemetryInitializer : ITelemetryInitializer
    {
        public void Initialize(ITelemetry telemetry)
        {

            //use telemetry is RequestTelemetry to make sure only add to request
            if (telemetry != null && telemetry is RequestTelemetry && !telemetry.Context.GlobalProperties.ContainsKey("testpro"))
            {
                telemetry.Context.GlobalProperties.Add("testpro", "testvalue");
            }
        }
    }

    public class MyStartup : IWebJobsStartup
    {
        public void Configure(IWebJobsBuilder builder)
        {
            builder.Services.AddSingleton<ITelemetryInitializer, MyTelemetryInitializer>();

        }
    }

    public static class Function2
    {


        [FunctionName("Function2")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            string name = req.Query["name"];

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data = JsonConvert.DeserializeObject(requestBody);
            name = name ?? data?.name;

            return name != null
                ? (ActionResult)new OkObjectResult($"Hello, {name}")
                : new BadRequestObjectResult("Please pass a name on the query string or in the request body");
        }
    }
}

【讨论】:

  • 谢谢!几个问题: 1. 这条线做什么?:[assembly: WebJobsStartup(typeof(FunctionApp54.MyStartup))] 2. telemetry.Context.GlobalProperties.Add 只能通过 MyTelemetryInitializer::Initialize 调用吗?我担心我想记录的属性可能不会那么早。
  • 用于添加WebJobsStartup 程序集属性,指定启动时使用的类型名称。 GlobalProperties.AddITelemetry 下的方法。
  • 如果你想在你的函数中添加属性,你可以参考这个答案:stackoverflow.com/a/53332461/10383250 但是这会创建一个新的跟踪。
  • 您所指的解决方案将自定义事件添加到应用程序中,我相信它与跟踪不同。这些事件不容易与痕迹相关联。
  • 似乎没有办法将自定义元数据添加到log.Information发出的每个跟踪中
猜你喜欢
  • 2020-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-24
  • 2017-03-06
  • 2021-09-16
  • 2018-11-15
相关资源
最近更新 更多