Skip to content

Commit

Permalink
Update snippet to support reporting script load failures
Browse files Browse the repository at this point in the history
- New Snippet Setup pollutes the global namespace (window) #974
  • Loading branch information
Nev Wylie committed Apr 22, 2020
1 parent 0271cda commit c9be850
Show file tree
Hide file tree
Showing 7 changed files with 365 additions and 145 deletions.
394 changes: 296 additions & 98 deletions AISKU/snippet/snippet.js

Large diffs are not rendered by default.

13 changes: 8 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
22 changes: 17 additions & 5 deletions README.md
Expand Up @@ -59,14 +59,26 @@ 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(v,T,y){var S=v.location,k="script",C="instrumentationKey",D="ingestionendpoint",E="disableExceptionTracking",I="ai.device.",b="toLowerCase",N="POST",e="appInsightsSDK",t=y.name||"appInsights";(y.name||v[e])&&(v[e]=t);var n=v[t]||function(u){var d=!1,g=!1,f={initialize:!0,queue:[],snipVer:3,version:2,config:u};function m(e,t){var n={},a="Browser";return n[I+"id"]=a[b](),n[I+"type"]=a,n["ai.operation.name"]=S&&S.pathname||"_unknown_",n["ai.internal.sdkVersion"]="javascript:snippet_"+(f.snipVer||f.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 n,h=u.url||y.src;if(h){function a(e){var t,n,a,i,r,o,s,c,p,l;d=!0,f.queue=[],g||(g=!0,t=h,o=function(){var e={},t=u.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[D]){var r=e.endpointsuffix,o=r?e.location:null;e[D]="https://"+(o?o+".":"")+"dc."+(r||"services.visualstudio.com")}return e}(),s=o[C]||u[C]||"",c=o[D],p=c?c+"/v2/track":config.endpointUrl,(l=[]).push((n="SDK LOAD Failure: Failed to load App Insights Sdk script (See stack for details)",a=t,(r=(i=m(s,"Exception")).data).baseType="ExceptionData",r.baseData.exceptions=[{typeName:"ScriptLoadFailed",message:n.replace(/\./g,"-"),hasFullStack:!1,stack:n+"\nSnippet failed to load ["+a+"] -- Telemetry is disabled\nHelp Link: https://aka.ms/<TBD>\nHost: "+(S&&S.pathname||"_unknown_"),parsedStack:[]}],i)),l.push(function(e,t,n){var a=m(s,"Message"),i=a.data;i.baseType="MessageData";var r=i.baseData;return r.message='AI (Internal): 99 message:"'+("SDK LOAD Failure: Failed to load App Insights Sdk script (See stack for details) ("+n+")").replace(/\"/g,"")+'"',r.properties={},a}(0,0,t)),function(e,t){if(JSON){var n=v.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){g||setTimeout(function(){!t&&f.core||a()},500)}var e=((n=T.createElement(k)).src=h,n.onload=i,n.onerror=a,n.onreadystatechange=function(e,t){"loaded"!==n.readyState&&"complete"!==n.readyState||i(0,t)},n);y.ld<0?T.getElementsByTagName("head")[0].appendChild(e):setTimeout(function(){T.getElementsByTagName(k)[0].parentNode.appendChild(e)},y.ld||0)}try{f.cookie=T.cookie}catch(l){}function t(e){for(;e.length;){var t=e.pop();f[t]=function(){var e=arguments;d||f.queue.push(function(){f[t].apply(f,e)})}}}var r="track",o="TrackPage",s="TrackEvent";t([r+"Event",r+"PageView",r+"Exception",r+"Trace",r+"DependencyData",r+"Metric",r+"PageViewPerformance","start"+o,"stop"+o,"start"+s,"stop"+s,"addTelemetryInitializer","setAuthenticatedUserContext","clearAuthenticatedUserContext","flush"]),f.SeverityLevel={Verbose:0,Information:1,Warning:2,Error:3,Critical:4};var c=(u.extensionConfig||{}).ApplicationInsightsAnalytics||{};if(!0!==u[E]&&!0!==c[E]){method="onerror",t(["_"+method]);var p=v[method];v[method]=function(e,t,n,a,i){var r=p&&p(e,t,n,a,i);return!0!==r&&f["_"+method]({message:e,url:t,lineNumber:n,columnNumber:a,error:i}),r},u.autoExceptionInstrumented=!0}return f}(y.cfg);(v[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)
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.
- 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
63 changes: 29 additions & 34 deletions common/config/rush/npm-shrinkwrap.json

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

0 comments on commit c9be850

Please sign in to comment.