microsoft / ApplicationInsights-JS

Microsoft Application Insights SDK for JavaScript
MIT License
642 stars 236 forks source link

Multiple Application Insights with different connection strings using JavaScript(Web) SDK v3 giving warnings #2355

Open rubiks-cube opened 1 month ago

rubiks-cube commented 1 month ago

I am trying to have multiple Application Insights(vesrion 3) with different connection strings using JavaScript(Web) SDK Loader Script on the same HTML page. I have also given different name in the configuration. But I am getting in this warning in console:

Two extensions have same priority

WhatsApp Image 2024-05-28 at 6 22 55 PM

How can I fix this? or is there any different way to have multiple instances using loader script? In the docs, it is mentioned that we can use "name" if you need to initialize two different SDKs at the same time.

MSNev commented 1 month ago

The SDK loaded does not support loading / initializing (directly) multiple SDK instances as (by default) it will always set (and sometimes (race condition) replace the global appInsights instance).

So I suspect that the (not often used) config that will help with what you are trying to achieve is the name (https://github.com/microsoft/ApplicationInsights-JS/blob/1f3dee13cd3019b68a70f027eea8cbdadfb8484d/tools/applicationinsights-web-snippet/src/snippet-config.js#L3) configuration, this is the name of the global window.appInsights (by default) where the SDK instance is registered. It's also has some additional documentation in the table in this section https://github.com/microsoft/ApplicationInsights-JS?tab=readme-ov-file#reporting-script-load-exceptions

This will require 3 separate SDK Loader instances with the 3 separate SDK Loader configs, you can't do it with a single SDK Loader config. The other option is via npm where you can load the SDK code once (in your own bundle) and then initialize multiple instances.

rubiks-cube commented 1 month ago

I am already using the name property in the config and getting the issue as above. Loading 2 separate SDK configs using Script Loader separately with different name. I don't want to use npm package since I am not using any bundler.

MSNev commented 1 month ago

Hmm, that is a little odd, its sounding like the multiple versions are "sharing" the same config object and therefore as each one is initialized it keeps "adding" to the existing values.

By default, when the SDK initializes (for version 3+) it uses the "provided" config as a template and effective clones the objects / arrays (to avoid this exact issue) as internally it "adds" objects that are being listed as duplicates... The only time it doesn't do this is if the config has already been converted into a dynamic config (it's already undergone the initialization process)...

This is the code that uses the name config, and the sdk loader doesn't use the createDynamicConfig() so this (shouldn't) be occurring... I'll need to have someone investigate this a little more, however, the person I would get to do this is currently on Leave, so it might be a while before they get to it....

If you have some time if you could do some initial debugging that would be helpful, the issue sounds like it would revolve around the handling / initializing of the SDK. One simple approach (assuming the issue is not in the SDK loader itself) is that if you change the "src" to https://js.monitor.azure.com/scripts/b/ai.3.gbl.js this will use download and use the unminified version of the SDK (although the minified one also includes the map file which is publically available) and trace into the AppInsightsCore initialize function this should be the line of code that "clones" the config while this is where we "add" the standard extensions to the provided config (which is calling the AppInsightsCore config)

rubiks-cube commented 3 weeks ago

Any update on this issue?

siyuniu-ms commented 3 weeks ago

Hi @rubiks-cube, apologies for the delay - I've just returned from vacation and am taking a look at the issue now. Thank you for your patience!

siyuniu-ms commented 3 weeks ago

Hello @rubiks-cube, thank you for bringing this issue to our attention. We were able to reproduce the problem and have identified that it is caused by a race condition. To address this, we will be releasing a new version of the snippet and SDK. Please note that this solution will not support IE and Opera Mini. However, you won't need to make any changes on your end. Thank you for your patience as we work to resolve this issue.

rubiks-cube commented 3 weeks ago

@siyuniu-ms thanks for the update.

rubiks-cube commented 2 weeks ago

@siyuniu-ms I see v3.2.2 is released and through npm it is installing this latest version but script loader is still loading 3.2.1

siyuniu-ms commented 2 weeks ago

Hi, our cdn release (where our snippet live) will take around 5 days after our npm is released to make sure we didn't break anything.

rubiks-cube commented 1 week ago

any update on script loader v3.2.2? still it is fetching old version file.

siyuniu-ms commented 1 week ago

@rubiks-cube It would be released early next week. Thanks for waiting.

siyuniu-ms commented 6 days ago

@rubiks-cube Both snippet package and AI 3.2.2 CDN is published which contains the newest changes.

