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.
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.