diff --git a/README.md b/README.md
index 42a27f182..8d1fa5329 100644
--- a/README.md
+++ b/README.md
@@ -396,6 +396,8 @@ Most configuration fields are named such that they can be defaulted to falsey. A
| featureOptIn
since 3.0.3 | IFeatureOptIn | undefined | [Optional] Set Feature opt in details. |
| throttleMgrCfg
since 3.0.3 | `{[key: number]: IThrottleMgrConfig}` | undefined | [Optional] Set throttle mgr configuration by key. |
| retryCodes | number[] | undefined | Identifies the status codes that will cause event batches to be resent, when `null` or `undefined` the SDK will use it's defaults `[401, 408, 429, 500, 502, 503, 504]`. `403` was removed in version 3.1.1. |
+| expCfg | [`IExceptionConfig`](https://github.com/microsoft/ApplicationInsights-JS/blob/main/shared/AppInsightsCommon/src/Interfaces/IExceptionTelemetry.ts) | undefined | Set additional configuration for exceptions, such as more scripts to include in the exception telemetry. |
+
### ExtensionConfig
diff --git a/channels/1ds-post-js/src/DataModels.ts b/channels/1ds-post-js/src/DataModels.ts
index 6ec624dfe..59483949c 100644
--- a/channels/1ds-post-js/src/DataModels.ts
+++ b/channels/1ds-post-js/src/DataModels.ts
@@ -256,7 +256,7 @@ export interface IChannelConfiguration {
* - "same-origin": only send and include credentials for same-origin requests.
*
* If not set, the default value will be "include".
- *
+ *
* For more information, refer to:
* - [Fetch API - Using Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#including_credentials)
* @since 3.3.1
diff --git a/extensions/applicationinsights-analytics-js/Tests/Unit/src/AnalyticsPlugin.tests.ts b/extensions/applicationinsights-analytics-js/Tests/Unit/src/AnalyticsPlugin.tests.ts
index 4528bf636..7c457d856 100644
--- a/extensions/applicationinsights-analytics-js/Tests/Unit/src/AnalyticsPlugin.tests.ts
+++ b/extensions/applicationinsights-analytics-js/Tests/Unit/src/AnalyticsPlugin.tests.ts
@@ -7,7 +7,7 @@ import {
Exception, SeverityLevel, Event, Trace, PageViewPerformance, IConfig, IExceptionInternal,
AnalyticsPluginIdentifier, IAppInsights, Metric, PageView, RemoteDependencyData, utlCanUseLocalStorage, createDomEvent
} from "@microsoft/applicationinsights-common";
-import { ITelemetryItem, AppInsightsCore, IPlugin, IConfiguration, IAppInsightsCore, setEnableEnvMocks, getLocation, dumpObj, __getRegisteredEvents, createCookieMgr } from "@microsoft/applicationinsights-core-js";
+import { ITelemetryItem, AppInsightsCore, IPlugin, IConfiguration, IAppInsightsCore, setEnableEnvMocks, getLocation, dumpObj, __getRegisteredEvents, createCookieMgr, findAllScripts } from "@microsoft/applicationinsights-core-js";
import { Sender } from "@microsoft/applicationinsights-channel-js"
import { PropertiesPlugin } from "@microsoft/applicationinsights-properties-js";
import { AnalyticsPlugin } from "../../../src/JavaScriptSDK/AnalyticsPlugin";
@@ -406,6 +406,76 @@ export class AnalyticsPluginTests extends AITestClass {
this.addOnErrorTests();
this.addTrackMetricTests();
this.addTelemetryInitializerTests();
+ this.addScriptInfoTests();
+ }
+
+ private addScriptInfoTests(): void {
+ this.testCase({
+ name: "AppInsightsTests: findAllScripts function returns correct information",
+ useFakeTimers: true,
+ test: () => {
+ // Initialize Application Insights core with plugins
+ let script = window.document.createElement("script");
+ script.src = "https://www.example.com/test.js";
+ script.innerHTML = 'test script';
+ window.document.body.appendChild(script);
+
+ let doc = window.document;
+ let scriptsInfo = findAllScripts(doc);
+ Assert.deepEqual(true, JSON.stringify(scriptsInfo).indexOf("https://www.example.com/test.js") !== -1, "script info contains the correct url");
+ }
+ });
+ this.testCase({
+ name: "AppInsightsTests: trackException would contain scrips info when config turns on",
+ useFakeTimers: true,
+ test: () => {
+ const appInsights = new AnalyticsPlugin();
+ const core = new AppInsightsCore();
+ const channel = new ChannelPlugin();
+ const properties = new PropertiesPlugin();
+ // Configuration
+ const config = {
+ instrumentationKey: 'ikey',
+ };
+ this.onDone(() => {
+ core.unload(false);
+ });
+ // Initialize Application Insights core with plugins
+ core.initialize(config, [appInsights, channel, properties]);
+
+ // add test script
+ let script = window.document.createElement("script");
+ script.src = "https://www.example1.com/test.js";
+ script.setAttribute("referrerpolicy", "no-referrer");
+ script.innerHTML = 'test script';
+ let script2 = window.document.createElement("script");
+ script2.src = "https://www.test.com/test.js";
+ script2.innerHTML = "test tests";
+ script2.setAttribute("async", "");
+ window.document.body.appendChild(script);
+ window.document.body.appendChild(script2);
+
+
+ const trackStub = this.sandbox.stub(appInsights.core, "track");
+ appInsights.trackException({error: new Error(), severityLevel: SeverityLevel.Critical});
+ Assert.ok(trackStub.calledOnce, "single exception is tracked");
+ const baseData = (trackStub.args[0][0] as ITelemetryItem).baseData as IExceptionInternal;
+ const prop = baseData.properties;
+ Assert.equal(-1, JSON.stringify(prop).indexOf("https://www.example.com/test.js"), "script info is not included");
+
+ appInsights.config.expCfg.inclScripts = true;
+ this.clock.tick(1);
+ appInsights.trackException({error: new Error(), severityLevel: SeverityLevel.Critical});
+ Assert.ok(trackStub.calledTwice, "single exception is tracked");
+ const baseData2 = (trackStub.args[1][0] as ITelemetryItem).baseData as IExceptionInternal;
+ const prop2 = baseData2.properties;
+ Assert.deepEqual(true, prop2["exceptionScripts"].includes('"url":"https://www.test.com/test.js","async":true}'))
+ Assert.deepEqual(true, prop2["exceptionScripts"].includes('"url":"https://www.example1.com/test.js","referrerPolicy":"no-referrer"'))
+
+ }
+ });
+
+
}
private addGenericTests(): void {
diff --git a/extensions/applicationinsights-analytics-js/src/JavaScriptSDK/AnalyticsPlugin.ts b/extensions/applicationinsights-analytics-js/src/JavaScriptSDK/AnalyticsPlugin.ts
index 6edfb95ed..2530e01b5 100644
--- a/extensions/applicationinsights-analytics-js/src/JavaScriptSDK/AnalyticsPlugin.ts
+++ b/extensions/applicationinsights-analytics-js/src/JavaScriptSDK/AnalyticsPlugin.ts
@@ -6,7 +6,7 @@
import dynamicProto from "@microsoft/dynamicproto-js";
import {
AnalyticsPluginIdentifier, Event as EventTelemetry, Exception, IAppInsights, IAutoExceptionTelemetry, IConfig, IDependencyTelemetry,
- IEventTelemetry, IExceptionInternal, IExceptionTelemetry, IMetricTelemetry, IPageViewPerformanceTelemetry,
+ IEventTelemetry, IExceptionConfig, IExceptionInternal, IExceptionTelemetry, IMetricTelemetry, IPageViewPerformanceTelemetry,
IPageViewPerformanceTelemetryInternal, IPageViewTelemetry, IPageViewTelemetryInternal, ITraceTelemetry, Metric, PageView,
PageViewPerformance, PropertiesPluginIdentifier, RemoteDependencyData, Trace, createDistributedTraceContextFromTrace, createDomEvent,
createTelemetryItem, dataSanitizeString, eSeverityLevel, isCrossOriginError, strNotSpecified, utlDisableStorage, utlEnableStorage,
@@ -16,9 +16,10 @@ import {
BaseTelemetryPlugin, IAppInsightsCore, IConfigDefaults, IConfiguration, ICookieMgr, ICustomProperties, IDistributedTraceContext,
IInstrumentCallDetails, IPlugin, IProcessTelemetryContext, IProcessTelemetryUnloadContext, ITelemetryInitializerHandler, ITelemetryItem,
ITelemetryPluginChain, ITelemetryUnloadState, InstrumentEvent, TelemetryInitializerFunction, _eInternalMessageId, arrForEach,
- cfgDfBoolean, cfgDfSet, cfgDfString, cfgDfValidate, createProcessTelemetryContext, createUniqueNamespace, dumpObj, eLoggingSeverity,
- eventOff, eventOn, generateW3CId, getDocument, getExceptionName, getHistory, getLocation, getWindow, hasHistory, hasWindow, isFunction,
- isNullOrUndefined, isString, isUndefined, mergeEvtNamespace, onConfigChange, safeGetCookieMgr, strUndefined, throwError
+ cfgDfBoolean, cfgDfMerge, cfgDfSet, cfgDfString, cfgDfValidate, createProcessTelemetryContext, createUniqueNamespace, dumpObj,
+ eLoggingSeverity, eventOff, eventOn, findAllScripts, generateW3CId, getDocument, getExceptionName, getHistory, getLocation, getWindow,
+ hasHistory, hasWindow, isFunction, isNullOrUndefined, isString, isUndefined, mergeEvtNamespace, onConfigChange, safeGetCookieMgr,
+ strUndefined, throwError
} from "@microsoft/applicationinsights-core-js";
import { PropertiesPlugin } from "@microsoft/applicationinsights-properties-js";
import { isError, objDeepFreeze, objDefine, scheduleTimeout, strIndexOf } from "@nevware21/ts-utils";
@@ -66,7 +67,8 @@ const defaultValues: IConfigDefaults = objDeepFreeze({
namePrefix: cfgDfString(),
enableDebug: cfgDfBoolean(),
disableFlushOnBeforeUnload: cfgDfBoolean(),
- disableFlushOnUnload: cfgDfBoolean(false, "disableFlushOnBeforeUnload")
+ disableFlushOnUnload: cfgDfBoolean(false, "disableFlushOnBeforeUnload"),
+ expCfg: cfgDfMerge({inclScripts: false})
});
function _chkConfigMilliseconds(value: number, defValue: number): number {
@@ -422,7 +424,11 @@ export class AnalyticsPlugin extends BaseTelemetryPlugin implements IAppInsights
exception.severityLevel,
exception.id
).toInterface();
-
+ var doc = getDocument();
+ if (doc && _self.config.expCfg?.inclScripts) {
+ var scriptsInfo = findAllScripts(doc);
+ exceptionPartB.properties["exceptionScripts"] = JSON.stringify(scriptsInfo);
+ }
let telemetryItem: ITelemetryItem = createTelemetryItem(
exceptionPartB,
Exception.dataType,
diff --git a/shared/AppInsightsCommon/src/Interfaces/IConfig.ts b/shared/AppInsightsCommon/src/Interfaces/IConfig.ts
index 878911921..7c63fe954 100644
--- a/shared/AppInsightsCommon/src/Interfaces/IConfig.ts
+++ b/shared/AppInsightsCommon/src/Interfaces/IConfig.ts
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
import { IConfiguration, ICustomProperties, isNullOrUndefined } from "@microsoft/applicationinsights-core-js";
import { DistributedTracingModes } from "../Enums";
+import { IExceptionConfig } from "./IExceptionTelemetry";
import { IRequestContext } from "./IRequestContext";
import { IStorageBuffer } from "./IStorageBuffer";
import { IThrottleMgrConfig } from "./IThrottleMgr";
@@ -389,6 +390,11 @@ export interface IConfig {
* This URL takes precedence over the 'config.endpointUrl' and any endpoint in the connection string.
*/
userOverrideEndpointUrl?: string;
+
+ /**
+ * [Optional] Set additional configuration for exceptions, such as more scripts to include in the exception telemetry.
+ */
+ expCfg?: IExceptionConfig;
}
export class ConfigurationManager {
diff --git a/shared/AppInsightsCommon/src/Interfaces/IExceptionTelemetry.ts b/shared/AppInsightsCommon/src/Interfaces/IExceptionTelemetry.ts
index 6f0be410f..5207e515d 100644
--- a/shared/AppInsightsCommon/src/Interfaces/IExceptionTelemetry.ts
+++ b/shared/AppInsightsCommon/src/Interfaces/IExceptionTelemetry.ts
@@ -4,6 +4,14 @@
import { SeverityLevel } from "./Contracts/SeverityLevel";
import { IPartC } from "./IPartC";
+export interface IExceptionConfig{
+ /**
+ * If set to true, when exception is sent out, the SDK will also send out all scripts basic info that are loaded on the page.
+ * Notice: This would increase the size of the exception telemetry.
+ */
+ inclScripts?: boolean;
+}
+
/**
* @export
* @interface IExceptionTelemetry
diff --git a/shared/AppInsightsCommon/src/applicationinsights-common.ts b/shared/AppInsightsCommon/src/applicationinsights-common.ts
index 32af7d137..dcc988c06 100644
--- a/shared/AppInsightsCommon/src/applicationinsights-common.ts
+++ b/shared/AppInsightsCommon/src/applicationinsights-common.ts
@@ -26,7 +26,7 @@ export { IEventTelemetry } from "./Interfaces/IEventTelemetry";
export { ITraceTelemetry } from "./Interfaces/ITraceTelemetry";
export { IMetricTelemetry } from "./Interfaces/IMetricTelemetry";
export { IDependencyTelemetry } from "./Interfaces/IDependencyTelemetry";
-export { IExceptionTelemetry, IAutoExceptionTelemetry, IExceptionInternal } from "./Interfaces/IExceptionTelemetry";
+export { IExceptionTelemetry, IAutoExceptionTelemetry, IExceptionInternal, IExceptionConfig } from "./Interfaces/IExceptionTelemetry";
export { IPageViewTelemetry, IPageViewTelemetryInternal } from "./Interfaces/IPageViewTelemetry";
export { IPageViewPerformanceTelemetry, IPageViewPerformanceTelemetryInternal } from "./Interfaces/IPageViewPerformanceTelemetry";
export { Trace } from "./Telemetry/Trace";
@@ -64,7 +64,7 @@ export { eDistributedTracingModes, DistributedTracingModes, EventPersistence } f
export { stringToBoolOrDefault, msToTimeSpan, getExtensionByName, isCrossOriginError } from "./HelperFuncs";
export {
isBeaconsSupported as isBeaconApiSupported,
- ITraceParent, createTraceParent, parseTraceParent, isValidTraceId, isValidSpanId, isValidTraceParent, isSampledFlag, formatTraceParent, findW3cTraceParent
+ ITraceParent, createTraceParent, parseTraceParent, isValidTraceId, isValidSpanId, isValidTraceParent, isSampledFlag, formatTraceParent, findW3cTraceParent, findAllScripts
} from "@microsoft/applicationinsights-core-js";
export { createDomEvent } from "./DomHelperFuncs";
export {
diff --git a/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts
index 1cdcf9337..8a22e9ae6 100644
--- a/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts
+++ b/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts
@@ -4,8 +4,8 @@ import * as pako from "pako";
export class AppInsightsCoreSizeCheck extends AITestClass {
private readonly MAX_RAW_SIZE = 65;
private readonly MAX_BUNDLE_SIZE = 65;
- private readonly MAX_RAW_DEFLATE_SIZE = 27;
- private readonly MAX_BUNDLE_DEFLATE_SIZE = 27;
+ private readonly MAX_RAW_DEFLATE_SIZE = 28;
+ private readonly MAX_BUNDLE_DEFLATE_SIZE = 28;
private readonly rawFilePath = "../dist/es5/applicationinsights-core-js.min.js";
private readonly prodFilePath = "../browser/es5/applicationinsights-core-js.min.js";
diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/W3cTraceParent.ts b/shared/AppInsightsCore/src/JavaScriptSDK/W3cTraceParent.ts
index e1264da83..ca62f1723 100644
--- a/shared/AppInsightsCore/src/JavaScriptSDK/W3cTraceParent.ts
+++ b/shared/AppInsightsCore/src/JavaScriptSDK/W3cTraceParent.ts
@@ -1,4 +1,4 @@
-import { isArray, isString, strLeft, strTrim } from "@nevware21/ts-utils";
+import { arrForEach, isArray, isString, strLeft, strTrim } from "@nevware21/ts-utils";
import { ITraceParent } from "../JavaScriptSDK.Interfaces/ITraceParent";
import { generateW3CId } from "./CoreUtils";
import { findMetaTag, findNamedServerTiming } from "./EnvUtils";
@@ -202,3 +202,45 @@ export function findW3cTraceParent(selectIdx?: number): ITraceParent {
return traceParent;
}
+
+export interface scriptsInfo {
+ url: string;
+ crossOrigin?: string;
+ async?: boolean;
+ defer?: boolean;
+ referrerPolicy?: string;
+}
+
+/**
+ * Find all script tags in the provided document and return the information about them.
+ * @param doc
+ * @returns
+ */
+export function findAllScripts(doc: any) {
+ let scripts = doc.getElementsByTagName("script");
+ let result: scriptsInfo[] = [];
+ arrForEach(scripts, (script: any) => {
+ let src = script.getAttribute("src");
+ if (src) {
+ let crossOrigin = script.getAttribute("crossorigin");
+ let async = script.hasAttribute("async") === true;
+ let defer = script.hasAttribute("defer") === true;
+ let referrerPolicy = script.getAttribute("referrerpolicy");
+ let info: scriptsInfo = { url: src };
+ if (crossOrigin) {
+ info.crossOrigin = crossOrigin;
+ }
+ if (async) {
+ info.async = async;
+ }
+ if (defer) {
+ info.defer = defer;
+ }
+ if (referrerPolicy) {
+ info.referrerPolicy = referrerPolicy;
+ }
+ result.push(info);
+ }
+ });
+ return result;
+}
diff --git a/shared/AppInsightsCore/src/applicationinsights-core-js.ts b/shared/AppInsightsCore/src/applicationinsights-core-js.ts
index 9eaf98bde..3a8551abc 100644
--- a/shared/AppInsightsCore/src/applicationinsights-core-js.ts
+++ b/shared/AppInsightsCore/src/applicationinsights-core-js.ts
@@ -93,7 +93,7 @@ export { ITelemetryUnloadState } from "./JavaScriptSDK.Interfaces/ITelemetryUnlo
export { IDistributedTraceContext } from "./JavaScriptSDK.Interfaces/IDistributedTraceContext";
export { ITraceParent } from "./JavaScriptSDK.Interfaces/ITraceParent";
export {
- createTraceParent, parseTraceParent, isValidTraceId, isValidSpanId, isValidTraceParent, isSampledFlag, formatTraceParent, findW3cTraceParent
+ createTraceParent, parseTraceParent, isValidTraceId, isValidSpanId, isValidTraceParent, isSampledFlag, formatTraceParent, findW3cTraceParent, findAllScripts
} from "./JavaScriptSDK/W3cTraceParent";
// Dynamic Config definitions