Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,8 @@ Most configuration fields are named such that they can be defaulted to falsey. A
| featureOptIn <br/><sub>since 3.0.3</sub> | IFeatureOptIn | undefined | [Optional] Set Feature opt in details. |
| throttleMgrCfg <br/><sub>since 3.0.3</sub> | `{[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

Expand Down
2 changes: 1 addition & 1 deletion channels/1ds-post-js/src/DataModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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";
Expand Down Expand Up @@ -66,7 +67,8 @@ const defaultValues: IConfigDefaults<IConfig> = objDeepFreeze({
namePrefix: cfgDfString(),
enableDebug: cfgDfBoolean(),
disableFlushOnBeforeUnload: cfgDfBoolean(),
disableFlushOnUnload: cfgDfBoolean(false, "disableFlushOnBeforeUnload")
disableFlushOnUnload: cfgDfBoolean(false, "disableFlushOnBeforeUnload"),
expCfg: cfgDfMerge<IExceptionConfig>({inclScripts: false})
});

function _chkConfigMilliseconds(value: number, defValue: number): number {
Expand Down Expand Up @@ -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<IExceptionInternal>(
exceptionPartB,
Exception.dataType,
Expand Down
6 changes: 6 additions & 0 deletions shared/AppInsightsCommon/src/Interfaces/IConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions shared/AppInsightsCommon/src/applicationinsights-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down
44 changes: 43 additions & 1 deletion shared/AppInsightsCore/src/JavaScriptSDK/W3cTraceParent.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down