0

I have set up NLog to work with Applicatin Insights and also log js exceptions and is working as required. However, I am struggling with making the instrumentation key dynamic so it targets the environment specific application insight instance.

NLog config target

<target name="aiTarget" xsi:type="ApplicationInsightsTarget"
     layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}">
      <instrumentationKey>"mydevappinsightinstrumentationkey"</instrumentationKey>
      <contextproperty name="threadid" layout="${threadid}" />
    </target>

Layout cshtm for JS exceptions

<script type="text/javascript">
        !function (v, y, T) { var S = v.location, k = "script", D = "instrumentationKey", C = "ingestionendpoint", I = "disableExceptionTracking", E = "ai.device.", b = "toLowerCase", w = (D[b](), "crossOrigin"), N = "POST", e = "appInsightsSDK", t = T.name || "appInsights", n = ((T.name || v[e]) && (v[e] = t), v[t] || function (l) { var u = !1, d = !1, g = { initialize: !0, queue: [], sv: "6", version: 2, config: l }; function m(e, t) { var n = {}, a = "Browser"; return n[E + "id"] = a[b](), n[E + "type"] = a, n["ai.operation.name"] = S && S.pathname || "_unknown_", n["ai.internal.sdkVersion"] = "javascript:snippet_" + (g.sv || g.version), { time: (a = new Date).getUTCFullYear() + "-" + i(1 + a.getUTCMonth()) + "-" + i(a.getUTCDate()) + "T" + i(a.getUTCHours()) + ":" + i(a.getUTCMinutes()) + ":" + i(a.getUTCSeconds()) + "." + (a.getUTCMilliseconds() / 1e3).toFixed(3).slice(2, 5) + "Z", iKey: e, name: "Microsoft.ApplicationInsights." + e.replace(/-/g, "") + "." + t, sampleRate: 100, tags: n, data: { baseData: { ver: 2 } } }; function i(e) { e = "" + e; return 1 === e.length ? "0" + e : e } } var e, n, f = l.url || T.src; function a(e) { var t, n, a, i, o, s, r, c, p; u = !0, g.queue = [], d || (d = !0, i = f, r = (c = function () { var e, t = {}, n = l.connectionString; if (n) for (var a = n.split(";"), i = 0; i < a.length; i++) { var o = a[i].split("="); 2 === o.length && (t[o[0][b]()] = o[1]) } return t[C] || (t[C] = "https://" + ((e = (n = t.endpointsuffix) ? t.location : null) ? e + "." : "") + "dc." + (n || "services.visualstudio.com")), t }()).instrumentationkey || l[D] || "", c = (c = c[C]) ? c + "/v2/track" : l.endpointUrl, (p = []).push((t = "SDK LOAD Failure: Failed to load Application Insights SDK script (See stack for details)", n = i, o = c, (s = (a = m(r, "Exception")).data).baseType = "ExceptionData", s.baseData.exceptions = [{ typeName: "SDKLoadFailed", message: t.replace(/\./g, "-"), hasFullStack: !1, stack: t + "\nSnippet failed to load [" + n + "] -- Telemetry is disabled\nHelp Link: https://go.microsoft.com/fwlink/?linkid=2128109\nHost: " + (S && S.pathname || "_unknown_") + "\nEndpoint: " + o, parsedStack: [] }], a)), p.push((s = i, t = c, (o = (n = m(r, "Message")).data).baseType = "MessageData", (a = o.baseData).message = 'AI (Internal): 99 message:"' + ("SDK LOAD Failure: Failed to load Application Insights SDK script (See stack for details) (" + s + ")").replace(/\"/g, "") + '"', a.properties = { endpoint: t }, n)), i = p, r = c, JSON && ((o = v.fetch) && !T.useXhr ? o(r, { method: N, body: JSON.stringify(i), mode: "cors" }) : XMLHttpRequest && ((s = new XMLHttpRequest).open(N, r), s.setRequestHeader("Content-type", "application/json"), s.send(JSON.stringify(i))))) } function i(e, t) { d || setTimeout(function () { !t && g.core || a() }, 500) } f && ((n = y.createElement(k)).src = f, !(o = T[w]) && "" !== o || "undefined" == n[w] || (n[w] = o), n.onload = i, n.onerror = a, n.onreadystatechange = function (e, t) { "loaded" !== n.readyState && "complete" !== n.readyState || i(0, t) }, e = n, T.ld < 0 ? y.getElementsByTagName("head")[0].appendChild(e) : setTimeout(function () { y.getElementsByTagName(k)[0].parentNode.appendChild(e) }, T.ld || 0)); try { g.cookie = y.cookie } catch (h) { } function t(e) { for (; e.length;)!function (t) { g[t] = function () { var e = arguments; u || g.queue.push(function () { g[t].apply(g, e) }) } }(e.pop()) } var s, r, o = "track", c = "TrackPage", p = "TrackEvent", o = (t([o + "Event", o + "PageView", o + "Exception", o + "Trace", o + "DependencyData", o + "Metric", o + "PageViewPerformance", "start" + c, "stop" + c, "start" + p, "stop" + p, "addTelemetryInitializer", "setAuthenticatedUserContext", "clearAuthenticatedUserContext", "flush"]), g.SeverityLevel = { Verbose: 0, Information: 1, Warning: 2, Error: 3, Critical: 4 }, (l.extensionConfig || {}).ApplicationInsightsAnalytics || {}); return !0 !== l[I] && !0 !== o[I] && (t(["_" + (s = "onerror")]), r = v[s], v[s] = function (e, t, n, a, i) { var o = r && r(e, t, n, a, i); return !0 !== o && g["_" + s]({ message: e, url: t, lineNumber: n, columnNumber: a, error: i, evt: v.event }), o }, l.autoExceptionInstrumented = !0), g }(T.cfg)); function a() { T.onInit && T.onInit(n) } (v[t] = n).queue && 0 === n.queue.length ? (n.queue.push(a), n.trackPageView({})) : a() }(window, document, {
            src: "https://js.monitor.azure.com/scripts/b/ai.2.min.js",

            crossOrigin: "anonymous",

            cfg: {
                connectionString: "InstrumentationKey=mydevappinsightinstrumentationkey;IngestionEndpoint=mydevappinsightingestionendpoint"
            }

        });

        window.appInsights = appInsights;
        appInsights.trackPageView();
        try {
            throw new Error("Logging Exception from Javascript");
        } catch (error) {
            appInsights.trackException("Logging Exception from Javascript.");
            appInsights.trackException({ error });
        }
    </script>

How do I make the instrumentation key dynamic in the above scenarios?

4
  • with Azure application insights key we use var instrumentationKey = "@instrumentationKey"; Commented Sep 13, 2023 at 8:27
  • @{ // Determine the environment (development, production, etc.) string environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); string developmentInstrumentationKey = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY_DEVELOPMENT"); string productionInstrumentationKey = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY_PRODUCTION"); string instrumentationKey = environment == "Production" ? productionInstrumentationKey : developmentInstrumentationKey; } Commented Sep 13, 2023 at 9:51
  • @Luky set ASPNETCORE_ENVIRONMENT=Development set APPINSIGHTS_INSTRUMENTATIONKEY_DEVELOPMENT=your_development_instrumentation_key Commented Sep 13, 2023 at 9:55
  • @Sampath Thank you so much, I have added a comment on your answer Commented Sep 13, 2023 at 13:04

2 Answers 2

1

The instrumentation key can be set to dynamic so it targets the environment-specific application insight instance like below.

const config = require('config');
const appInsights = require('applicationinsights');

// Determine the environment (development, production, etc.)
const environment = process.env.NODE_ENV || 'development';

// Get the instrumentation key from the configuration based on the environment
const instrumentationKey = config.get('appInsightsInstrumentationKey');

// Initialize Application Insights with the dynamic instrumentation key
appInsights
  .setup(instrumentationKey)
  .start();

  • Install npm install applicationinsights config mkdir config
  • Create a config directory within your project to store environment-specific configuration files.

mkdir config

Configure Application Insights

In your Azure portal, create an Application Insights resource if you haven't already. You'll need the instrumentation key for this resource.

Create Configuration Files

Inside the config directory, create two configuration files: development.json and production.json. Replace "YOUR_DEVELOPMENT_INSTRUMENTATION_KEY" and "YOUR_PRODUCTION_INSTRUMENTATION_KEY" with your actual instrumentation keys.

development.json

{

"appInsightsInstrumentationKey_development":  "key "

}
  • Run set NODE_ENV=development in bash and run the code.

In Layout cshtm for JS:

@{
    string instrumentationKey = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY");
}

<script type="text/javascript">
    !function (v, y, T) {
    
            };

            // Rest of your script here...

            function a() {
                T.onInit && T.onInit(n)
            }

            (v[t] = n).queue && 0 === n.queue.length ? (n.queue.push(a), n.trackPageView({})) : a()
        })(window, document, {
            src: "https://js.monitor.azure.com/scripts/b/ai.2.min.js",
            crossOrigin: "anonymous",
            cfg: {
                connectionString: "InstrumentationKey=" + @instrumentationKey + ";IngestionEndpoint=mydevappinsightingestionendpoint"
            }
        });

        window.appInsights = appInsights;
        appInsights.trackPageView();
        try {
            throw new Error("Logging Exception from Javascript");
        } catch (error) {
            appInsights.trackException("Logging Exception from Javascript.");
            appInsights.trackException({ error });
        }
    }(window, document, {});
</script>

enter image description here

Sign up to request clarification or add additional context in comments.

8 Comments

Hi Sampath, thank you for your detailed response. I was wondering can I not read appsetting value from azure app service or appsettings json directly in nlog config and in layout cshtml?
@Lucky If you define a value(or) application insights key in 'appsettings.json` it will be static like this example and to set dynamic targets that are environment-specific, you can go through the above steps for more information refer this link.
In my set up I will be having a dedicated app insight instance for my web app in every environment and so I will have environment specific app setting json files / azure app service
you set env in Azure app service like this configuration.template.json in example
I am using ASPNETCORE ENVIRONMENT for it so it can use the appropriate appsetting json... But my question is I need to refer appsetting value in nlog config. I am trying like this in layout ``` @using Microsoft.Extensions.Configuration @inject IConfiguration Configuration @Configuration.GetSection("ApplicationInsights")["ConnectionString"] ```
|
1

For Layout cshtml you can do the following:

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

connectionString: @Json.Serialize(Configuration.GetSection("ApplicationInsights")["ConnectionString"])

In my azure app service configuration, appsetting name is present in the following format: ApplicationInsights:ConnectionString and if reading from appsettings.json it should be in the following format:

"ApplicationInsights": {
    "ConnectionString": "your app insight connection string here"
  }

In Nlog config if you want to make the instrumentation key dynamic

${configsetting:item=ApplicationInsights.InstrumentationKey}

So your target will become:

<target name="aiTarget" xsi:type="ApplicationInsightsTarget"
     layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}">
      <instrumentationKey>${configsetting:item=ApplicationInsights.InstrumentationKey}</instrumentationKey>
      <contextproperty name="threadid" layout="${threadid}" />
    </target>

Again ensure the same set up for app service configuration or appsetting json as I have shown in layout cshtml solution, only difference you will have is InstrumentationKey instead of ConnectionString

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.