Skip to content

Commit

Permalink
[BUG] App Insights not auto-capturing from a Web Worker #1995
Browse files Browse the repository at this point in the history
  • Loading branch information
MSNev committed Feb 24, 2023
1 parent 2565ee3 commit 6f3edcf
Show file tree
Hide file tree
Showing 8 changed files with 418 additions and 392 deletions.
695 changes: 320 additions & 375 deletions common/config/rush/npm-shrinkwrap.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion examples/shared-worker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"devDependencies": {
"@microsoft/ai-test-framework": "0.0.1",
"@microsoft/applicationinsights-rollup-plugin-uglify3-js": "1.0.0",
"@microsoft/applicationinsights-rollup-es5": "1.0.0",
"@microsoft/applicationinsights-rollup-es3": "^1.1.3",
"grunt": "^1.5.3",
"grunt-cli": "^1.4.3",
"grunt-contrib-qunit": "^6.2.1",
Expand Down
6 changes: 3 additions & 3 deletions examples/shared-worker/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { uglify } from "@microsoft/applicationinsights-rollup-plugin-uglify3-js"
import replace from "@rollup/plugin-replace";
import cleanup from "rollup-plugin-cleanup";
import dynamicRemove from "@microsoft/dynamicproto-js/tools/rollup/node/removedynamic";
import { es5Poly, es5Check, importCheck } from "@microsoft/applicationinsights-rollup-es5";
import { es3Poly, es3Check, importCheck } from "@microsoft/applicationinsights-rollup-es3";
import { updateDistEsmFiles } from "../../tools/updateDistEsm/updateDistEsm";

const version = require("./package.json").version;
Expand Down Expand Up @@ -65,8 +65,8 @@ const browserRollupConfigFactory = (name, isProduction, format = "umd", extensio
preferBuiltins: false
}),
doCleanup(),
es5Poly(),
es5Check()
es3Poly(),
es3Check()
]
};

Expand Down
8 changes: 6 additions & 2 deletions examples/shared-worker/src/worker-npm-init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ let _appInsights: ApplicationInsights;
* @param config
* @returns
*/
export function initApplicationInsights(config: IConfiguration) {
export function initApplicationInsights(config: IConfiguration, onInitCallback: (appInsights: ApplicationInsights, port: MessagePort) => void, port: MessagePort) {

if (!_appInsights) {
// Make sure we have a configuration object
Expand All @@ -25,7 +25,11 @@ export function initApplicationInsights(config: IConfiguration) {
});

_appInsights.loadAppInsights();
_appInsights.trackPageView(); // Manually call trackPageView to establish the current user/session/pageview
if (_appInsights.core.isInitialized()) {
// Call the callback before the trackPageView
onInitCallback(_appInsights, port);
_appInsights.trackPageView(); // Manually call trackPageView to establish the current user/session/pageview
}

return _appInsights;
}
Expand Down
41 changes: 37 additions & 4 deletions examples/shared-worker/src/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import { initApplicationInsights, trackPageView, unloadApplicationInsights } from "./worker-npm-init";
import { ExampleMessageType, IExampleRequest, IExampleResponse } from "./interfaces/IExampleMessage";
import { IConfiguration, INotificationListener } from "@microsoft/applicationinsights-web";
import { ApplicationInsights, IConfiguration, INotificationListener } from "@microsoft/applicationinsights-web";
import { dumpObj, objAssign } from "@nevware21/ts-utils";

/**
Expand All @@ -12,7 +12,16 @@ import { dumpObj, objAssign } from "@nevware21/ts-utils";
* the connection string.
*/
const defaultApplicationInsightsConfig: IConfiguration = {

/**
* Telemtry logging level to instrumentation key. All logs with a severity
* level higher than the configured level will sent as telemetry data to
* the configured instrumentation key.
*
* 0: ALL iKey logging off
* 1: logs to iKey: severity >= CRITICAL
* 2: logs to iKey: severity >= WARNING
*/
loggingLevelTelemetry: 2
};

/**
Expand Down Expand Up @@ -91,6 +100,31 @@ function notificationListener(port: MessagePort): INotificationListener {
};
}

/**
* We only want to add any notification listener or telemetry initializer once
* otherwise they WILL get called multiple times during processing.
* @param appInsights
* @param port
*/
function onInitAddInitializers(appInsights: ApplicationInsights, port: MessagePort) {
// This callback is only called once, otherwise we would keep adding listeners and initializers
appInsights.core.getNotifyMgr().addNotificationListener(notificationListener(port));

// This is not normally needed, but this provides a view from the worker to the
// main page about errors that the worker is having / seeing
appInsights.addTelemetryInitializer((theEvent) => {
if (theEvent && theEvent.name && theEvent.name["startsWith"]("InternalMessageId") && theEvent.baseData) {
port.postMessage({
success: true,
message: "Internal Message: " + (theEvent.baseData?.message || "--")
});

// Drop ALL internal message from being sent to Azure Monitor portal
return false;
}
});
}

/**
* Initialize the SDK using the passed connection string from the request (if supplied)
* @param request
Expand All @@ -100,9 +134,8 @@ function notificationListener(port: MessagePort): INotificationListener {
function workerLoadSdk(request: IExampleRequest, port: MessagePort) {
let theConfig = objAssign({}, defaultApplicationInsightsConfig);
theConfig.connectionString = request.connectionString;
let appInsights = initApplicationInsights(theConfig);
let appInsights = initApplicationInsights(theConfig, onInitAddInitializers, port);
if (appInsights && appInsights.core.isInitialized()) {
appInsights.core.getNotifyMgr().addNotificationListener(notificationListener(port));
return {
success: true,
message: `SDK Loaded and Initialized with - ${appInsights.config.connectionString}`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,23 @@ import {
} from "@microsoft/applicationinsights-core-js";
import { PageViewPerformanceManager } from "./PageViewPerformanceManager";

declare let WorkerGlobalScope: any;
declare let self: any;

let _isWebWorker: boolean = null;

function isWebWorker() {
if (_isWebWorker == null) {
try {
_isWebWorker = !!(self && self instanceof WorkerGlobalScope);
} catch(e) {
_isWebWorker = false;
}
}

return _isWebWorker;
}

/**
* Internal interface to pass appInsights object to subcomponents without coupling
*/
Expand Down Expand Up @@ -99,11 +116,13 @@ export class PageViewManager {
);
_flushChannels(true);

// no navigation timing (IE 8, iOS Safari 8.4, Opera Mini 8 - see http://caniuse.com/#feat=nav-timing)
_throwInternal(_logger,
eLoggingSeverity.WARNING,
_eInternalMessageId.NavigationTimingNotSupported,
"trackPageView: navigation timing API used for calculation of page duration is not supported in this browser. This page view will be collected without duration and timing info.");
if (!isWebWorker()) {
// no navigation timing (IE 8, iOS Safari 8.4, Opera Mini 8 - see http://caniuse.com/#feat=nav-timing)
_throwInternal(_logger,
eLoggingSeverity.WARNING,
_eInternalMessageId.NavigationTimingNotSupported,
"trackPageView: navigation timing API used for calculation of page duration is not supported in this browser. This page view will be collected without duration and timing info.");
}

return;
}
Expand Down
19 changes: 18 additions & 1 deletion extensions/applicationinsights-dependencies-js/src/ajax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import {
} from "./DependencyListener";
import { IAjaxRecordResponse, ajaxRecord } from "./ajaxRecord";

