IvanJosipovic / BlazorApplicationInsights

Application Insights for Blazor web applications

Home Page:https://BlazorApplicationInsights.netlify.app

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Feature Request: Allow for getting Connection String from Config

kingua opened this issue · comments

Are there any plans to allow getting the connection string / intstrumentation key from appsettings.json?

It looks like up through version 1.6 this was supported, but has since been removed in favor of using a cookie.

Great work on this!

I have no plans on supporting this feature as it had a number of bugs. When we set the connection string programmatically, parts of App Insights fail.

Okay. Thanks for the quick reply! Hopefully we can find a way to do this in the future, or MS will start officially supporting AI with WASM :)

I pondered about this too. We are using a self hosted Blazor WASM app in an Azure App Service, and I'm not aware of any easy way to set the cookie as suggested.

Blazor WASM apps can have an appsettings.json in wwwroot, and it's easy to set the value as part of the deployment. This is my suggestion:

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

    fetch('appsettings.json').then(response => {
        if (!response.ok) {
            throw ('HTTP: Error getting appsettings.')
        }
        return response.json();
    }).then(appSettings => {
        const connectionString = appSettings?.ApplicationInsightsOptions?.ConnectionString;
        if (connectionString) {
            initAppInsights(window, document, {
                src: "https://js.monitor.azure.com/scripts/b/ai.2.min.js",
                ld: -1,
                crossOrigin: "anonymous",
                cfg: {
                    connectionString,
                    enableCorsCorrelation: true,
                    enableRequestHeaderTracking: true,
                    enableResponseHeaderTracking: true
                }
            })
        }
    });
</script>
- job: deploy
    displayName: Deploy
    dependsOn: manual_approval
    variables:
      ApplicationInsightsOptions.ConnectionString: '...' <-------
    steps:
    - download: current
      artifact: Foo
    - task: AzureRmWebAppDeployment@4
      displayName: 'Deploy client'
      inputs:
        ConnectionType: 'AzureRM'
        azureSubscription: '...'
        appType: 'webApp'
        WebAppName: '...'
        deployToSlotOrASE: true
        slotName: 'stageslot'
        ResourceGroupName: '...'
        package: $(Pipeline.Workspace)/**/Foo.zip
        JSONFiles: '**/appsettings.json' <-------

I'm using Azure Static Web app. @paulinfrancis solution works but It would be great to be able to obtain the connection string depending on the environment. That is, by specifying it in appsettings.json, appsettings.Production.json, etc

Read through this thread, if someone can find a fix, I'll happily implement it.

#90

Due to the way Blazor works a few issues occur when you set connection string in Blazor:

  • Initial dependency requests are not tracked (Not the end of the world)
  • Http Tracking does not work

I would highly suggest updating the connection string in the html using a CI/CD pipeline.

Following @IvanJosipovic recommendation this works for replacing the connection string in the html when deploying on a specific environment (GitHub actions with environments example):

...
jobs:
  name: deploy
  runs-on: ubuntu-latest
    environment:
      name: your-environment
    ...
   steps:
      ...
      - name: Set Application Insights Instrumentation Key
        run: |
          sed -i "s/InstrumentationKey=[^;]*;/InstrumentationKey=${{ secrets.APPINSIGHTS_INSTRUMENTATIONKEY }};/g" wwwroot/index.html
      ...

This feature is now supported in v3.