Skip to content

Commit

Permalink
Beta Part 2: Part of Mega Dynamic Load/Unload support
Browse files Browse the repository at this point in the history
- Add Event Namespace support
- Minification of constant values
- Add part of the unload functionality (required for unified `teardown()` functionality)
  • Loading branch information
MSNev committed Mar 8, 2022
1 parent 17bb23e commit 75646d6
Show file tree
Hide file tree
Showing 56 changed files with 2,740 additions and 637 deletions.
48 changes: 21 additions & 27 deletions extensions/applicationinsights-dependencies-js/src/ajax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
import {
RequestHeaders, CorrelationIdHelper, TelemetryItemCreator, ICorrelationConfig,
RemoteDependencyData, dateTimeUtilsNow, DisabledPropertyName, IDependencyTelemetry,
IConfig, ITelemetryContext, PropertiesPluginIdentifier, DistributedTracingModes, IRequestContext, isInternalApplicationInsightsEndpoint
IConfig, ITelemetryContext, PropertiesPluginIdentifier, eDistributedTracingModes, IRequestContext, isInternalApplicationInsightsEndpoint
} from "@microsoft/applicationinsights-common";
import {
isNullOrUndefined, arrForEach, isString, strTrim, isFunction, LoggingSeverity, _InternalMessageId,
IAppInsightsCore, BaseTelemetryPlugin, ITelemetryPluginChain, IConfiguration, IPlugin, ITelemetryItem, IProcessTelemetryContext,
getLocation, getGlobal, strPrototype, IInstrumentCallDetails, InstrumentFunc, InstrumentProto, getPerformance,
IInstrumentHooksCallbacks, IInstrumentHook, objForEachKey, generateW3CId, getIEVersion, dumpObj, ICustomProperties, isXhrSupported, attachEvent
IInstrumentHooksCallbacks, objForEachKey, generateW3CId, getIEVersion, dumpObj, ICustomProperties, isXhrSupported, eventOn, mergeEvtNamespace, createUniqueNamespace
} from "@microsoft/applicationinsights-core-js";
import { ajaxRecord, IAjaxRecordResponse } from "./ajaxRecord";
import { Traceparent } from "./TraceParent";
Expand Down Expand Up @@ -158,7 +158,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
disableFetchTracking: true,
excludeRequestFromAutoTrackingPatterns: undefined,
disableCorrelationHeaders: false,
distributedTracingMode: DistributedTracingModes.AI_AND_W3C,
distributedTracingMode: eDistributedTracingModes.AI_AND_W3C,
correlationHeaderExcludedDomains: [
"*.blob.core.windows.net",
"*.blob.core.chinacloudapi.cn",
Expand Down Expand Up @@ -214,21 +214,25 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
let _enableAjaxPerfTracking:boolean = false;
let _maxAjaxCallsPerView:number = 0;
let _enableResponseHeaderTracking:boolean = false;
let _hooks:IInstrumentHook[] = [];
let _disabledUrls:any = {};
let _excludeRequestFromAutoTrackingPatterns: string[] | RegExp[];
let _addRequestContext: (requestContext?: IRequestContext) => ICustomProperties;
let _evtNamespace: string | string[];

dynamicProto(AjaxMonitor, this, (_self, _base) => {
let _addHook = _base._addHook;

dynamicProto(AjaxMonitor, this, (_self, base) => {
_self.initialize = (config: IConfiguration & IConfig, core: IAppInsightsCore, extensions: IPlugin[], pluginChain?:ITelemetryPluginChain) => {
if (!_self.isInitialized()) {
base.initialize(config, core, extensions, pluginChain);
_base.initialize(config, core, extensions, pluginChain);
let ctx = _self._getTelCtx();
const defaultConfig = AjaxMonitor.getDefaultConfig();
objForEachKey(defaultConfig, (field, value) => {
_config[field] = ctx.getConfig(AjaxMonitor.identifier, field, value);
});

_evtNamespace = mergeEvtNamespace(createUniqueNamespace("ajax"), core && core.evtNamespace && core.evtNamespace());

let distributedTracingMode = _config.distributedTracingMode;
_enableRequestHeaderTracking = _config.enableRequestHeaderTracking;
_enableAjaxErrorStatusText = _config.enableAjaxErrorStatusText;
Expand All @@ -238,8 +242,8 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
_excludeRequestFromAutoTrackingPatterns = _config.excludeRequestFromAutoTrackingPatterns;
_addRequestContext = _config.addRequestContext;

_isUsingAIHeaders = distributedTracingMode === DistributedTracingModes.AI || distributedTracingMode === DistributedTracingModes.AI_AND_W3C;
_isUsingW3CHeaders = distributedTracingMode === DistributedTracingModes.AI_AND_W3C || distributedTracingMode === DistributedTracingModes.W3C;
_isUsingAIHeaders = distributedTracingMode === eDistributedTracingModes.AI || distributedTracingMode === eDistributedTracingModes.AI_AND_W3C;
_isUsingW3CHeaders = distributedTracingMode === eDistributedTracingModes.AI_AND_W3C || distributedTracingMode === eDistributedTracingModes.W3C;
if (_enableAjaxPerfTracking) {
let iKey = config.instrumentationKey || "unkwn";
if (iKey.length > 5) {
Expand Down Expand Up @@ -272,16 +276,10 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
}
};

_self.teardown = () => {
// Remove all instrumentation hooks
arrForEach(_hooks, (fn) => {
fn.rm();
});
_hooks = [];
_self._doUnload = () => {
_fetchInitialized = false;
_xhrInitialized = false;
_self.setInitialized(false);
}
};

_self.trackDependencyData = (dependency: IDependencyTelemetry, properties?: { [key: string]: any }) => {
_self[strTrackDependencyDataInternal](dependency, properties);
Expand Down Expand Up @@ -359,8 +357,8 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
// Hack since expected format in w3c mode is |abc.def.
// Non-w3c format is |abc.def
// @todo Remove if better solution is available, e.g. handle in portal
if ((_config.distributedTracingMode === DistributedTracingModes.W3C
|| _config.distributedTracingMode === DistributedTracingModes.AI_AND_W3C)
if ((_config.distributedTracingMode === eDistributedTracingModes.W3C
|| _config.distributedTracingMode === eDistributedTracingModes.AI_AND_W3C)
&& typeof dependency.id === "string" && dependency.id[dependency.id.length - 1] !== "."
) {
dependency.id += ".";
Expand Down Expand Up @@ -411,7 +409,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
let global = getGlobal();
let isPolyfill = (fetch as any).polyfill;
if (_config.disableFetchTracking === false) {
_hooks.push(InstrumentFunc(global, strFetch, {
_addHook(InstrumentFunc(global, strFetch, {
// Add request hook
req: (callDetails: IInstrumentCallDetails, input, init) => {
let fetchData: ajaxRecord;
Expand Down Expand Up @@ -473,7 +471,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
// Note: Polyfill implementations that don't support the "poyyfill" tag are not supported
// the workaround is to add a polyfill property to your fetch implementation before initializing
// App Insights
_hooks.push(InstrumentFunc(global, strFetch, {
_addHook(InstrumentFunc(global, strFetch, {
req: (callDetails: IInstrumentCallDetails, input, init) => {
// Just call so that we record any disabled URL
_isDisabledRequest(null, input, init);
Expand All @@ -489,7 +487,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
}

function _hookProto(target: any, funcName: string, callbacks: IInstrumentHooksCallbacks) {
_hooks.push(InstrumentProto(target, funcName, callbacks));
_addHook(InstrumentProto(target, funcName, callbacks));
}

function _instrumentXhr():void {
Expand Down Expand Up @@ -653,7 +651,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
}

function _attachToOnReadyStateChange(xhr: XMLHttpRequestInstrumented) {
xhr[strAjaxData].xhrMonitoringState.stateChangeAttached = attachEvent(xhr, "readystatechange", () => {
xhr[strAjaxData].xhrMonitoringState.stateChangeAttached = eventOn(xhr, "readystatechange", () => {
try {
if (xhr && xhr.readyState === 4 && _isMonitoredXhrInstance(xhr)) {
_onAjaxComplete(xhr);
Expand All @@ -672,7 +670,7 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
});
}
}
});
}, _evtNamespace);
}

function _getResponseText(xhr: XMLHttpRequestInstrumented) {
Expand Down Expand Up @@ -1007,10 +1005,6 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
}

public teardown():void {
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
}

public processTelemetry(item: ITelemetryItem, itemCtx?: IProcessTelemetryContext) {
this.processNext(item, itemCtx);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ function _populatePerfData(ajaxData:ajaxRecord, dependency:IDependencyTelemetry)
arrForEach(serverTiming, (value, idx) => {
let name = normalizeJsName(value[strName] || "" + idx);
let newValue = server[name] || {};
objForEachKey(value, (key, val) => {
objForEachKey(value, (key, val: any) => {
if (key !== strName && isString(val) || isNumber(val)) {
if (newValue[key]) {
val = newValue[key] + ";" + val;
Expand Down
22 changes: 19 additions & 3 deletions shared/AppInsightsCommon/src/Enums.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { createEnumStyle } from "@microsoft/applicationinsights-core-js";

/**
* Type of storage to differentiate between local storage and session storage
*/
export enum StorageType {
export const enum eStorageType {
LocalStorage,
SessionStorage
}

export const StorageType = createEnumStyle<{ [key in (keyof typeof eStorageType)]: number; }>({
LocalStorage: eStorageType.LocalStorage,
SessionStorage: eStorageType.SessionStorage
});
export type StorageType = eStorageType | typeof StorageType;


/**
* Enum is used in aiDataContract to describe how fields are serialized.
* For instance: (Fieldtype.Required | FieldType.Array) will mark the field as required and indicate it's an array
*/
export const enum FieldType { Default = 0, Required = 1, Array = 2, Hidden = 4 }

export enum DistributedTracingModes {
export const enum eDistributedTracingModes {
/**
* (Default) Send Application Insights correlation headers
*/

AI=0,
AI = 0,

/**
* Send both W3C Trace Context headers and back-compatibility Application Insights headers
Expand All @@ -32,3 +41,10 @@ export enum DistributedTracingModes {
*/
W3C
}

export const DistributedTracingModes = createEnumStyle<{ [key in (keyof typeof eDistributedTracingModes)]: number; }>({
AI: eDistributedTracingModes.AI,
AI_AND_W3C: eDistributedTracingModes.AI_AND_W3C,
W3C: eDistributedTracingModes.W3C
});
export type DistributedTracingModes = number | eDistributedTracingModes;
12 changes: 7 additions & 5 deletions shared/AppInsightsCommon/src/HelperFuncs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

import { arrForEach, IPlugin, isString } from "@microsoft/applicationinsights-core-js";

const strEmpty = "";

export function stringToBoolOrDefault(str: any, defaultValue = false): boolean {
if (str === undefined || str === null) {
return defaultValue;
Expand All @@ -21,18 +23,18 @@ export function msToTimeSpan(totalms: number): string {

totalms = Math.round(totalms);

let ms = "" + totalms % 1000;
let sec = "" + Math.floor(totalms / 1000) % 60;
let min = "" + Math.floor(totalms / (1000 * 60)) % 60;
let hour = "" + Math.floor(totalms / (1000 * 60 * 60)) % 24;
let ms = strEmpty + totalms % 1000;
let sec = strEmpty + Math.floor(totalms / 1000) % 60;
let min = strEmpty + Math.floor(totalms / (1000 * 60)) % 60;
let hour = strEmpty + Math.floor(totalms / (1000 * 60 * 60)) % 24;
const days = Math.floor(totalms / (1000 * 60 * 60 * 24));

ms = ms.length === 1 ? "00" + ms : ms.length === 2 ? "0" + ms : ms;
sec = sec.length < 2 ? "0" + sec : sec;
min = min.length < 2 ? "0" + min : min;
hour = hour.length < 2 ? "0" + hour : hour;

return (days > 0 ? days + "." : "") + hour + ":" + min + ":" + sec + "." + ms;
return (days > 0 ? days + "." : strEmpty) + hour + ":" + min + ":" + sec + "." + ms;
}

export function getExtensionByName(extensions: IPlugin[], identifier: string): IPlugin | null {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// // Copyright (c) Microsoft Corporation. All rights reserved.
// // Licensed under the MIT License.

// // THIS FILE WAS AUTOGENERATED
// import { Domain } from "./Domain";
// "use strict";

// /**
// * Instances of AvailabilityData represent the result of executing an availability test.
// */
// export class AvailabilityData implements Domain {

// /**
// * Schema version
// */
// public ver: number = 2;

// /**
// * Identifier of a test run. Use it to correlate steps of test run and telemetry generated by the service.
// */
// public id: string;

// /**
// * Name of the test that these availability results represent.
// */
// public name: string;

// /**
// * Duration in format: DD.HH:MM:SS.MMMMMM. Must be less than 1000 days.
// */
// public duration: string;

// /**
// * Success flag.
// */
// public success: boolean;

// /**
// * Name of the location where the test was run from.
// */
// public runLocation: string;

// /**
// * Diagnostic message for the result.
// */
// public message: string;

// /**
// * Collection of custom properties.
// */
// public properties: any = {};

// /**
// * Collection of custom measurements.
// */
// public measurements: any = {};
// }
Loading

0 comments on commit 75646d6

Please sign in to comment.