declare let WorkerGlobalScope: any;
declare let self: any;

const AJAX_MONITOR_PREFIX = "ai.ajxmn.";
const strDiagLog = "diagLog";
const strAjaxData = "ajaxData";
Expand Down Expand Up @@ -54,6 +57,20 @@ function _supportsFetch(): (input: RequestInfo, init?: RequestInit) => Promise<R
return _global[STR_FETCH];
}

let _isWebWorker: boolean = null;

function isWebWorker() {
if (_isWebWorker == null) {
try {
_isWebWorker = !!(self && self instanceof WorkerGlobalScope);
} catch(e) {
_isWebWorker = false;
}
}

return _isWebWorker;
}

/**
* Determines whether ajax monitoring can be enabled on this document
* @returns True if Ajax monitoring is supported on this page, otherwise false
Expand Down Expand Up @@ -617,7 +634,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
// Create an error callback to report any hook errors
hkErr: _createErrorCallbackFunc(_self, _eInternalMessageId.FailedMonitorAjaxOpen,
"Failed to monitor Window.fetch" + ERROR_POSTFIX)
}));
}, true, isWebWorker()));

_fetchInitialized = true;
} else if (isPolyfill) {
Expand Down
10 changes: 9 additions & 1 deletion gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,12 @@ module.exports = function (grunt) {
path: "./extensions/applicationinsights-properties-js",
unitTestName: "prop.tests.js"
},

// Examples
"example-shared-worker": {
autoMinify: false,
path: "./examples/shared-worker",
testHttp: false
},
// Tools
"rollupuglify": {
autoMinify: false,
Expand Down Expand Up @@ -750,6 +755,9 @@ module.exports = function (grunt) {
grunt.registerTask("clickanalyticstests", tsTestActions("clickanalytics"));
grunt.registerTask("clickanalytics-mintests", tsTestActions("clickanalytics", true));

grunt.registerTask("example-shared-worker", tsBuildActions("example-shared-worker"));
grunt.registerTask("example-shared-worker-test", tsTestActions("example-shared-worker"));

grunt.registerTask("tst-framework", tsBuildActions("tst-framework"));
grunt.registerTask("serve", ["connect:server:keepalive"]);
} catch (e) {
Expand Down

0 comments on commit 6f3edcf

Please sign in to comment.