How to add a custom dimension to request telemetry in a Nodejs/typescript azure function?

Viewed 460

Goal

A request comes in and is handled by the Azure Functions run-time. By default it creates a Request entry, and a bunch of Trace entries in Application Insights. I want to add a custom dimension to that top level request item (on a per-request basis) so I can use it for filtering/analysis later.

Query for -requests- on Application Insights

Query for -requests- on Application Insights

Resulting list of requests including custom dimensions column

Resulting list of requests including custom dimensions column

The Azure Functions runtime adds a few custom dimensions already. I want to add a few of my own.

Image of the custom dimensions expanded

Approach

The most promising approach I've found is show below (taken from here https://github.com/microsoft/ApplicationInsights-node.js/issues/392)

appInsights.defaultClient.addTelemetryProcessor(( envelope, context ) => {
    var data = envelope.data.baseData;
    data.properties['mykey'] = 'myvalue';
    return true;
});

However, I find that this processor is only called for requests that I initialise within my function. For example, if I make an HTTP request to another service, then details of that request will be passed thru the processor and I can add custom properties to it. But the main function does not seem to pass thru here. So I can't add my custom property.

I also tried this

defaultClient.commonProperties['anotherCustomProp'] = 'bespokeProp2'

Same problem. The custom property doesn't arrive in application insights. I've played with many variations on this and it appears that the logging done by azure-functions is walled off from anything I can do within my code.

The best workaround I have right now, is to call trackRequest manually. This is okay, except I end up with each request logged twice in application insights, one by the framework and one by me. And both need to have the same operation_id otherwise I can't find the associated trace/error items. So I'm having to extract the operationId in a slightly hacky way. This may be fine, my knowledge of application insights is pretty naive at this point.

import { setup, defaultClient } from 'applicationinsights' // i have to import the specific functions, because "import ai from applicationinsights" returns null

// call this because otherwise defaultClient is null.
// Some examples call start(), I've tried with and without this.
// I think the start() function must be useful when you're adding application-insights to a project fresh, whereas I think the azure-functions run-time must be doing this already.
setup()

const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
    // Extract the operation id from the traceparent as per w3 standard https://www.w3.org/TR/trace-context/.
    const operationId = context.traceContext.traceparent.split('-')[1]
    var operationIdOverride = { 'ai.operation.id': operationId }

    // Create my own trackRequest entry
    defaultClient.trackRequest({
      name: 'my func name',
      url: context.req.url.split('?')[0],
      duration: 123,
      resultCode: 200,
      success: true,
      tagOverrides: operationIdOverride,
      properties: {
        customProp: 'bespokeProp'
      }
    })

The Dream

Our C# cousins seem to have an array of options, like Activity.Current.tags and the ability to add TelemetryInitializer. However it looks like what I'm trying to do is supported, I'm just not finding the right combination of commands! Is there something similar for javascript/typescript/nodejs, where I can just add a tag on a per-request basis? Along the lines of context.traceContext.attributes['myprop'] = 'myValue'

Alternative

Alternatively, instrumenting my code using my own TelemetryClient (rather than the defaultClient) using trackRequest, trackTrace, trackError etc, is not a very big job and should work well - that would be more explicit. Should I just do that? Is there a way to disable the azure functions tracking - or perhaps I just leave that as something running side-by-side.

0 Answers
Related