Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: What is the correct way to add request-specific properties to telemetry context? #1428

Closed
joostvz opened this issue Jul 4, 2019 · 8 comments

Comments

@joostvz
Copy link

joostvz commented Jul 4, 2019

I want to add request-specific data to the telemetry context, so that it will be included in the default AI Trace and Request log messages. This data is retrieved from the request body in my Azure Function (v2). Ideally, I want to be able to add this data to the context inside my Function, and not in a TelemetryInitializer (as that would force me to parse the request body in both the Function and the initializer).

I looked at the TelemetryClient to do this, but this one doesn't seem to have an applicable property for it:

  • TelemetryClient.Context.GlobalProperties is meant for global properties, and not for request-scoped properties;
  • TelemetryClient.Context.Properties is obsolete, and I don't see how I can use the recommended replacement ISupportProperties.Properties there.

Note: I've also opened a question on StackOverflow for this.

@cijothomas
Copy link
Contributor

cc: @lmolkova as well.

@lmolkova
Copy link
Member

lmolkova commented Jul 9, 2019

You can update request telemetry properties by adding tags on Activity.Current like

  Activity.Current?.AddTag("my-prop", ExtractPropFromRequest());

Without any additional changes, these tags will appear on requests.
Unfortunately, you won't get them stamped on traces.

You can also parse your request body once in the function and store it in AsyncLocal. Then access this AsyncLocal in the TelemetryInitializer

   public class AsyncLocalPropertyTelemetryInitializer : ITelemetryInitializer
    {
        public void Initialize(ITelemetry telemetry)
        {
            if (telemetry is ISupportProperties propTelemetry &&
                Function1.AdditionalContext.Value != null) // you may find a better way to make it work with DI
            {
                propTelemetry.Properties["my-prop"] = Function1.AdditionalContext.Value;
            }
        }
    }

    public static class Function1
    {
        internal static readonly AsyncLocal<string> AdditionalContext = new AsyncLocal<string>();
        private static readonly HttpClient httpClient = new HttpClient(); 

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

Hope it answers your question, feel free to reopen the issue if it does not.

@lmolkova lmolkova closed this as completed Jul 9, 2019
@reyesml
Copy link

reyesml commented Aug 6, 2019

@lmolkova I'm having some trouble getting custom properties to appear using the Activity.Current approach. As a test, I have a simple controller that only has one method:

using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;

namespace HelloWorld
{
    [Route("")]
    public class DefaultController : Controller
    {
        [Route("")]
        [HttpGet]
        public ContentResult checkIfAlive()
        {
            Activity.Current?.AddTag("Hello", "World");
            return new ContentResult
            {
                Content = "Services are running"
            };
        }
    }
}

I've stepped through the code to verify that Activity.Current isn't null, but I still don't see my "Hello" attribute on my app insights request logs. Am I looking in the wrong place?

App Insights Screenshot

@cijothomas cijothomas reopened this Aug 15, 2019
@lmolkova
Copy link
Member

Oh, sorry for misleading info, this is true only for Azure Functions. Tags are not supported out of the box for ASP.NET Core apps (#562).

You'd need to write custom telemetry initializer that populates Tags on the telemetry.

@reyesml
Copy link

reyesml commented Aug 20, 2019

That clears it up, thank you! I decided to get around this by creating custom events as children of the request. I accomplished this by adding TelemtryClient as a dependency to the controller, then calling _myTelemetryClient.TrackEvent("Some Event", myEventPropertyDictionary);

@scottmcm
Copy link

For anyone who ends up here in the future, if you're in AspNetCore one answer is to do this:

var requestTelemetry = context.HttpContext.Features.Get<RequestTelemetry>();
requestTelemetry.Properties["Foo"] = "Bar";

@safakgur
Copy link

safakgur commented Aug 6, 2021

@lmolkova:

You can update request telemetry properties by adding tags on Activity.Current like

Activity.Current?.AddTag("my-prop", ExtractPropFromRequest());

Hi - is this still the case with Azure Functions on .NET 5 (isolated process)? Activity.Current seems to always be null:

[Function("Foo")]
public HttpResponseData Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "foo")]
    HttpRequestData req)
{
    // `Current` is null, `AddTag` doesn't get executed.
    Activity.Current?.AddTag("Bar", "Baz");

    return req.CreateResponse();
}

Do I need to start an activity manually using TraceParent and TraceState from req.FunctionContext.TraceContext?

@Zenuka
Copy link

Zenuka commented Sep 6, 2021

@lmolkova:

You can update request telemetry properties by adding tags on Activity.Current like

Activity.Current?.AddTag("my-prop", ExtractPropFromRequest());

Hi - is this still the case with Azure Functions on .NET 5 (isolated process)? Activity.Current seems to always be null:

[Function("Foo")]
public HttpResponseData Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "foo")]
    HttpRequestData req)
{
    // `Current` is null, `AddTag` doesn't get executed.
    Activity.Current?.AddTag("Bar", "Baz");

    return req.CreateResponse();
}

Do I need to start an activity manually using TraceParent and TraceState from req.FunctionContext.TraceContext?

I just started a new 3.1 function app with Microsoft.NET.Sdk.Functions (3.0.13) and Microsoft.ApplicationInsights.AspNetCore (2.18.0) and Activity.Current seems to be null as well.

I tried to use the "HttpContext"-way like scottmcm suggested but there is no HttpContext which makes sense since I'm not using an http trigger but a service bus trigger.

Another thing I tried is to make a scoped ITelemetryInitializer so that I could access it from in different classes and add properties to it but unfortunately you cannot register a scoped ITelemetryInitializer for dependency injection, it needs to be a singleton.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants