Skip to content

Commit

Permalink
Update snippet to support reporting script load failures (#1258)
Browse files Browse the repository at this point in the history
- New Snippet Setup pollutes the global namespace (window) #974
  • Loading branch information
MSNev committed May 1, 2020
1 parent 88cf8ed commit 5cb9e44
Show file tree
Hide file tree
Showing 9 changed files with 395 additions and 158 deletions.
405 changes: 307 additions & 98 deletions AISKU/snippet/snippet.js

Large diffs are not rendered by default.

14 changes: 9 additions & 5 deletions AISKU/snippet/snippet.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions AISKU/src/Init.ts
Expand Up @@ -34,8 +34,8 @@ try {
const snippet: Snippet = _window[aiName] || ({ version: 2.0 } as any);

// overwrite snippet with full appInsights
// for 2.0 initialize only if required
if ((snippet.version === 2.0 && (_window[aiName] as any).initialize) || snippet.version === undefined ) {
// only initiaize if required and detected snippet version is >= 2 or not defined
if ((snippet.version >= 2.0 && (_window[aiName] as any).initialize) || snippet.version === undefined ) {
ApplicationInsightsContainer.getAppInsights(snippet, snippet.version);
}
}
Expand Down
26 changes: 15 additions & 11 deletions AISKU/src/Initialization.ts
Expand Up @@ -433,6 +433,9 @@ export class Initialization implements IApplicationInsights {
(function () {
let sdkSrc = null;
let isModule = false;
let cdns: string[] = [
"://az416426.vo.msecnd.net/"
];

try {
// Try and determine whether the sdk is being loaded from the CDN
Expand All @@ -455,19 +458,20 @@ export class Initialization implements IApplicationInsights {
let url = sdkSrc.toLowerCase();
if (url) {
let src = "";
if (url.indexOf("://az416426.vo.msecnd.net/") !== -1) {
src = "cdn1";
if (url.indexOf("/scripts/") === -1) {
if (url.indexOf("/next/") !== -1) {
src += "-next";
} else if (url.indexOf("/beta/") !== -1) {
src += "-beta";
for (let idx = 0; idx < cdns.length; idx++) {
if (url.indexof(cdns[idx]) !== -1) {
src = "cdn" + (idx + 1);
if (url.indexOf("/scripts/") === -1) {
if (url.indexOf("/next/") !== -1) {
src += "-next";
} else if (url.indexOf("/beta/") !== -1) {
src += "-beta";
}
}
}
}

if (src) {
_internalSdkSrc = src + (isModule ? ".mod" : "");
_internalSdkSrc = src + (isModule ? ".mod" : "");
break;
}
}
}
} catch (e) {
Expand Down
24 changes: 19 additions & 5 deletions README.md
Expand Up @@ -59,14 +59,28 @@ If your app does not use NPM, you can directly instrument your webpages with App

```html
<script type="text/javascript">
var sdkInstance="appInsightsSDK";window[sdkInstance]="appInsights";var aiName=window[sdkInstance],aisdk=window[aiName]||function(n){var o={config:n,initialize:!0},t=document,e=window,i="script";setTimeout(function(){var e=t.createElement(i);e.src=n.url||"https://az416426.vo.msecnd.net/scripts/b/ai.2.min.js",t.getElementsByTagName(i)[0].parentNode.appendChild(e)});try{o.cookie=t.cookie}catch(e){}function a(n){o[n]=function(){var e=arguments;o.queue.push(function(){o[n].apply(o,e)})}}o.queue=[],o.version=2;for(var s=["Event","PageView","Exception","Trace","DependencyData","Metric","PageViewPerformance"];s.length;)a("track"+s.pop());var r="Track",c=r+"Page";a("start"+c),a("stop"+c);var u=r+"Event";if(a("start"+u),a("stop"+u),a("addTelemetryInitializer"),a("setAuthenticatedUserContext"),a("clearAuthenticatedUserContext"),a("flush"),o.SeverityLevel={Verbose:0,Information:1,Warning:2,Error:3,Critical:4},!(!0===n.disableExceptionTracking||n.extensionConfig&&n.extensionConfig.ApplicationInsightsAnalytics&&!0===n.extensionConfig.ApplicationInsightsAnalytics.disableExceptionTracking)){a("_"+(s="onerror"));var p=e[s];e[s]=function(e,n,t,i,a){var r=p&&p(e,n,t,i,a);return!0!==r&&o["_"+s]({message:e,url:n,lineNumber:t,columnNumber:i,error:a}),r},n.autoExceptionInstrumented=!0}return o}(
{
instrumentationKey:"INSTRUMENTATION_KEY"
}
);(window[aiName]=aisdk).queue&&0===aisdk.queue.length&&aisdk.trackPageView({});
!function(T,l,y){var S=T.location,u="script",k="instrumentationKey",D="ingestionendpoint",C="disableExceptionTracking",E="ai.device.",I="toLowerCase",b="crossOrigin",w="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:"3",version:2,config:d};function v(e,t){var n={},a="Browser";return n[E+"id"]=a[I](),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,p,l,u;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][I]()]=i[1])}if(!e[D]){var r=e.endpointsuffix,o=r?e.location:null;e[D]="https://"+(o?o+".":"")+"dc."+(r||"services.visualstudio.com")}return e}(),c=s[k]||d[k]||"",p=s[D],l=p?p+"/v2/track":config.endpointUrl,(u=[]).push((n="SDK LOAD Failure: Failed to load Application Insights SDK script (See stack for details)",a=t,i=l,(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)),u.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,l)),function(e,t){if(JSON){var n=T.fetch;if(n&&!y.useXhr)n(t,{method:w,body:JSON.stringify(e),mode:"cors"});else if(XMLHttpRequest){var a=new XMLHttpRequest;a.open(w,t),a.setRequestHeader("Content-type","application/json"),a.send(JSON.stringify(e))}}}(u,l))}function i(e,t){f||setTimeout(function(){!t&&m.core||a()},500)}var e=function(){var n=l.createElement(u);n.src=h;var e=y[b];return!e&&""!==e||"undefined"==n[b]||(n[b]=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(u)[0].parentNode.appendChild(e)},y.ld||0)}try{m.cookie=l.cookie}catch(p){}function t(e){for(;e.length;){var t=e.pop();m[t]=function(){var e=arguments;g||m.queue.push(function(){m[t].apply(m,e)})}}}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[C]&&!0!==s[C]){method="onerror",t(["_"+method]);var c=T[method];T[method]=function(e,t,n,a,i){var r=c&&c(e,t,n,a,i);return!0!==r&&m["_"+method]({message:e,url:t,lineNumber:n,columnNumber:a,error:i}),r},d.autoExceptionInstrumented=!0}return m}(y.cfg);(T[t]=n).queue&&0===n.queue.length&&n.trackPageView({})}(window,document,{
src: "https://az416426.vo.msecnd.net/scripts/b/ai.2.min.js", // The SDK URL Source
//name: "appInsights", // Global SDK Instance name defaults to "appInsights" when not supplied
//ld: 0, // Defines the load delay (in ms) before attempting to load the sdk. -1 = block page load and add to head. (default) = 0ms load after timeout,
//useXhr: 1, // Use XHR instead of fetch to report failures (if available),
//crossOrigin: "anonymous", // When supplied this will add the provided value as the cross origin attribute on the script tag
cfg: { // Application Insights Configuration
instrumentationKey: "INSTRUMENTATION_KEY"
}});
</script>
```

The snippet supports reporting sdk script load failures as exceptions to the portal, this type of error would cause your application/website to either not report any telemetry or in some extreme cases become unstable due to excessive queuing of events which are never sent.

It also supports some additional snippet specific configuration.
- src (string) [required] - The URL of the SDK version to load
- name (string) [optional] - The global SDK instance name to use, defaults to appInsights
- ld (number in ms) [optional] - Defines the load delay to wait before attempting to load the SDK. Default value is 0ms and any negative value will just add a script tag to the page head and will block the page load event.
- useXhr (boolean) [optional] - This setting is specifically for the reporting of SDK load failures. Reporting will first use fetch() if available and then fallback to XHR, setting this value to true just bypasses the fetch check. Use of this value would only be required if you know your app/site is being used in an environment where fetch would fail to send the failure events.
- crossOrigin (string) [optional] - By including this setting the script tag used to download the SDK will include the crossOrigin attribute with this string value. When not defined (the default) no crossOrigin attribute is added. Recommended values are not defined (the default); ""; or "anonymous" (For all valid values see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/crossorigin)
- cfg (object) - This is the Application Insights configuration that is used to initialize your sdk.

### Connection String Setup

For either the NPM or Snippet setup, you can also configure your instance of Application Insights using a Connection String. Simply replace the `instrumentationKey` field with the `connectionString` field.
Expand Down

0 comments on commit 5cb9e44

Please sign in to comment.