rubiks-cube commented 6 days ago

@siyuniu-ms I am still facing the above same issue of warnings with updated version and also onInitcallback function is getting called for the last appinisghts one only and not for every appInsights instance added by script loader in the html. Also there is another error I see in console: Screenshot 2024-06-25 024255

siyuniu-ms commented 6 days ago

Hi, could you provide more error details? I just did a local test with two snippet inited at the same time wtih two different ikey and both track message is delivered successfully.

siyuniu-ms commented 6 days ago

and below is my test code for reference

<!DOCTYPE html>

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>AISKU Sample</title>
    <link rel="stylesheet" href="style/style.css"/>
<script type="text/javascript">
!(function (cfg){function e(){cfg.onInit&&cfg.onInit(n)}var x,w,D,t,E,n,C=window,O=document,b=C.location,q="script",I="ingestionendpoint",L="disableExceptionTracking",j="ai.device.";"instrumentationKey"[x="toLowerCase"](),w="crossOrigin",D="POST",t="appInsightsSDK",E=cfg.name||"appInsights",(cfg.name||C[t])&&(C[t]=E),n=C[E]||function(g){var f=!1,m=!1,h={initialize:!0,queue:[],sv:"8",version:2,config:g};function v(e,t){var n={},i="Browser";function a(e){e=""+e;return 1===e.length?"0"+e:e}return n[j+"id"]=i[x](),n[j+"type"]=i,n["ai.operation.name"]=b&&b.pathname||"_unknown_",n["ai.internal.sdkVersion"]="javascript:snippet_"+(h.sv||h.version),{time:(i=new Date).getUTCFullYear()+"-"+a(1+i.getUTCMonth())+"-"+a(i.getUTCDate())+"T"+a(i.getUTCHours())+":"+a(i.getUTCMinutes())+":"+a(i.getUTCSeconds())+"."+(i.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}},ver:undefined,seq:"1",aiDataContract:undefined}}var n,i,t,a,y=-1,T=0,S=["js.monitor.azure.com","js.cdn.applicationinsights.io","js.cdn.monitor.azure.com","js0.cdn.applicationinsights.io","js0.cdn.monitor.azure.com","js2.cdn.applicationinsights.io","js2.cdn.monitor.azure.com","az416426.vo.msecnd.net"],o=g.url||cfg.src,r=function(){return s(o,null)};function s(d,t){if((n=navigator)&&(~(n=(n.userAgent||"").toLowerCase()).indexOf("msie")||~n.indexOf("trident/"))&&~d.indexOf("ai.3")&&(d=d.replace(/(\/)(ai\.3\.)([^\d]*)$/,function(e,t,n){return t+"ai.2"+n})),!1!==cfg.cr)for(var e=0;e<S.length;e++)if(0<d.indexOf(S[e])){y=e;break}var n,i=function(e){var a,t,n,i,o,r,s,c,u,l;h.queue=[],m||(0<=y&&T+1<S.length?(a=(y+T+1)%S.length,p(d.replace(/^(.*\/\/)([\w\.]*)(\/.*)$/,function(e,t,n,i){return t+S[a]+i})),T+=1):(f=m=!0,s=d,!0!==cfg.dle&&(c=(t=function(){var e,t={},n=g.connectionString;if(n)for(var i=n.split(";"),a=0;a<i.length;a++){var o=i[a].split("=");2===o.length&&(t[o[0][x]()]=o[1])}return t[I]||(e=(n=t.endpointsuffix)?t.location:null,t[I]="https://"+(e?e+".":"")+"dc."+(n||"services.visualstudio.com")),t}()).instrumentationkey||g.instrumentationKey||"",t=(t=(t=t[I])&&"/"===t.slice(-1)?t.slice(0,-1):t)?t+"/v2/track":g.endpointUrl,t=g.userOverrideEndpointUrl||t,(n=[]).push((i="SDK LOAD Failure: Failed to load Application Insights SDK script (See stack for details)",o=s,u=t,(l=(r=v(c,"Exception")).data).baseType="ExceptionData",l.baseData.exceptions=[{typeName:"SDKLoadFailed",message:i.replace(/\./g,"-"),hasFullStack:!1,stack:i+"\nSnippet failed to load ["+o+"] -- Telemetry is disabled\nHelp Link: https://go.microsoft.com/fwlink/?linkid=2128109\nHost: "+(b&&b.pathname||"_unknown_")+"\nEndpoint: "+u,parsedStack:[]}],r)),n.push((l=s,i=t,(u=(o=v(c,"Message")).data).baseType="MessageData",(r=u.baseData).message='AI (Internal): 99 message:"'+("SDK LOAD Failure: Failed to load Application Insights SDK script (See stack for details) ("+l+")").replace(/\"/g,"")+'"',r.properties={endpoint:i},o)),s=n,c=t,JSON&&((u=C.fetch)&&!cfg.useXhr?u(c,{method:D,body:JSON.stringify(s),mode:"cors"}):XMLHttpRequest&&((l=new XMLHttpRequest).open(D,c),l.setRequestHeader("Content-type","application/json"),l.send(JSON.stringify(s)))))))},a=function(e,t){m||setTimeout(function(){!t&&h.core||i()},500),f=!1},p=function(e){var n=O.createElement(q),e=(n.src=e,t&&(n.integrity=t),n.setAttribute("data-ai-name",E),cfg[w]);return!e&&""!==e||"undefined"==n[w]||(n[w]=e),n.onload=a,n.onerror=i,n.onreadystatechange=function(e,t){"loaded"!==n.readyState&&"complete"!==n.readyState||a(0,t)},cfg.ld&&cfg.ld<0?O.getElementsByTagName("head")[0].appendChild(n):setTimeout(function(){O.getElementsByTagName(q)[0].parentNode.appendChild(n)},cfg.ld||0),n};p(d)}cfg.sri&&(n=o.match(/^((http[s]?:\/\/.*\/)\w+(\.\d+){1,5})\.(([\w]+\.){0,2}js)$/))&&6===n.length?(d="".concat(n[1],".integrity.json"),i="@".concat(n[4]),l=window.fetch,t=function(e){if(!e.ext||!e.ext[i]||!e.ext[i].file)throw Error("Error Loading JSON response");var t=e.ext[i].integrity||null;s(o=n[2]+e.ext[i].file,t)},l&&!cfg.useXhr?l(d,{method:"GET",mode:"cors"}).then(function(e){return e.json()["catch"](function(){return{}})}).then(t)["catch"](r):XMLHttpRequest&&((a=new XMLHttpRequest).open("GET",d),a.onreadystatechange=function(){if(a.readyState===XMLHttpRequest.DONE)if(200===a.status)try{t(JSON.parse(a.responseText))}catch(e){r()}else r()},a.send())):o&&r();try{h.cookie=O.cookie}catch(k){}function e(e){for(;e.length;)!function(t){h[t]=function(){var e=arguments;f||h.queue.push(function(){h[t].apply(h,e)})}}(e.pop())}var c,u,l="track",d="TrackPage",p="TrackEvent",l=(e([l+"Event",l+"PageView",l+"Exception",l+"Trace",l+"DependencyData",l+"Metric",l+"PageViewPerformance","start"+d,"stop"+d,"start"+p,"stop"+p,"addTelemetryInitializer","setAuthenticatedUserContext","clearAuthenticatedUserContext","flush"]),h.SeverityLevel={Verbose:0,Information:1,Warning:2,Error:3,Critical:4},(g.extensionConfig||{}).ApplicationInsightsAnalytics||{});return!0!==g[L]&&!0!==l[L]&&(e(["_"+(c="onerror")]),u=C[c],C[c]=function(e,t,n,i,a){var o=u&&u(e,t,n,i,a);return!0!==o&&h["_"+c]({message:e,url:t,lineNumber:n,columnNumber:i,error:a,evt:C.event}),o},g.autoExceptionInstrumented=!0),h}(cfg.cfg),(C[E]=n).queue&&0===n.queue.length?(n.queue.push(e),n.trackPageView({})):e();})({
    src: "https://js.monitor.azure.com/scripts/b/ai.3.gbl.min.js",
    name: "appInsights",
    crossOrigin: "anonymous", // When supplied this will add the provided value as the cross origin attribute on the script tag
    sri: true, // Custom optional value to specify whether fetching the snippet from integrity file and do integrity check 
    cfg: { // Application Insights Configuration
        connectionString: ""
    }
});
  </script>
  <script type="text/javascript">
    !(function (cfg){function e(){cfg.onInit&&cfg.onInit(n)}var x,w,D,t,E,n,C=window,O=document,b=C.location,q="script",I="ingestionendpoint",L="disableExceptionTracking",j="ai.device.";"instrumentationKey"[x="toLowerCase"](),w="crossOrigin",D="POST",t="appInsightsSDK",E=cfg.name||"appInsights",(cfg.name||C[t])&&(C[t]=E),n=C[E]||function(g){var f=!1,m=!1,h={initialize:!0,queue:[],sv:"8",version:2,config:g};function v(e,t){var n={},i="Browser";function a(e){e=""+e;return 1===e.length?"0"+e:e}return n[j+"id"]=i[x](),n[j+"type"]=i,n["ai.operation.name"]=b&&b.pathname||"_unknown_",n["ai.internal.sdkVersion"]="javascript:snippet_"+(h.sv||h.version),{time:(i=new Date).getUTCFullYear()+"-"+a(1+i.getUTCMonth())+"-"+a(i.getUTCDate())+"T"+a(i.getUTCHours())+":"+a(i.getUTCMinutes())+":"+a(i.getUTCSeconds())+"."+(i.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}},ver:undefined,seq:"1",aiDataContract:undefined}}var n,i,t,a,y=-1,T=0,S=["js.monitor.azure.com","js.cdn.applicationinsights.io","js.cdn.monitor.azure.com","js0.cdn.applicationinsights.io","js0.cdn.monitor.azure.com","js2.cdn.applicationinsights.io","js2.cdn.monitor.azure.com","az416426.vo.msecnd.net"],o=g.url||cfg.src,r=function(){return s(o,null)};function s(d,t){if((n=navigator)&&(~(n=(n.userAgent||"").toLowerCase()).indexOf("msie")||~n.indexOf("trident/"))&&~d.indexOf("ai.3")&&(d=d.replace(/(\/)(ai\.3\.)([^\d]*)$/,function(e,t,n){return t+"ai.2"+n})),!1!==cfg.cr)for(var e=0;e<S.length;e++)if(0<d.indexOf(S[e])){y=e;break}var n,i=function(e){var a,t,n,i,o,r,s,c,u,l;h.queue=[],m||(0<=y&&T+1<S.length?(a=(y+T+1)%S.length,p(d.replace(/^(.*\/\/)([\w\.]*)(\/.*)$/,function(e,t,n,i){return t+S[a]+i})),T+=1):(f=m=!0,s=d,!0!==cfg.dle&&(c=(t=function(){var e,t={},n=g.connectionString;if(n)for(var i=n.split(";"),a=0;a<i.length;a++){var o=i[a].split("=");2===o.length&&(t[o[0][x]()]=o[1])}return t[I]||(e=(n=t.endpointsuffix)?t.location:null,t[I]="https://"+(e?e+".":"")+"dc."+(n||"services.visualstudio.com")),t}()).instrumentationkey||g.instrumentationKey||"",t=(t=(t=t[I])&&"/"===t.slice(-1)?t.slice(0,-1):t)?t+"/v2/track":g.endpointUrl,t=g.userOverrideEndpointUrl||t,(n=[]).push((i="SDK LOAD Failure: Failed to load Application Insights SDK script (See stack for details)",o=s,u=t,(l=(r=v(c,"Exception")).data).baseType="ExceptionData",l.baseData.exceptions=[{typeName:"SDKLoadFailed",message:i.replace(/\./g,"-"),hasFullStack:!1,stack:i+"\nSnippet failed to load ["+o+"] -- Telemetry is disabled\nHelp Link: https://go.microsoft.com/fwlink/?linkid=2128109\nHost: "+(b&&b.pathname||"_unknown_")+"\nEndpoint: "+u,parsedStack:[]}],r)),n.push((l=s,i=t,(u=(o=v(c,"Message")).data).baseType="MessageData",(r=u.baseData).message='AI (Internal): 99 message:"'+("SDK LOAD Failure: Failed to load Application Insights SDK script (See stack for details) ("+l+")").replace(/\"/g,"")+'"',r.properties={endpoint:i},o)),s=n,c=t,JSON&&((u=C.fetch)&&!cfg.useXhr?u(c,{method:D,body:JSON.stringify(s),mode:"cors"}):XMLHttpRequest&&((l=new XMLHttpRequest).open(D,c),l.setRequestHeader("Content-type","application/json"),l.send(JSON.stringify(s)))))))},a=function(e,t){m||setTimeout(function(){!t&&h.core||i()},500),f=!1},p=function(e){var n=O.createElement(q),e=(n.src=e,t&&(n.integrity=t),n.setAttribute("data-ai-name",E),cfg[w]);return!e&&""!==e||"undefined"==n[w]||(n[w]=e),n.onload=a,n.onerror=i,n.onreadystatechange=function(e,t){"loaded"!==n.readyState&&"complete"!==n.readyState||a(0,t)},cfg.ld&&cfg.ld<0?O.getElementsByTagName("head")[0].appendChild(n):setTimeout(function(){O.getElementsByTagName(q)[0].parentNode.appendChild(n)},cfg.ld||0),n};p(d)}cfg.sri&&(n=o.match(/^((http[s]?:\/\/.*\/)\w+(\.\d+){1,5})\.(([\w]+\.){0,2}js)$/))&&6===n.length?(d="".concat(n[1],".integrity.json"),i="@".concat(n[4]),l=window.fetch,t=function(e){if(!e.ext||!e.ext[i]||!e.ext[i].file)throw Error("Error Loading JSON response");var t=e.ext[i].integrity||null;s(o=n[2]+e.ext[i].file,t)},l&&!cfg.useXhr?l(d,{method:"GET",mode:"cors"}).then(function(e){return e.json()["catch"](function(){return{}})}).then(t)["catch"](r):XMLHttpRequest&&((a=new XMLHttpRequest).open("GET",d),a.onreadystatechange=function(){if(a.readyState===XMLHttpRequest.DONE)if(200===a.status)try{t(JSON.parse(a.responseText))}catch(e){r()}else r()},a.send())):o&&r();try{h.cookie=O.cookie}catch(k){}function e(e){for(;e.length;)!function(t){h[t]=function(){var e=arguments;f||h.queue.push(function(){h[t].apply(h,e)})}}(e.pop())}var c,u,l="track",d="TrackPage",p="TrackEvent",l=(e([l+"Event",l+"PageView",l+"Exception",l+"Trace",l+"DependencyData",l+"Metric",l+"PageViewPerformance","start"+d,"stop"+d,"start"+p,"stop"+p,"addTelemetryInitializer","setAuthenticatedUserContext","clearAuthenticatedUserContext","flush"]),h.SeverityLevel={Verbose:0,Information:1,Warning:2,Error:3,Critical:4},(g.extensionConfig||{}).ApplicationInsightsAnalytics||{});return!0!==g[L]&&!0!==l[L]&&(e(["_"+(c="onerror")]),u=C[c],C[c]=function(e,t,n,i,a){var o=u&&u(e,t,n,i,a);return!0!==o&&h["_"+c]({message:e,url:t,lineNumber:n,columnNumber:i,error:a,evt:C.event}),o},g.autoExceptionInstrumented=!0),h}(cfg.cfg),(C[E]=n).queue&&0===n.queue.length?(n.queue.push(e),n.trackPageView({})):e();})({
        src: "https://js.monitor.azure.com/scripts/b/ai.3.gbl.min.js",
        name: "appInsights2",
        crossOrigin: "anonymous", // When supplied this will add the provided value as the cross origin attribute on the script tag
        sri: true, // Custom optional value to specify whether fetching the snippet from integrity file and do integrity check 
        cfg: { // Application Insights Configuration
          connectionString: ""
        }
    });
      </script>
  </head>
  <body>
    <h1>Microsoft Application Insights JavaScript SDK - AISKU</h1>
    <script>
      let appInsights = new ApplicationInsights.ApplicationInsights({ config: {connectionString: "InstrumentationKey=88888888", disableInstrumentationKeyValidation: true}});
      appInsights.loadAppInsights();
      window.appInsights = appInsights;
    </script>
  </body>
</html>
MSNev commented 6 days ago

For some context, you will need both the new version "8" (see "sv": "8") of the SDK Loader AND version 3.2.2 of the SDK, if either version does not match (or greater) then the identifed race condition causing SDK A to use Loader B and Vica-versa configuration may still occur. This is because v3.2.2 is now (optionally) using the data-tag to identify the "global" instance name (this also requires that you runtime supports the document.currentScript (as this is what it uses to get access to any passed attribute on the script tag). And only v8 onwards will add this new data attribute to the script tag.

rubiks-cube commented 6 days ago

The script loader mentioned in docs is different : Script Loader. Using the above snippet doesn't have this issue.

MSNev commented 6 days ago

Yeah, not all of the documentation has been updated yet, it is included on the main readme https://github.com/microsoft/ApplicationInsights-JS/blob/main/tools/grunt-tasks/minifyNames.js and it is included in v1.2.0 of the web-snippet package https://www.npmjs.com/package/@microsoft/applicationinsights-web-snippet (which we published on friday)