Adding authenticated user ID information in server-side NodeJS Application Insights events
Asked Answered
B

2

7

I have a NodeJS app in which I'm consuming the applicationinsights NodeJS package (this). According to ApplicationInsights data model described here, it says the property exists, but I am not able to find a code snipped as to how to set this property in the telemetry event I'm sending.

Any snipped describing how to do this would be helpful!

Backswept answered 8/6, 2018 at 17:9 Comment(0)
H
11

According to your description, I only found the tutorials for ASP.NET about Setting the user context in an ITelemetryInitializer and Authenticated users for JavaScript.

Then I checked the setAuthenticatedUserContext method under User.ts of Microsoft Application Insights SDK for JavaScript and found the related code snippet under TelemetryContext.ts as follows:

if (typeof userContext.authenticatedId === "string") {
      envelope.tags[tagKeys.userAuthUserId] = userContext.authenticatedId;
}

Then checked ContextTagKeys.ts and found the context tags as follows:

this.sessionId = "ai.session.id";
this.userAccountId = "ai.user.accountId";
this.userId = "ai.user.id";
this.userAuthUserId = "ai.user.authUserId";
...

but I am not able to find a code snipped as to how to set this property in the telemetry event I'm sending.

For NodeJS SDK, the context tag keys are under ContextTagKeys.ts. For your requirement, you could leverage the following code snippet:

appInsights.defaultClient.context.tags[appInsights.defaultClient.context.keys.userAuthUserId] ="xxxx";

For Session id, Account id or other context fields, you just need to choose the relevant context tag key.

Hemichordate answered 13/6, 2018 at 7:20 Comment(1)
With this you can set the Session/User ID once, right? But how do you set it up to use the sessionId and userId from the request so it's different for each request?Hydroplane
C
6

Just in case someone is still struggling with adding user information to the telemetry event on a per-request basis, here's what I did:

const appInsights = require("applicationinsights");

appInsights.setup().start()
appInsights.defaultClient.addTelemetryProcessor(
  (envelope, context) => {
    // context keys from the `ContextTagKeys` contract
    const contextKeys = {
      userId: "userId",
      sessionId: "sessionId",
    }
    const getContextKey = (key) => {
      return appInsights.defaultClient.context.keys[key]
    }
    const setContextKey = (key, value) => {
      envelope.tags[key] = value;
    }

    // custom context that I set on per-request basis
    const requestContext = appInsights.getCorrelationContext().requestContext
    const data = envelope.data.baseData;

    for (const [key, value] of Object.entries(requestContext)) {
      switch (key) {
        case "userId":
          setContextKey(
            getContextKey("userId"),  // ai.user.id
            value                     // [email protected]
          )
          break
        case "sessionId":
          setContextKey(
            getContextKey("userId"),  // ai.session.id
            value                     // 507f191e810c19729de860ea
          )
          break
        default:
          // if it's a custom property that doesn't belong in the
          // `ContextTagKeys` contract, such as browser information, add
          // it as a custom property on the `envelope.data.baseData` object
          data.properties[key] = value
      }
    }

    return true
  }
)

Then, since I am using Express, I created a middleware function that sets per-request information on the context object:

const express = require('express')
const Bowser = require("bowser");

const app = express();

// ...

app.use((req, res, next) => {
  const session = req.session;
  const userAgent = req.get('User-Agent')

  const sessionId = session.id
  const userId = session.userId
  const browser = Bowser.getParser(userAgent) 

  const currentRequestContext = 
    appInsights.getCorrelationContext().requestContext || {}

  const nextRequestContext = {
    ...currentRequestContext,
    sessionId,      // 507f191e810c19729de860ea 
    userId,         // [email protected]
    browser:        // custom property, e.g. Firefox 83
      browser.getBrowserName() + " " + browser.getBrowserVersion()
  }

  appInsights.getCorrelationContext().requestContext = nextRequestContext

  next()
})

To get a list of all available ContextTagKeys contracts, have a look here:

  • ContextTagKeys.ts
  • ContextTagKeys.ts (client-side library)
    • It appears that some of these ContextTagKeys from the client-side library can be set in the server-side library as well, which is how I got the client_Browser property to show up in Azure portal after populating ai.device.browserVersion with browser information

Here's an example from the documentation on how to create your own custom telemetry processor:

Here are the issues on GitHub that helped me find the proper solution:

Lastly, here's the version of applicationinsights that I am using:

  • applicationinsights v1.8.8
Claudelle answered 11/12, 2020 at 13:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.