ApplicationInsights-JS
ApplicationInsights-JS copied to clipboard
Correlation of PageView with Requests, ASP.NET Framework
Hi,
I am trying to correlate ASP.NET requests with the page view (not ajax calls) as per the last scenario in this blog post
https://apmtips.com/posts/2017-05-11-page-view-and-telemetry-correlation/
I am using the latest Javascript snippet for injecting the AppInsights into my page.
!function(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()}(window,document,{
src: "https://js.monitor.azure.com/scripts/b/ai.2.min.js",
// 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,
crossOrigin: "anonymous", // When supplied this will add the provided value as the cross origin attribute on the script tag
// onInit: null, // Once the application insights instance has loaded and initialized this callback function will be called with 1 argument -- the sdk instance (DO NOT ADD anything to the sdk.queue -- As they won't get called)
cfg: { // Application Insights Configuration
instrumentationKey: '@Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.Active.InstrumentationKey',
disableAjaxTracking: false,
disableCorrelationHeaders: false,
disableFetchTracking: false,
distributedTracingMode: 2,
enableCorsCorrelation: true,
enableRequestHeaderTracking: true,
enableResponseHeaderTracking: true,
correlationHeaderExcludedDomains: ['*.azurewebsites.net', '*.queue.core.windows.net']
}
});
window.appInsights = appInsights; window.appInsights.queue.push(function () { var serverId = '@this.Context.GetRequestTelemetry().Context.Operation.Id'; appInsights.context.operation.id = serverId; });
window.appInsights.trackPageView();
If I do an inspect page source, I can see that the serverId is being set to operation id of the request (validated in App Insights Log).
However when the page view metrics are being tracked in the logs, the operation id and parent id are unique values and do not correlate with the original request, which was the intent.
Any insights on where I have gone wrong would be appreciated.
I'm having a similar issue. Unless my memory is tricking me, this used to work, but then it broke a few versions ago.
appInsights.context.operation.id is from v1 of the since v2 this is how its done https://docs.microsoft.com/en-us/azure/azure-monitor/app/javascript?tabs=snippet#advanced-correlation
appInsights.context.telemetryContext.parentID
I had seen this information, however (and this may be a bug) but when adding a callback of
onInit: function(appInsights) {
var serverId = "@this.Context.GetRequestTelemetry().Context.Operation.Id";
appInsights.context.telemetryContext.parentID = serverId;
},
The later call : window.appInsights.trackPageView(); now fails with no visible error message and no page views then recorded in the App Insights tables.
Hmm, it shouldn't... (but I guess you know that part already). Can you supply a sample value of what the serverId value is, so that I can try for a more exact repro... I've not tried to create a repro yet.
Here is the configuration part of the snippet upto trackPageView, I removed my Instrumentation Key.
src: "https://js.monitor.azure.com/scripts/b/ai.2.min.js", // 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, crossOrigin: "anonymous", // When supplied this will add the provided value as the cross origin attribute on the script tag onInit: function(appInsights) { var serverId = '4f3cb91815455940b3e99bc63da7bb2d'; window.appInsights.context.telemetryContext.parentID = serverId; }, cfg: { // Application Insights Configuration instrumentationKey: '<Insturmentation Key Here>', disableAjaxTracking: false, disableCorrelationHeaders: false, disableFetchTracking: false, distributedTracingMode: 2, enableCorsCorrelation: true, enableRequestHeaderTracking: true, enableResponseHeaderTracking: true, correlationHeaderExcludedDomains: ['.azurewebsites.net', '.queue.core.windows.net'] } }); window.appInsights = appInsights;
var appInsightsUserName = '[email protected]';
window.appInsights.setAuthenticatedUserContext(appInsightsUserName.replace(/[,;=| ]+/g, "_"));
window.appInsights.trackPageView();
The serverId corresponds to the operation_ParentId of the request.
Ok, finally managed to repro and trace this issue down, there are a couple of issues
One of which is that the documentation on MS Docs has a bug, so starting there.
This bit
onInit: function(appInsights) {
var serverId = "@this.Context.GetRequestTelemetry().Context.Operation.Id";
appInsights.context.telemetryContext.parentID = serverId;
},
Should be
onInit: function(appInsights) {
var serverId = "@this.Context.GetRequestTelemetry().Context.Operation.Id";
appInsights.context.telemetryTrace.parentID = serverId;
},
Because the appInsights.context.telemetryContext is undefined it throws.
The other issue, is that it looks like you are setting window.appInsights = appInsights; directly after the snippet, this has 2 issues
- The new snippet doesn't actually return the instance, so this "clears" the
window.appinsightsinstance which then stops the SDK from actually initializing and causes an exception (SDK could not be loaded)
I used this and I'm seeing 2 PageView events (this is because the snippet actually call pageView internally -- so you don't need to), but it does mean that you should be "setting" the authenticated user context within the onInit as well
<script type="text/javascript">
!function(T,l,y){var /* ... truncated ... */ }(window,document,{
src: "https://js.monitor.azure.com/scripts/b/ai.2.js",
// 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,
crossOrigin: "anonymous", // When supplied this will add the provided value as the cross origin attribute on the script tag
onInit: function(appInsights) {
var serverId = '4f3cb91815455940b3e99bc63da7bb2d';
appInsights.context.telemetryTrace.parentID = serverId;
},
cfg: { // Application Insights Configuration
instrumentationKey: '',
disableAjaxTracking: false,
disableCorrelationHeaders: false,
disableFetchTracking: false,
distributedTracingMode: 2,
enableCorsCorrelation: true,
enableRequestHeaderTracking: true,
enableResponseHeaderTracking: true,
correlationHeaderExcludedDomains: ['.azurewebsites.net', '.queue.core.windows.net']
}});
var appInsightsUserName = '[email protected]';
window.appInsights.setAuthenticatedUserContext(appInsightsUserName.replace(/[,;=| ]+/g, "_"));
window.appInsights.trackPageView();
</script>
I've raised an internal task to get the advanced correlation docs fixed and will close this issue (assuming there is nothing else) once the documentation is fixed and deployed.
@MSNev Thank you for taking the time, but what I am trying to achieve may not be possible, or other pieces of the documentation could also be inadvertently incorrect.
I was trying to be able to query, for the request with all dependencies and the resulting page view. This is not a SPA.
onInit: function (appInsights) { appInsights.context.telemetryTrace.parentID = "@this.Context.GetRequestTelemetry().Id"; appInsights.context.telemetryTrace.operationID = "@this.Context.GetRequestTelemetry().Context.Operation.Id"; },
Using the above onInit, thank you for pointing out the other incorrections I had noticed the duplicate page tracks, I get the following in the logs.
Request id = 3384f1a61681af4a operation_id = 0a04ff382eefe34c988eb7d58ba8725b operation_parent_id = 0a04ff382eefe34c988eb7d58ba8725b
dependancy id = 5574c142fb688141 operation_id = 0a04ff382eefe34c988eb7d58ba8725b operation_parent_id = 3384f1a61681af4a
pageView id = 48e47877827844a8b4b0f52f5024b29d operation_id = 48e47877827844a8b4b0f52f5024b29d operation_parent_id = 3384f1a61681af4a
Notice the pageView, whilst now haveing the correct parent_Id the operation_id is overridden to the the same as the id. This is different to the request dependancies.
So does this mean, using a single query (sample below) I am unable to get the request, dependancies AND pageView?
(requests | union dependencies | union pageViews) | where operation_Id == "0a04ff382eefe34c988eb7d58ba8725b" | project timestamp, itemType, name, id, operation_ParentId, operation_Id | order by timestamp asc
appInsights.context.telemetryTrace.operationID is not a value that is referenced in the code, so therefore it's not populated in the event. This is the telemetryTrace object and for the 'ai.operation.id' tag this is populated from the traceID, so if you want the same value then setting that instead of operationID (I think) is what you are look for.
Another way would be to use a telemetryInitializer which is a callback function that lets you add / change fields for an event and even stop the event from being sent (by returning false) https://github.com/microsoft/ApplicationInsights-JS#telemetry-initializers
Ok, thank you for the help and advice. For anyone else, I cannot be the only person who wants to correlate in this way.
To correlate Request, Dependencies, PageView from the App Insights log here is the onInit function that works for me.
onInit: function (appInsights) { appInsights.context.telemetryTrace.parentID = "@this.Context.GetRequestTelemetry().Id"; var telemetryInitializer = (envelope) => { envelope.tags["ai.operation.id"] = "@this.Context.GetRequestTelemetry().Context.Operation.Id"; } appInsights.addTelemetryInitializer(telemetryInitializer); },
Then this query, with the relevant operation Id, returns back all of the calls made from requests all dependancies and finally the pageView.
(requests | union dependencies | union pageViews) | where operation_Id == "b4b609757e6ddb4f9456ec881f5771f4" | project timestamp, itemType, name, id, operation_ParentId, operation_Id | order by timestamp asc