From acc2e437787e9b8b02477cc6620808def7bf0379 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 4 Mar 2025 17:50:08 -0800 Subject: [PATCH 01/62] basic structure --- .../src/Sender.ts | 64 ++++-- .../IAppInsightsCore.ts | 3 + .../IConfiguration.ts | 1 + .../JavaScriptSDK.Interfaces/IStatsBeat.ts | 11 + .../IStatsBeatEvent.ts | 10 + .../JavaScriptSDK.Interfaces/IXHROverride.ts | 3 +- .../src/JavaScriptSDK/AppInsightsCore.ts | 15 ++ .../src/JavaScriptSDK/NetworkStatsbeat.ts | 42 ++++ .../src/JavaScriptSDK/StatsBeat.ts | 212 ++++++++++++++++++ .../src/applicationinsights-core-js.ts | 2 + 10 files changed, 343 insertions(+), 20 deletions(-) create mode 100644 shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts create mode 100644 shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeatEvent.ts create mode 100644 shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts create mode 100644 shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 8c70249e4..fec71cfb3 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -2,31 +2,32 @@ import dynamicProto from "@microsoft/dynamicproto-js"; import { BreezeChannelIdentifier, DEFAULT_BREEZE_ENDPOINT, DEFAULT_BREEZE_PATH, Event, Exception, IConfig, IEnvelope, IOfflineListener, ISample, IStorageBuffer, Metric, PageView, PageViewPerformance, ProcessLegacy, RemoteDependencyData, RequestHeaders, SampleRate, Trace, - createOfflineListener, eRequestHeaders, isInternalApplicationInsightsEndpoint, utlCanUseSessionStorage, utlSetStoragePrefix + createOfflineListener, eRequestHeaders, isInternalApplicationInsightsEndpoint, urlParseUrl, utlCanUseSessionStorage, utlSetStoragePrefix } from "@microsoft/applicationinsights-common"; import { ActiveStatus, BaseTelemetryPlugin, IAppInsightsCore, IBackendResponse, IChannelControls, IConfigDefaults, IConfiguration, IDiagnosticLogger, IInternalOfflineSupport, INotificationManager, IPayloadData, IPlugin, IProcessTelemetryContext, - IProcessTelemetryUnloadContext, ITelemetryItem, ITelemetryPluginChain, ITelemetryUnloadState, IXDomainRequest, IXHROverride, - OnCompleteCallback, SendPOSTFunction, SendRequestReason, SenderPostManager, TransportType, _ISendPostMgrConfig, _ISenderOnComplete, - _eInternalMessageId, _throwInternal, _warnToConsole, arrForEach, cfgDfBoolean, cfgDfValidate, createProcessTelemetryContext, - createUniqueNamespace, dateNow, dumpObj, eLoggingSeverity, formatErrorMessageXdr, formatErrorMessageXhr, getExceptionName, getIEVersion, - isArray, isBeaconsSupported, isFetchSupported, isNullOrUndefined, mergeEvtNamespace, objExtend, onConfigChange, parseResponse, - prependTransports, runTargetUnload + IProcessTelemetryUnloadContext, IStatsBeat, IStatsBeatEvent, ITelemetryItem, ITelemetryPluginChain, ITelemetryUnloadState, + IXDomainRequest, IXHROverride, OnCompleteCallback, SendPOSTFunction, SendRequestReason, SenderPostManager, TransportType, + _ISendPostMgrConfig, _ISenderOnComplete, _eInternalMessageId, _throwInternal, _warnToConsole, arrForEach, cfgDfBoolean, cfgDfValidate, + createProcessTelemetryContext, createUniqueNamespace, dateNow, dumpObj, eLoggingSeverity, formatErrorMessageXdr, formatErrorMessageXhr, + getExceptionName, getIEVersion, isArray, isBeaconsSupported, isFetchSupported, isNullOrUndefined, mergeEvtNamespace, objExtend, + onConfigChange, parseResponse, prependTransports, runTargetUnload } from "@microsoft/applicationinsights-core-js"; import { IPromise } from "@nevware21/ts-async"; import { ITimerHandler, isNumber, isPromiseLike, isString, isTruthy, objDeepFreeze, objDefine, scheduleTimeout } from "@nevware21/ts-utils"; import { - DependencyEnvelopeCreator, EventEnvelopeCreator, ExceptionEnvelopeCreator, MetricEnvelopeCreator, PageViewEnvelopeCreator, - PageViewPerformanceEnvelopeCreator, TraceEnvelopeCreator + DependencyEnvelopeCreator, EnvelopeCreator, EventEnvelopeCreator, ExceptionEnvelopeCreator, MetricEnvelopeCreator, + PageViewEnvelopeCreator, PageViewPerformanceEnvelopeCreator, TraceEnvelopeCreator } from "./EnvelopeCreator"; import { IInternalStorageItem, ISenderConfig } from "./Interfaces"; import { ArraySendBuffer, ISendBuffer, SessionStorageSendBuffer } from "./SendBuffer"; import { Serializer } from "./Serializer"; import { Sample } from "./TelemetryProcessors/Sample"; +const INSTRUMENTATION_KEY = "c4a29126-a7cb-47e5-b348-11414998b11e"; const UNDEFINED_VALUE: undefined = undefined; const EMPTY_STR = ""; @@ -160,6 +161,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let _offlineListener: IOfflineListener; let _evtNamespace: string | string[]; let _endpointUrl: string; + let _statsBeat: IStatsBeat; let _orgEndpointUrl: string; let _maxBatchSizeInBytes: number; let _beaconSupported: boolean; @@ -270,6 +272,15 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let senderConfig = ctx.getExtCfg(identifier, defaultAppInsightsChannelConfig); let curExtUrl = senderConfig.endpointUrl; + _statsBeat = core.getStatsBeat(); + if (_statsBeat && !_statsBeat.isInitialized()) { + let senderConfig = {...config}; + senderConfig.instrumentationKey = INSTRUMENTATION_KEY; + let statsBeatSender = new Sender(); + statsBeatSender.initialize(senderConfig, core, extensions, pluginChain); + var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; + _statsBeat.initialize(senderConfig.instrumentationKey, statsBeatSender, endpointHost, EnvelopeCreator.Version); + } // if it is not inital change (_endpointUrl has value) // if current sender endpoint url is not changed directly // means ExtCfg is not changed directly @@ -628,20 +639,22 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { /** * xdr state changes */ - _self._xdrOnLoad = (xdr: IXDomainRequest, payload: IInternalStorageItem[] | string[]) => { + _self._xdrOnLoad = (xdr: IXDomainRequest, payload: IInternalStorageItem[] | string[], statsBeatData?: IStatsBeatEvent) => { // since version 3.1.3, string[] is no-op if (_isStringArr(payload)) { return; } - return _xdrOnLoad(xdr, payload as IInternalStorageItem[]); + return _xdrOnLoad(xdr, payload as IInternalStorageItem[], statsBeatData); } - function _xdrOnLoad (xdr: IXDomainRequest, payload: IInternalStorageItem[]) { + function _xdrOnLoad (xdr: IXDomainRequest, payload: IInternalStorageItem[], statsBeatData?: IStatsBeatEvent) { const responseText = _getResponseText(xdr); if (xdr && (responseText + "" === "200" || responseText === "")) { _consecutiveErrors = 0; _self._onSuccess(payload, 0); + var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; + _statsBeat.countRequest(endpointHost, dateNow() - statsBeatData.startTime, true); } else { const results = parseResponse(responseText); @@ -663,6 +676,9 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (!data) { return; } + if (payload.statsBeatData){ + return _xdrOnLoad(xdr, data, payload.statsBeatData); + } return _xdrOnLoad(xdr, data); }, @@ -671,6 +687,9 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (!data) { return; } + if (payload.statsBeatData){ + return _checkResponsStatus(response.status, data, response.url, data.length, response.statusText, resValue || "", payload.statsBeatData); + } return _checkResponsStatus(response.status, data, response.url, data.length, response.statusText, resValue || ""); }, xhrOnComplete: (request: XMLHttpRequest, oncomplete: OnCompleteCallback, payload?: IPayloadData) => { @@ -727,11 +746,13 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { { message }); _self._buffer && _self._buffer.clearSent(payload); + var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; + _statsBeat.countException(endpointHost); } /** * partial success handler */ - function _onPartialSuccess(payload: IInternalStorageItem[], results: IBackendResponse) { + function _onPartialSuccess(payload: IInternalStorageItem[], results: IBackendResponse, statsBeatData?: IStatsBeatEvent) { const failed: IInternalStorageItem[] = []; const retry: IInternalStorageItem[] = []; @@ -928,6 +949,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { return _getOnComplete(payload, status, headers, response); } let payloadData = _getPayload(payload); + payloadData.statsBeatData = {startTime: dateNow()}; let sendPostFunc: SendPOSTFunction = sendInterface && sendInterface.sendPOST; if (sendPostFunc && payloadData) { // *********************************************************************************************** @@ -986,7 +1008,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { return false; } - function _checkResponsStatus(status: number, payload: IInternalStorageItem[], responseUrl: string, countOfItemsInPayload: number, errorMessage: string, res: any) { + function _checkResponsStatus(status: number, payload: IInternalStorageItem[], responseUrl: string, countOfItemsInPayload: number, errorMessage: string, res: any, statsBeatData?: IStatsBeatEvent) { let response: IBackendResponse = null; if (!_self._appId) { response = parseResponse(res); @@ -1028,7 +1050,8 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { _self._onError(payload, errorMessage); } } else { - + let endTime = dateNow(); + _statsBeat.countRequest(responseUrl, endTime - statsBeatData.startTime, status === 200); // check if the xhr's responseURL or fetch's response.url is same as endpoint url // TODO after 10 redirects force send telemetry with 'redirect=false' as query parameter. _checkAndUpdateEndPointUrl(responseUrl); @@ -1095,6 +1118,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { // Can't send anymore, so split the batch and drop the rest droppedPayload.push(thePayload); } else { + _statsBeat.countRequest(urlParseUrl(_self._senderConfig.endpointUrl).hostname, dateNow() - payload.statsBeatData.startTime, true); _self._onSuccess(arr, arr.length); } } @@ -1104,6 +1128,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } } else { _fallbackSend && _fallbackSend(data, true); + _statsBeat.countException(urlParseUrl(_self._senderConfig.endpointUrl).hostname); _throwInternal(_self.diagLog(), eLoggingSeverity.WARNING, _eInternalMessageId.TransmissionFailed, ". " + "Failed to send telemetry with Beacon API, retried with normal sender."); } @@ -1159,6 +1184,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (!payload || payload.length === 0) { return; } + _statsBeat.countRetry(urlParseUrl(_self._senderConfig.endpointUrl).hostname); const buffer = _self._buffer; buffer.clearSent(payload); @@ -1413,7 +1439,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { * @Internal * since version 3.2.0, if the payload is string[], this function is no-op (string[] is only used for backwards Compatibility) */ - public _onError(payload: string[] | IInternalStorageItem[], message: string, event?: ErrorEvent) { + public _onError(payload: string[] | IInternalStorageItem[], message: string, event?: ErrorEvent, statsBeatData?: IStatsBeatEvent) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } @@ -1422,7 +1448,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { * @Internal * since version 3.2.0, if the payload is string[], this function is no-op (string[] is only used for backwards Compatibility) */ - public _onPartialSuccess(payload: string[] | IInternalStorageItem[], results: IBackendResponse) { + public _onPartialSuccess(payload: string[] | IInternalStorageItem[], results: IBackendResponse, statsBeatData?: IStatsBeatEvent) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } @@ -1431,7 +1457,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { * @Internal * since version 3.2.0, if the payload is string[], this function is no-op (string[] is only used for backwards Compatibility) */ - public _onSuccess(payload: string[] | IInternalStorageItem[], countOfItemsInPayload: number) { + public _onSuccess(payload: string[] | IInternalStorageItem[], countOfItemsInPayload: number, statsBeatData?: IStatsBeatEvent) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } @@ -1440,7 +1466,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { * @deprecated * since version 3.2.0, if the payload is string[], this function is no-op (string[] is only used for backwards Compatibility) */ - public _xdrOnLoad(xdr: IXDomainRequest, payload: string[] | IInternalStorageItem[]) { + public _xdrOnLoad(xdr: IXDomainRequest, payload: string[] | IInternalStorageItem[], statsBeatData?: IStatsBeatEvent) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IAppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IAppInsightsCore.ts index fbb62ba7c..12dcd085b 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IAppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IAppInsightsCore.ts @@ -16,6 +16,7 @@ import { INotificationListener } from "./INotificationListener"; import { INotificationManager } from "./INotificationManager"; import { IPerfManagerProvider } from "./IPerfManager"; import { IProcessTelemetryContext } from "./IProcessTelemetryContext"; +import { IStatsBeat } from "./IStatsBeat"; import { ITelemetryInitializerHandler, TelemetryInitializerFunction } from "./ITelemetryInitializers"; import { ITelemetryItem } from "./ITelemetryItem"; import { IPlugin, ITelemetryPlugin } from "./ITelemetryPlugin"; @@ -124,6 +125,8 @@ export interface IAppInsightsCore im let _logger: IDiagnosticLogger; let _eventQueue: ITelemetryItem[]; let _notificationManager: INotificationManager | null | undefined; + let _statsBeat: IStatsBeat | null; let _perfManager: IPerfManager | null; let _cfgPerfManager: IPerfManager | null; let _cookieManager: ICookieMgr | null; @@ -357,6 +360,9 @@ export class AppInsightsCore im } _initInMemoMaxSize = rootCfg.initInMemoMaxSize || maxInitQueueSize; + if (config.disableStatsBeat === false){ + _statsBeat = new Statsbeat(); + } // app Insights core only handle ikey and endpointurl, aisku will handle cs let ikey = rootCfg.instrumentationKey; let endpointUrl = rootCfg.endpointUrl; // do not need to validate endpoint url, if it is null, default one will be set by sender @@ -612,6 +618,10 @@ export class AppInsightsCore im return _perfManager || _cfgPerfManager || getGblPerfMgr(); }; + _self.getStatsBeat = (): IStatsBeat => { + return _statsBeat; + }; + _self.setPerfMgr = (perfMgr: IPerfManager) => { _perfManager = perfMgr; }; @@ -1012,6 +1022,7 @@ export class AppInsightsCore im runTargetUnload(_notificationManager, false); _notificationManager = null; _perfManager = null; + _statsBeat = null; _cfgPerfManager = null; runTargetUnload(_cookieManager, false); _cookieManager = null; @@ -1424,6 +1435,10 @@ export class AppInsightsCore im return null; } + public getStatsBeat(): IStatsBeat { + return null; + } + public setPerfMgr(perfMgr: IPerfManager) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts new file mode 100644 index 000000000..3f57e3017 --- /dev/null +++ b/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts @@ -0,0 +1,42 @@ +import { utcNow } from "@nevware21/ts-utils"; + +export class NetworkStatsbeat { + + public time: number; + + public lastTime: number; + + public host: string; + + public totalRequestCount: number; + + public lastRequestCount: number; + + public totalSuccesfulRequestCount: number; + + public totalFailedRequestCount: number; + + public retryCount: number; + + public exceptionCount: number; + + public throttleCount: number; + + public intervalRequestExecutionTime: number; + + public lastIntervalRequestExecutionTime: number; + + constructor(host: string) { + this.host = host; + this.totalRequestCount = 0; + this.totalSuccesfulRequestCount = 0; + this.totalFailedRequestCount = 0; + this.retryCount = 0; + this.exceptionCount = 0; + this.throttleCount = 0; + this.intervalRequestExecutionTime = 0; + this.lastIntervalRequestExecutionTime = 0; + this.lastTime = utcNow(); + this.lastRequestCount = 0; + } +} diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts new file mode 100644 index 000000000..6b6776d28 --- /dev/null +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -0,0 +1,212 @@ +import dynamicProto from "@microsoft/dynamicproto-js"; +import { objKeys, utcNow } from "@nevware21/ts-utils"; +import { IChannelControls, IStatsBeat, ITelemetryItem } from "../applicationinsights-core-js"; +import { NetworkStatsbeat } from "./NetworkStatsbeat"; + +export const StatsbeatCounter = { + REQUEST_SUCCESS: "Request Success Count", + REQUEST_FAILURE: "Requests Failure Count", + REQUEST_DURATION: "Request Duration", + RETRY_COUNT: "Retry Count", + THROTTLE_COUNT: "Throttle Count", + EXCEPTION_COUNT: "Exception Count" +} + +const INSTRUMENTATION_KEY = "c4a29126-a7cb-47e5-b348-11414998b11e"; +const STATS_COLLECTION_SHORT_INTERVAL: number = 900000; // 15 minutes +const NETWORK = "Network"; +const STATSBEAT_LANGUAGE = "JavaScript"; +const STATSBEAT_TYPE = "Browser"; + +export class Statsbeat implements IStatsBeat { + constructor() { + let _networkCounter: NetworkStatsbeat; + let _handle: any; + let _statsbeatMetrics: { properties?: {} }; + let _isEnabled: boolean; + let _channel: IChannelControls; + + // Custom dimensions + let _cikey: string; + let _language: string; + let _sdkVersion: string; + let _os: string; + let _runTimeVersion: string; + dynamicProto(Statsbeat, this, (_self, _base) => { + _self.initialize = (ikey: string, channel: IChannelControls, endpoint: string, version?: string) => { + _networkCounter = new NetworkStatsbeat(endpoint); + _statsbeatMetrics = {}; + _isEnabled = true; + _channel = channel; + _sdkVersion = version; + if (_isEnabled) { + _getCustomProperties(ikey); + if (!_handle) { + _handle = setInterval(() => { + this.trackShortIntervalStatsbeats(); + }, STATS_COLLECTION_SHORT_INTERVAL); + } + } + } + + _self.isInitialized = (): boolean => { + return !!_isEnabled; + } + + _self.countRequest = (endpoint: string, duration: number, success: boolean) => { + if (!_isEnabled || !_checkEndpoint(endpoint)) { + return; + } + _networkCounter.totalRequestCount++; + _networkCounter.intervalRequestExecutionTime += duration; + if (success === false) { + _networkCounter.totalFailedRequestCount++; + } else { + _networkCounter.totalSuccesfulRequestCount++; + } + + } + + _self.countException = (endpoint: string) => { + if (!_isEnabled || !_checkEndpoint(endpoint)) { + return; + } + _networkCounter.exceptionCount++; + } + + _self.countThrottle = (endpoint: string) => { + if (!_isEnabled || !_checkEndpoint(endpoint)) { + return; + } + _networkCounter.throttleCount++; + } + + _self.countRetry = (endpoint: string) => { + if (!_isEnabled || !_checkEndpoint(endpoint)) { + return; + } + _networkCounter.retryCount++; + } + + _self.trackShortIntervalStatsbeats = (): void => { + _trackRequestDuration(); + _trackRequestsCount(); + _sendStatsbeats(); + } + + function _checkEndpoint(endpoint: string) { + return _networkCounter && _networkCounter.host === endpoint; + } + + function _getCustomProperties(ikey: string) { + _cikey = ikey; + _language = STATSBEAT_LANGUAGE; + _os = STATSBEAT_TYPE; + _runTimeVersion = STATSBEAT_TYPE; + } + + + + function _sendStatsbeats() { + // Add extra properties + let networkProperties = { + "cikey": _cikey, + "runtimeVersion": _runTimeVersion, + "language": _language, + "version": _sdkVersion, + "os": _os + } + if (objKeys(_statsbeatMetrics)) { + let statsbeat: ITelemetryItem = { + iKey: INSTRUMENTATION_KEY, + name: NETWORK, + baseData: { + name: NETWORK, + average: 0, + properties: {"host": _networkCounter.host, ..._statsbeatMetrics.properties, ...networkProperties} + } + // baseType: Metric.dataType + }; + _channel.processTelemetry(statsbeat); + } + _statsbeatMetrics = {}; + _channel.flush(true); + } + + function _trackRequestDuration() { + var currentCounter = _networkCounter; + currentCounter.time = utcNow(); + var intervalRequests = (currentCounter.totalRequestCount - currentCounter.lastRequestCount) || 0; + var elapsedMs = currentCounter.time - currentCounter.lastTime; + var averageRequestExecutionTime = ((currentCounter.intervalRequestExecutionTime - currentCounter.lastIntervalRequestExecutionTime) / intervalRequests) || 0; + currentCounter.lastIntervalRequestExecutionTime = currentCounter.intervalRequestExecutionTime; // reset + if (elapsedMs > 0 && intervalRequests > 0) { + _statsbeatMetrics.properties = _statsbeatMetrics.properties || {}; + _statsbeatMetrics.properties[StatsbeatCounter.REQUEST_DURATION] = averageRequestExecutionTime; + } + // Set last counters + currentCounter.lastRequestCount = currentCounter.totalRequestCount; + currentCounter.lastTime = currentCounter.time; + } + + function _trackRequestsCount() { + var currentCounter = _networkCounter; + if (currentCounter.totalSuccesfulRequestCount > 0) { + _statsbeatMetrics.properties = _statsbeatMetrics.properties || {}; + _statsbeatMetrics.properties[StatsbeatCounter.REQUEST_SUCCESS] = currentCounter.totalSuccesfulRequestCount; + currentCounter.totalSuccesfulRequestCount = 0; //Reset + } + if (currentCounter.totalFailedRequestCount > 0) { + _statsbeatMetrics.properties = _statsbeatMetrics.properties || {}; + _statsbeatMetrics.properties[StatsbeatCounter.REQUEST_FAILURE] = currentCounter.totalFailedRequestCount; + currentCounter.totalFailedRequestCount = 0; //Reset + } + if (currentCounter.retryCount > 0) { + _statsbeatMetrics.properties = _statsbeatMetrics.properties || {}; + _statsbeatMetrics.properties[StatsbeatCounter.RETRY_COUNT] = currentCounter.retryCount; + currentCounter.retryCount = 0; //Reset + } + if (currentCounter.throttleCount > 0) { + _statsbeatMetrics.properties = _statsbeatMetrics.properties || {}; + _statsbeatMetrics.properties[StatsbeatCounter.THROTTLE_COUNT] = currentCounter.throttleCount; + currentCounter.throttleCount = 0; //Reset + } + if (currentCounter.exceptionCount > 0) { + _statsbeatMetrics.properties = _statsbeatMetrics.properties || {}; + _statsbeatMetrics.properties[StatsbeatCounter.EXCEPTION_COUNT] = currentCounter.exceptionCount; + currentCounter.exceptionCount = 0; //Reset + } + } + }) + } + + public initialize(ikey: string, channel: IChannelControls, endpoint: string) { + // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging + } + + public isInitialized(): boolean { + // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging + return false; + } + + public countRequest(endpoint: string, duration: number, success: boolean) { + // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging + } + + public countException(endpoint: string) { + // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging + } + + public countThrottle(endpoint: string) { + // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging + } + + public countRetry(endpoint: string) { + // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging + } + + public trackShortIntervalStatsbeats() { + // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging + } + +} diff --git a/shared/AppInsightsCore/src/applicationinsights-core-js.ts b/shared/AppInsightsCore/src/applicationinsights-core-js.ts index 78cc7151f..a26af9beb 100644 --- a/shared/AppInsightsCore/src/applicationinsights-core-js.ts +++ b/shared/AppInsightsCore/src/applicationinsights-core-js.ts @@ -36,6 +36,8 @@ export { parseResponse } from "./JavaScriptSDK/ResponseHelpers"; export { IXDomainRequest, IBackendResponse } from "./JavaScriptSDK.Interfaces/IXDomainRequest"; export { _ISenderOnComplete, _ISendPostMgrConfig, _ITimeoutOverrideWrapper, _IInternalXhrOverride } from "./JavaScriptSDK.Interfaces/ISenderPostManager"; export { SenderPostManager } from "./JavaScriptSDK/SenderPostManager"; +export { IStatsBeatEvent } from "./JavaScriptSDK.Interfaces/IStatsBeatEvent"; +export { IStatsBeat } from "./JavaScriptSDK.Interfaces/IStatsBeat"; export { isArray, isTypeof, isUndefined, isNullOrUndefined, objHasOwnProperty as hasOwnProperty, isObject, isFunction, strEndsWith, strStartsWith, isDate, isError, isString, isNumber, isBoolean, arrForEach, arrIndexOf, From bfe5965412e2cd2829fe183bc9c7c5dd3e24f1b4 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 4 Mar 2025 20:16:57 -0800 Subject: [PATCH 02/62] imp[ort --- shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts | 2 +- shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index ce13fd322..d5005bdcb 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -29,6 +29,7 @@ import { INotificationListener } from "../JavaScriptSDK.Interfaces/INotification import { INotificationManager } from "../JavaScriptSDK.Interfaces/INotificationManager"; import { IPerfManager } from "../JavaScriptSDK.Interfaces/IPerfManager"; import { IProcessTelemetryContext, IProcessTelemetryUpdateContext } from "../JavaScriptSDK.Interfaces/IProcessTelemetryContext"; +import { IStatsBeat } from "../JavaScriptSDK.Interfaces/IStatsBeat"; import { ITelemetryInitializerHandler, TelemetryInitializerFunction } from "../JavaScriptSDK.Interfaces/ITelemetryInitializers"; import { ITelemetryItem } from "../JavaScriptSDK.Interfaces/ITelemetryItem"; import { IPlugin, ITelemetryPlugin } from "../JavaScriptSDK.Interfaces/ITelemetryPlugin"; @@ -36,7 +37,6 @@ import { ITelemetryPluginChain } from "../JavaScriptSDK.Interfaces/ITelemetryPlu import { ITelemetryUnloadState } from "../JavaScriptSDK.Interfaces/ITelemetryUnloadState"; import { ITelemetryUpdateState } from "../JavaScriptSDK.Interfaces/ITelemetryUpdateState"; import { ILegacyUnloadHook, IUnloadHook } from "../JavaScriptSDK.Interfaces/IUnloadHook"; -import { IStatsBeat } from "../applicationinsights-core-js"; import { doUnloadAll, runTargetUnload } from "./AsyncUtils"; import { ChannelControllerPriority } from "./Constants"; import { createCookieMgr } from "./CookieMgr"; diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 6b6776d28..65bdb7503 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -1,6 +1,8 @@ import dynamicProto from "@microsoft/dynamicproto-js"; import { objKeys, utcNow } from "@nevware21/ts-utils"; -import { IChannelControls, IStatsBeat, ITelemetryItem } from "../applicationinsights-core-js"; +import { IChannelControls } from "../JavaScriptSDK.Interfaces/IChannelControls"; +import { IStatsBeat } from "../JavaScriptSDK.Interfaces/IStatsBeat"; +import { ITelemetryItem } from "../JavaScriptSDK.Interfaces/ITelemetryItem"; import { NetworkStatsbeat } from "./NetworkStatsbeat"; export const StatsbeatCounter = { @@ -34,6 +36,7 @@ export class Statsbeat implements IStatsBeat { let _runTimeVersion: string; dynamicProto(Statsbeat, this, (_self, _base) => { _self.initialize = (ikey: string, channel: IChannelControls, endpoint: string, version?: string) => { + console.log("Statsbeat initialize called"); _networkCounter = new NetworkStatsbeat(endpoint); _statsbeatMetrics = {}; _isEnabled = true; @@ -54,6 +57,7 @@ export class Statsbeat implements IStatsBeat { } _self.countRequest = (endpoint: string, duration: number, success: boolean) => { + console.log("Statsbeat countRequest called", endpoint, duration, success); if (!_isEnabled || !_checkEndpoint(endpoint)) { return; } From 518276598e5dbd6b9bbf76ebce35e2d0384c1e85 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Wed, 5 Mar 2025 16:05:37 -0800 Subject: [PATCH 03/62] test locally works good --- .../src/Sender.ts | 39 +++++++++---------- .../JavaScriptSDK.Interfaces/IStatsBeat.ts | 1 + .../src/JavaScriptSDK/StatsBeat.ts | 15 +++++-- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index a58932f4a..50156b536 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -274,6 +274,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let curExtUrl = senderConfig.endpointUrl; _statsBeat = core.getStatsBeat(); if (_statsBeat && !_statsBeat.isInitialized()) { + _statsBeat.setInitialized(true); // otherwise, it will fall into infinite loop of creating new sender let senderConfig = {...config}; senderConfig.instrumentationKey = INSTRUMENTATION_KEY; let statsBeatSender = new Sender(); @@ -526,7 +527,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (_isStringArr(payload)) { return; } - return _xhrReadyStateChange(xhr, payload as IInternalStorageItem[],countOfItemsInPayload); + return _xhrReadyStateChange(xhr, payload as IInternalStorageItem[], countOfItemsInPayload); } @@ -672,32 +673,26 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { try { let onCompleteFuncs = { xdrOnComplete: (xdr: IXDomainRequest, oncomplete: OnCompleteCallback,payload?: IPayloadData) => { - let data = _getPayloadArr(payload); - if (!data) { + let { payloadArr = null, statsBeat = null } = _getPayloadArr(payload); + if (!payloadArr) { return; } - if (payload.statsBeatData){ - return _xdrOnLoad(xdr, data, payload.statsBeatData); - } - return _xdrOnLoad(xdr, data); + return _xdrOnLoad(xdr, payloadArr, statsBeat); }, fetchOnComplete: (response: Response, onComplete: OnCompleteCallback, resValue?: string, payload?: IPayloadData) => { - let data = _getPayloadArr(payload); - if (!data) { + let { payloadArr = null, statsBeat = null } = _getPayloadArr(payload); + if (!payloadArr) { return; } - if (payload.statsBeatData){ - return _checkResponsStatus(response.status, data, response.url, data.length, response.statusText, resValue || "", payload.statsBeatData); - } - return _checkResponsStatus(response.status, data, response.url, data.length, response.statusText, resValue || ""); + return _checkResponsStatus(response.status, payloadArr, response.url, payloadArr.length, response.statusText, resValue || "", statsBeat); }, xhrOnComplete: (request: XMLHttpRequest, oncomplete: OnCompleteCallback, payload?: IPayloadData) => { - let data = _getPayloadArr(payload); - if (!data) { + let { payloadArr = null, statsBeat = null } = _getPayloadArr(payload); + if (!payloadArr) { return; } - return _xhrReadyStateChange(request, data, data.length); + return _xhrReadyStateChange(request, payloadArr, payloadArr.length, statsBeat); }, beaconOnRetry: (data: IPayloadData, onComplete: OnCompleteCallback, canSend: (payload: IPayloadData, oncomplete: OnCompleteCallback, sync?: boolean) => boolean) => { @@ -729,9 +724,10 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { /** * xhr state changes */ - function _xhrReadyStateChange (xhr: XMLHttpRequest, payload: IInternalStorageItem[], countOfItemsInPayload: number) { + function _xhrReadyStateChange (xhr: XMLHttpRequest, payload: IInternalStorageItem[], countOfItemsInPayload: number, statsBeat?: IStatsBeatEvent) { if (xhr.readyState === 4) { - _checkResponsStatus(xhr.status, payload, xhr.responseURL, countOfItemsInPayload, formatErrorMessageXhr(xhr), _getResponseText(xhr) || xhr.response); + + _checkResponsStatus(xhr.status, payload, xhr.responseURL, countOfItemsInPayload, formatErrorMessageXhr(xhr), _getResponseText(xhr) || xhr.response, statsBeat); } } @@ -801,16 +797,17 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (payload) { let internalPayload = payload as IInternalPayloadData; let arr = internalPayload.oriPayload; + let statsBeat = internalPayload.statsBeatData; if (arr && arr.length) { - return arr + return { payloadArr: arr, statsBeat }; } - return null; + return { payloadArr: null, statsBeat: undefined }; } } catch (e) { // eslint-disable-next-line no-empty } - return null; + return { payloadArr: null, statsBeat: undefined }; } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts index 586901902..81676ff45 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts @@ -3,6 +3,7 @@ import { IChannelControls } from "./IChannelControls"; export interface IStatsBeat { initialize(ikey: string, channel: IChannelControls, endpoint: string, version?: string): void; isInitialized(): boolean; + setInitialized(value: boolean): void; countRequest(endpoint: string, duration: number, success: boolean): void; countException(endpoint: string): void; countThrottle(endpoint: string): void; diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 65bdb7503..2625faec2 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -36,7 +36,6 @@ export class Statsbeat implements IStatsBeat { let _runTimeVersion: string; dynamicProto(Statsbeat, this, (_self, _base) => { _self.initialize = (ikey: string, channel: IChannelControls, endpoint: string, version?: string) => { - console.log("Statsbeat initialize called"); _networkCounter = new NetworkStatsbeat(endpoint); _statsbeatMetrics = {}; _isEnabled = true; @@ -56,8 +55,11 @@ export class Statsbeat implements IStatsBeat { return !!_isEnabled; } + _self.setInitialized = (value: boolean) => { + _isEnabled = value; + } + _self.countRequest = (endpoint: string, duration: number, success: boolean) => { - console.log("Statsbeat countRequest called", endpoint, duration, success); if (!_isEnabled || !_checkEndpoint(endpoint)) { return; } @@ -128,7 +130,8 @@ export class Statsbeat implements IStatsBeat { name: NETWORK, average: 0, properties: {"host": _networkCounter.host, ..._statsbeatMetrics.properties, ...networkProperties} - } + }, + baseType: "StatsbeatData" // baseType: Metric.dataType }; _channel.processTelemetry(statsbeat); @@ -184,7 +187,7 @@ export class Statsbeat implements IStatsBeat { }) } - public initialize(ikey: string, channel: IChannelControls, endpoint: string) { + public initialize(ikey: string, channel: IChannelControls, endpoint: string, version?: string) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } @@ -193,6 +196,10 @@ export class Statsbeat implements IStatsBeat { return false; } + public setInitialized(value: boolean) { + // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging + } + public countRequest(endpoint: string, duration: number, success: boolean) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } From 3f5ae6c4339eed33d6c49c942a114714ab8ad0de Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Wed, 5 Mar 2025 16:25:05 -0800 Subject: [PATCH 04/62] Update StatsBeat.ts --- shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 2625faec2..99e494420 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -131,8 +131,7 @@ export class Statsbeat implements IStatsBeat { average: 0, properties: {"host": _networkCounter.host, ..._statsbeatMetrics.properties, ...networkProperties} }, - baseType: "StatsbeatData" - // baseType: Metric.dataType + baseType: "MetricData" }; _channel.processTelemetry(statsbeat); } From 0711bf795c6ebd344c0feb4d5a7d202e37636471 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Wed, 5 Mar 2025 16:37:48 -0800 Subject: [PATCH 05/62] only check statsbeat before send it --- .../src/Sender.ts | 7 +++--- .../JavaScriptSDK.Interfaces/IStatsBeat.ts | 3 ++- .../src/JavaScriptSDK/StatsBeat.ts | 23 +++++++++++-------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 50156b536..455450875 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -655,7 +655,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { _consecutiveErrors = 0; _self._onSuccess(payload, 0); var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - _statsBeat.countRequest(endpointHost, dateNow() - statsBeatData.startTime, true); + _statsBeat.countRequest(endpointHost, statsBeatData, true); } else { const results = parseResponse(responseText); @@ -1047,8 +1047,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { _self._onError(payload, errorMessage); } } else { - let endTime = dateNow(); - _statsBeat.countRequest(responseUrl, endTime - statsBeatData.startTime, status === 200); + _statsBeat.countRequest(responseUrl, statsBeatData, status === 200); // check if the xhr's responseURL or fetch's response.url is same as endpoint url // TODO after 10 redirects force send telemetry with 'redirect=false' as query parameter. _checkAndUpdateEndPointUrl(responseUrl); @@ -1115,7 +1114,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { // Can't send anymore, so split the batch and drop the rest droppedPayload.push(thePayload); } else { - _statsBeat.countRequest(urlParseUrl(_self._senderConfig.endpointUrl).hostname, dateNow() - payload.statsBeatData.startTime, true); + _statsBeat.countRequest(urlParseUrl(_self._senderConfig.endpointUrl).hostname, payload.statsBeatData, true); _self._onSuccess(arr, arr.length); } } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts index 81676ff45..5b831aad3 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts @@ -1,10 +1,11 @@ import { IChannelControls } from "./IChannelControls"; +import { IStatsBeatEvent } from "./IStatsBeatEvent"; export interface IStatsBeat { initialize(ikey: string, channel: IChannelControls, endpoint: string, version?: string): void; isInitialized(): boolean; setInitialized(value: boolean): void; - countRequest(endpoint: string, duration: number, success: boolean): void; + countRequest(endpoint: string, statsBeatData: IStatsBeatEvent, success: boolean): void; countException(endpoint: string): void; countThrottle(endpoint: string): void; countRetry(endpoint: string): void; diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 99e494420..f5bab2a71 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -2,6 +2,7 @@ import dynamicProto from "@microsoft/dynamicproto-js"; import { objKeys, utcNow } from "@nevware21/ts-utils"; import { IChannelControls } from "../JavaScriptSDK.Interfaces/IChannelControls"; import { IStatsBeat } from "../JavaScriptSDK.Interfaces/IStatsBeat"; +import { IStatsBeatEvent } from "../JavaScriptSDK.Interfaces/IStatsBeatEvent"; import { ITelemetryItem } from "../JavaScriptSDK.Interfaces/ITelemetryItem"; import { NetworkStatsbeat } from "./NetworkStatsbeat"; @@ -41,14 +42,14 @@ export class Statsbeat implements IStatsBeat { _isEnabled = true; _channel = channel; _sdkVersion = version; - if (_isEnabled) { - _getCustomProperties(ikey); - if (!_handle) { - _handle = setInterval(() => { - this.trackShortIntervalStatsbeats(); - }, STATS_COLLECTION_SHORT_INTERVAL); - } + + _getCustomProperties(ikey); + if (!_handle) { + _handle = setInterval(() => { + this.trackShortIntervalStatsbeats(); + }, STATS_COLLECTION_SHORT_INTERVAL); } + } _self.isInitialized = (): boolean => { @@ -59,12 +60,14 @@ export class Statsbeat implements IStatsBeat { _isEnabled = value; } - _self.countRequest = (endpoint: string, duration: number, success: boolean) => { + _self.countRequest = (endpoint: string, statsBeatData: IStatsBeatEvent, success: boolean) => { if (!_isEnabled || !_checkEndpoint(endpoint)) { return; } _networkCounter.totalRequestCount++; - _networkCounter.intervalRequestExecutionTime += duration; + if (statsBeatData && statsBeatData.startTime) { + _networkCounter.intervalRequestExecutionTime += utcNow() - statsBeatData.startTime; + } if (success === false) { _networkCounter.totalFailedRequestCount++; } else { @@ -199,7 +202,7 @@ export class Statsbeat implements IStatsBeat { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } - public countRequest(endpoint: string, duration: number, success: boolean) { + public countRequest(endpoint: string, statsBeatData: IStatsBeatEvent, success: boolean) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } From 94a090eff24374016f9138eac819b92d0565bef8 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 11 Mar 2025 15:43:47 -0700 Subject: [PATCH 06/62] refactor --- .../src/Sender.ts | 6 +- .../Unit/src/AppInsightsCoreSize.Tests.ts | 4 +- .../src/JavaScriptSDK/StatsBeat.ts | 55 +++++++------------ 3 files changed, 26 insertions(+), 39 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 455450875..33bca4659 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -522,12 +522,12 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { /** * xhr state changes */ - _self._xhrReadyStateChange = (xhr: XMLHttpRequest, payload: string[] | IInternalStorageItem[], countOfItemsInPayload: number) => { + _self._xhrReadyStateChange = (xhr: XMLHttpRequest, payload: string[] | IInternalStorageItem[], countOfItemsInPayload: number, statsBeat?: IStatsBeatEvent) => { // since version 3.2.0, this function is no-op if (_isStringArr(payload)) { return; } - return _xhrReadyStateChange(xhr, payload as IInternalStorageItem[], countOfItemsInPayload); + return _xhrReadyStateChange(xhr, payload as IInternalStorageItem[], countOfItemsInPayload, statsBeat); } @@ -1409,7 +1409,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { * @deprecated * since version 3.2.0, if the payload is string[], this function is no-op (string[] is only used for backwards Compatibility) */ - public _xhrReadyStateChange(xhr: XMLHttpRequest, payload: string[] | IInternalStorageItem[], countOfItemsInPayload: number) { + public _xhrReadyStateChange(xhr: XMLHttpRequest, payload: string[] | IInternalStorageItem[], countOfItemsInPayload: number, statsBeat?: IStatsBeatEvent) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging // TODO: no-op // add note to users, this will be removed diff --git a/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts index a624e8008..c8da7b41d 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts @@ -51,8 +51,8 @@ function _checkSize(checkType: string, maxSize: number, size: number, isNightly: } export class AppInsightsCoreSizeCheck extends AITestClass { - private readonly MAX_RAW_SIZE = 65; - private readonly MAX_BUNDLE_SIZE = 65; + private readonly MAX_RAW_SIZE = 67; + private readonly MAX_BUNDLE_SIZE = 67; private readonly MAX_RAW_DEFLATE_SIZE = 28; private readonly MAX_BUNDLE_DEFLATE_SIZE = 28; private readonly rawFilePath = "../dist/es5/applicationinsights-core-js.min.js"; diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index f5bab2a71..a62973701 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -6,15 +6,6 @@ import { IStatsBeatEvent } from "../JavaScriptSDK.Interfaces/IStatsBeatEvent"; import { ITelemetryItem } from "../JavaScriptSDK.Interfaces/ITelemetryItem"; import { NetworkStatsbeat } from "./NetworkStatsbeat"; -export const StatsbeatCounter = { - REQUEST_SUCCESS: "Request Success Count", - REQUEST_FAILURE: "Requests Failure Count", - REQUEST_DURATION: "Request Duration", - RETRY_COUNT: "Retry Count", - THROTTLE_COUNT: "Throttle Count", - EXCEPTION_COUNT: "Exception Count" -} - const INSTRUMENTATION_KEY = "c4a29126-a7cb-47e5-b348-11414998b11e"; const STATS_COLLECTION_SHORT_INTERVAL: number = 900000; // 15 minutes const NETWORK = "Network"; @@ -98,9 +89,8 @@ export class Statsbeat implements IStatsBeat { } _self.trackShortIntervalStatsbeats = (): void => { - _trackRequestDuration(); - _trackRequestsCount(); - _sendStatsbeats(); + _trackSendRequestDuration(); + _trackSendRequestsCount(); } function _checkEndpoint(endpoint: string) { @@ -114,25 +104,27 @@ export class Statsbeat implements IStatsBeat { _runTimeVersion = STATSBEAT_TYPE; } - - - function _sendStatsbeats() { + function _sendStatsbeats(name: string, val: number, properties?: {}) { // Add extra properties - let networkProperties = { + let baseProperties = { + "rp": "unknown", + "attach": "Manual", "cikey": _cikey, "runtimeVersion": _runTimeVersion, + "os": _os, "language": _language, "version": _sdkVersion, - "os": _os + "endpoint": "breeze", + "host": _networkCounter.host } if (objKeys(_statsbeatMetrics)) { let statsbeat: ITelemetryItem = { iKey: INSTRUMENTATION_KEY, - name: NETWORK, + name: name, baseData: { - name: NETWORK, - average: 0, - properties: {"host": _networkCounter.host, ..._statsbeatMetrics.properties, ...networkProperties} + name: name, + average: val, + properties: {"host": _networkCounter.host, ...properties, ...baseProperties} }, baseType: "MetricData" }; @@ -142,7 +134,7 @@ export class Statsbeat implements IStatsBeat { _channel.flush(true); } - function _trackRequestDuration() { + function _trackSendRequestDuration() { var currentCounter = _networkCounter; currentCounter.time = utcNow(); var intervalRequests = (currentCounter.totalRequestCount - currentCounter.lastRequestCount) || 0; @@ -151,38 +143,33 @@ export class Statsbeat implements IStatsBeat { currentCounter.lastIntervalRequestExecutionTime = currentCounter.intervalRequestExecutionTime; // reset if (elapsedMs > 0 && intervalRequests > 0) { _statsbeatMetrics.properties = _statsbeatMetrics.properties || {}; - _statsbeatMetrics.properties[StatsbeatCounter.REQUEST_DURATION] = averageRequestExecutionTime; + _sendStatsbeats("Request_Duration", averageRequestExecutionTime); } // Set last counters currentCounter.lastRequestCount = currentCounter.totalRequestCount; currentCounter.lastTime = currentCounter.time; } - function _trackRequestsCount() { + function _trackSendRequestsCount() { var currentCounter = _networkCounter; if (currentCounter.totalSuccesfulRequestCount > 0) { - _statsbeatMetrics.properties = _statsbeatMetrics.properties || {}; - _statsbeatMetrics.properties[StatsbeatCounter.REQUEST_SUCCESS] = currentCounter.totalSuccesfulRequestCount; + _sendStatsbeats("Request_Success_Count", currentCounter.totalSuccesfulRequestCount); currentCounter.totalSuccesfulRequestCount = 0; //Reset } if (currentCounter.totalFailedRequestCount > 0) { - _statsbeatMetrics.properties = _statsbeatMetrics.properties || {}; - _statsbeatMetrics.properties[StatsbeatCounter.REQUEST_FAILURE] = currentCounter.totalFailedRequestCount; + _sendStatsbeats("Requests_Failure_Count", currentCounter.totalFailedRequestCount); currentCounter.totalFailedRequestCount = 0; //Reset } if (currentCounter.retryCount > 0) { - _statsbeatMetrics.properties = _statsbeatMetrics.properties || {}; - _statsbeatMetrics.properties[StatsbeatCounter.RETRY_COUNT] = currentCounter.retryCount; + _sendStatsbeats("Retry_Count", currentCounter.retryCount); currentCounter.retryCount = 0; //Reset } if (currentCounter.throttleCount > 0) { - _statsbeatMetrics.properties = _statsbeatMetrics.properties || {}; - _statsbeatMetrics.properties[StatsbeatCounter.THROTTLE_COUNT] = currentCounter.throttleCount; + _sendStatsbeats("Throttle_Count", currentCounter.throttleCount); currentCounter.throttleCount = 0; //Reset } if (currentCounter.exceptionCount > 0) { - _statsbeatMetrics.properties = _statsbeatMetrics.properties || {}; - _statsbeatMetrics.properties[StatsbeatCounter.EXCEPTION_COUNT] = currentCounter.exceptionCount; + _sendStatsbeats("Exception_Count", currentCounter.exceptionCount); currentCounter.exceptionCount = 0; //Reset } } From 5cbac358903f4682e9da330643173dc27e600d9f Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 17 Mar 2025 15:28:04 -0700 Subject: [PATCH 07/62] remove statsbeatdata from function call --- .../src/Sender.ts | 56 ++++++++-------- .../JavaScriptSDK.Interfaces/IStatsBeat.ts | 4 +- .../src/JavaScriptSDK/NetworkStatsbeat.ts | 8 +-- .../src/JavaScriptSDK/StatsBeat.ts | 64 ++++++++----------- 4 files changed, 58 insertions(+), 74 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 33bca4659..96988b63d 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -36,6 +36,7 @@ const FetchSyncRequestSizeLimitBytes = 65000; // approx 64kb (the current Edge, interface IInternalPayloadData extends IPayloadData { oriPayload: IInternalStorageItem[]; retryCnt?: number; + statsBeatData?: IStatsBeatEvent; } @@ -273,6 +274,9 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let curExtUrl = senderConfig.endpointUrl; _statsBeat = core.getStatsBeat(); + if (config.disableStatsBeat !== false){ + _statsBeat.setInitialized(false); + } if (_statsBeat && !_statsBeat.isInitialized()) { _statsBeat.setInitialized(true); // otherwise, it will fall into infinite loop of creating new sender let senderConfig = {...config}; @@ -522,7 +526,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { /** * xhr state changes */ - _self._xhrReadyStateChange = (xhr: XMLHttpRequest, payload: string[] | IInternalStorageItem[], countOfItemsInPayload: number, statsBeat?: IStatsBeatEvent) => { + _self._xhrReadyStateChange = (xhr: XMLHttpRequest, payload: string[] | IInternalStorageItem[], countOfItemsInPayload: number) => { // since version 3.2.0, this function is no-op if (_isStringArr(payload)) { return; @@ -640,22 +644,21 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { /** * xdr state changes */ - _self._xdrOnLoad = (xdr: IXDomainRequest, payload: IInternalStorageItem[] | string[], statsBeatData?: IStatsBeatEvent) => { + _self._xdrOnLoad = (xdr: IXDomainRequest, payload: IInternalStorageItem[] | string[]) => { // since version 3.1.3, string[] is no-op if (_isStringArr(payload)) { return; } - return _xdrOnLoad(xdr, payload as IInternalStorageItem[], statsBeatData); + return _xdrOnLoad(xdr, payload as IInternalStorageItem[]); } - function _xdrOnLoad (xdr: IXDomainRequest, payload: IInternalStorageItem[], statsBeatData?: IStatsBeatEvent) { + function _xdrOnLoad (xdr: IXDomainRequest, payload: IInternalStorageItem[]) { const responseText = _getResponseText(xdr); if (xdr && (responseText + "" === "200" || responseText === "")) { _consecutiveErrors = 0; _self._onSuccess(payload, 0); var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - _statsBeat.countRequest(endpointHost, statsBeatData, true); } else { const results = parseResponse(responseText); @@ -673,26 +676,26 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { try { let onCompleteFuncs = { xdrOnComplete: (xdr: IXDomainRequest, oncomplete: OnCompleteCallback,payload?: IPayloadData) => { - let { payloadArr = null, statsBeat = null } = _getPayloadArr(payload); + let payloadArr = _getPayloadArr(payload); if (!payloadArr) { return; } - return _xdrOnLoad(xdr, payloadArr, statsBeat); + return _xdrOnLoad(xdr, payloadArr); }, fetchOnComplete: (response: Response, onComplete: OnCompleteCallback, resValue?: string, payload?: IPayloadData) => { - let { payloadArr = null, statsBeat = null } = _getPayloadArr(payload); + let payloadArr = _getPayloadArr(payload); if (!payloadArr) { return; } - return _checkResponsStatus(response.status, payloadArr, response.url, payloadArr.length, response.statusText, resValue || "", statsBeat); + return _checkResponsStatus(response.status, payloadArr, response.url, payloadArr.length, response.statusText, resValue || ""); }, xhrOnComplete: (request: XMLHttpRequest, oncomplete: OnCompleteCallback, payload?: IPayloadData) => { - let { payloadArr = null, statsBeat = null } = _getPayloadArr(payload); + let payloadArr = _getPayloadArr(payload); if (!payloadArr) { return; } - return _xhrReadyStateChange(request, payloadArr, payloadArr.length, statsBeat); + return _xhrReadyStateChange(request, payloadArr, payloadArr.length); }, beaconOnRetry: (data: IPayloadData, onComplete: OnCompleteCallback, canSend: (payload: IPayloadData, oncomplete: OnCompleteCallback, sync?: boolean) => boolean) => { @@ -724,10 +727,10 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { /** * xhr state changes */ - function _xhrReadyStateChange (xhr: XMLHttpRequest, payload: IInternalStorageItem[], countOfItemsInPayload: number, statsBeat?: IStatsBeatEvent) { + function _xhrReadyStateChange (xhr: XMLHttpRequest, payload: IInternalStorageItem[], countOfItemsInPayload: number) { if (xhr.readyState === 4) { - _checkResponsStatus(xhr.status, payload, xhr.responseURL, countOfItemsInPayload, formatErrorMessageXhr(xhr), _getResponseText(xhr) || xhr.response, statsBeat); + _checkResponsStatus(xhr.status, payload, xhr.responseURL, countOfItemsInPayload, formatErrorMessageXhr(xhr), _getResponseText(xhr) || xhr.response); } } @@ -748,7 +751,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { /** * partial success handler */ - function _onPartialSuccess(payload: IInternalStorageItem[], results: IBackendResponse, statsBeatData?: IStatsBeatEvent) { + function _onPartialSuccess(payload: IInternalStorageItem[], results: IBackendResponse) { const failed: IInternalStorageItem[] = []; const retry: IInternalStorageItem[] = []; @@ -797,17 +800,16 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (payload) { let internalPayload = payload as IInternalPayloadData; let arr = internalPayload.oriPayload; - let statsBeat = internalPayload.statsBeatData; if (arr && arr.length) { - return { payloadArr: arr, statsBeat }; + return arr; } - return { payloadArr: null, statsBeat: undefined }; + return null; } } catch (e) { // eslint-disable-next-line no-empty } - return { payloadArr: null, statsBeat: undefined }; + return null; } @@ -943,6 +945,8 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { function _doSend(sendInterface: IXHROverride, payload: IInternalStorageItem[], isAsync: boolean, markAsSent: boolean = true): void | IPromise { let onComplete = (status: number, headers: {[headerName: string]: string;}, response?: string) => { + console.log("onComplete", status, headers, response, payloadData.statsBeatData.startTime); + _statsBeat.count(status, headers, response, payloadData); return _getOnComplete(payload, status, headers, response); } let payloadData = _getPayload(payload); @@ -1005,7 +1009,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { return false; } - function _checkResponsStatus(status: number, payload: IInternalStorageItem[], responseUrl: string, countOfItemsInPayload: number, errorMessage: string, res: any, statsBeatData?: IStatsBeatEvent) { + function _checkResponsStatus(status: number, payload: IInternalStorageItem[], responseUrl: string, countOfItemsInPayload: number, errorMessage: string, res: any) { let response: IBackendResponse = null; if (!_self._appId) { response = parseResponse(res); @@ -1047,7 +1051,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { _self._onError(payload, errorMessage); } } else { - _statsBeat.countRequest(responseUrl, statsBeatData, status === 200); // check if the xhr's responseURL or fetch's response.url is same as endpoint url // TODO after 10 redirects force send telemetry with 'redirect=false' as query parameter. _checkAndUpdateEndPointUrl(responseUrl); @@ -1114,7 +1117,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { // Can't send anymore, so split the batch and drop the rest droppedPayload.push(thePayload); } else { - _statsBeat.countRequest(urlParseUrl(_self._senderConfig.endpointUrl).hostname, payload.statsBeatData, true); _self._onSuccess(arr, arr.length); } } @@ -1124,7 +1126,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } } else { _fallbackSend && _fallbackSend(data, true); - _statsBeat.countException(urlParseUrl(_self._senderConfig.endpointUrl).hostname); _throwInternal(_self.diagLog(), eLoggingSeverity.WARNING, _eInternalMessageId.TransmissionFailed, ". " + "Failed to send telemetry with Beacon API, retried with normal sender."); } @@ -1180,7 +1181,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (!payload || payload.length === 0) { return; } - _statsBeat.countRetry(urlParseUrl(_self._senderConfig.endpointUrl).hostname); const buffer = _self._buffer; buffer.clearSent(payload); @@ -1409,7 +1409,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { * @deprecated * since version 3.2.0, if the payload is string[], this function is no-op (string[] is only used for backwards Compatibility) */ - public _xhrReadyStateChange(xhr: XMLHttpRequest, payload: string[] | IInternalStorageItem[], countOfItemsInPayload: number, statsBeat?: IStatsBeatEvent) { + public _xhrReadyStateChange(xhr: XMLHttpRequest, payload: string[] | IInternalStorageItem[], countOfItemsInPayload: number) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging // TODO: no-op // add note to users, this will be removed @@ -1435,7 +1435,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { * @Internal * since version 3.2.0, if the payload is string[], this function is no-op (string[] is only used for backwards Compatibility) */ - public _onError(payload: string[] | IInternalStorageItem[], message: string, event?: ErrorEvent, statsBeatData?: IStatsBeatEvent) { + public _onError(payload: string[] | IInternalStorageItem[], message: string, event?: ErrorEvent) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } @@ -1444,7 +1444,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { * @Internal * since version 3.2.0, if the payload is string[], this function is no-op (string[] is only used for backwards Compatibility) */ - public _onPartialSuccess(payload: string[] | IInternalStorageItem[], results: IBackendResponse, statsBeatData?: IStatsBeatEvent) { + public _onPartialSuccess(payload: string[] | IInternalStorageItem[], results: IBackendResponse) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } @@ -1453,7 +1453,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { * @Internal * since version 3.2.0, if the payload is string[], this function is no-op (string[] is only used for backwards Compatibility) */ - public _onSuccess(payload: string[] | IInternalStorageItem[], countOfItemsInPayload: number, statsBeatData?: IStatsBeatEvent) { + public _onSuccess(payload: string[] | IInternalStorageItem[], countOfItemsInPayload: number) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } @@ -1462,7 +1462,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { * @deprecated * since version 3.2.0, if the payload is string[], this function is no-op (string[] is only used for backwards Compatibility) */ - public _xdrOnLoad(xdr: IXDomainRequest, payload: string[] | IInternalStorageItem[], statsBeatData?: IStatsBeatEvent) { + public _xdrOnLoad(xdr: IXDomainRequest, payload: string[] | IInternalStorageItem[]) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts index 5b831aad3..6caa66813 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts @@ -5,9 +5,7 @@ export interface IStatsBeat { initialize(ikey: string, channel: IChannelControls, endpoint: string, version?: string): void; isInitialized(): boolean; setInitialized(value: boolean): void; - countRequest(endpoint: string, statsBeatData: IStatsBeatEvent, success: boolean): void; + count(status: number, payloadData: IStatsBeatEvent, endpoint: string): void; countException(endpoint: string): void; - countThrottle(endpoint: string): void; - countRetry(endpoint: string): void; trackShortIntervalStatsbeats(): void; } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts index 3f57e3017..e3ef4670d 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts @@ -12,9 +12,9 @@ export class NetworkStatsbeat { public lastRequestCount: number; - public totalSuccesfulRequestCount: number; + public succesfulRequestCount: number; - public totalFailedRequestCount: number; + public failedRequestCount: number; public retryCount: number; @@ -29,8 +29,8 @@ export class NetworkStatsbeat { constructor(host: string) { this.host = host; this.totalRequestCount = 0; - this.totalSuccesfulRequestCount = 0; - this.totalFailedRequestCount = 0; + this.succesfulRequestCount = 0; + this.failedRequestCount = 0; this.retryCount = 0; this.exceptionCount = 0; this.throttleCount = 0; diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index a62973701..5b69569f2 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -1,5 +1,5 @@ import dynamicProto from "@microsoft/dynamicproto-js"; -import { objKeys, utcNow } from "@nevware21/ts-utils"; +import { objKeys, strIncludes, utcNow } from "@nevware21/ts-utils"; import { IChannelControls } from "../JavaScriptSDK.Interfaces/IChannelControls"; import { IStatsBeat } from "../JavaScriptSDK.Interfaces/IStatsBeat"; import { IStatsBeatEvent } from "../JavaScriptSDK.Interfaces/IStatsBeatEvent"; @@ -51,22 +51,29 @@ export class Statsbeat implements IStatsBeat { _isEnabled = value; } - _self.countRequest = (endpoint: string, statsBeatData: IStatsBeatEvent, success: boolean) => { + _self.count = (status, payloadData, endpoint) => { if (!_isEnabled || !_checkEndpoint(endpoint)) { return; } _networkCounter.totalRequestCount++; - if (statsBeatData && statsBeatData.startTime) { - _networkCounter.intervalRequestExecutionTime += utcNow() - statsBeatData.startTime; + if (payloadData && payloadData.startTime) { + _networkCounter.intervalRequestExecutionTime += utcNow() - payloadData.startTime; } - if (success === false) { - _networkCounter.totalFailedRequestCount++; + if (status === 200) { + _networkCounter.succesfulRequestCount++; + } else if (strIncludes("307,308,401,402,403,408,429,439,500,503", status.toString())) { + // These statuses are not considered failures + if (strIncludes("401,403,408,429,500,503", status.toString())) { + _networkCounter.retryCount++; + } + if (strIncludes("402,439", status.toString())) { + _networkCounter.throttleCount++; + } } else { - _networkCounter.totalSuccesfulRequestCount++; + _networkCounter.failedRequestCount++; } - - } - + }; + _self.countException = (endpoint: string) => { if (!_isEnabled || !_checkEndpoint(endpoint)) { return; @@ -74,19 +81,6 @@ export class Statsbeat implements IStatsBeat { _networkCounter.exceptionCount++; } - _self.countThrottle = (endpoint: string) => { - if (!_isEnabled || !_checkEndpoint(endpoint)) { - return; - } - _networkCounter.throttleCount++; - } - - _self.countRetry = (endpoint: string) => { - if (!_isEnabled || !_checkEndpoint(endpoint)) { - return; - } - _networkCounter.retryCount++; - } _self.trackShortIntervalStatsbeats = (): void => { _trackSendRequestDuration(); @@ -152,13 +146,13 @@ export class Statsbeat implements IStatsBeat { function _trackSendRequestsCount() { var currentCounter = _networkCounter; - if (currentCounter.totalSuccesfulRequestCount > 0) { - _sendStatsbeats("Request_Success_Count", currentCounter.totalSuccesfulRequestCount); - currentCounter.totalSuccesfulRequestCount = 0; //Reset + if (currentCounter.succesfulRequestCount > 0) { + _sendStatsbeats("Request_Success_Count", currentCounter.succesfulRequestCount); + currentCounter.succesfulRequestCount = 0; //Reset } - if (currentCounter.totalFailedRequestCount > 0) { - _sendStatsbeats("Requests_Failure_Count", currentCounter.totalFailedRequestCount); - currentCounter.totalFailedRequestCount = 0; //Reset + if (currentCounter.failedRequestCount > 0) { + _sendStatsbeats("Requests_Failure_Count", currentCounter.failedRequestCount); + currentCounter.failedRequestCount = 0; //Reset } if (currentCounter.retryCount > 0) { _sendStatsbeats("Retry_Count", currentCounter.retryCount); @@ -189,22 +183,14 @@ export class Statsbeat implements IStatsBeat { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } - public countRequest(endpoint: string, statsBeatData: IStatsBeatEvent, success: boolean) { + public count(status: number, payloadData: any, endpoint: string) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } - + public countException(endpoint: string) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } - public countThrottle(endpoint: string) { - // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging - } - - public countRetry(endpoint: string) { - // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging - } - public trackShortIntervalStatsbeats() { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } From 9913e66a8d2cb7ff596b4c910c3d306a32bb5ca7 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 17 Mar 2025 15:29:17 -0700 Subject: [PATCH 08/62] remove --- .../AppInsightsCore/src/JavaScriptSDK.Interfaces/IXHROverride.ts | 1 - shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IXHROverride.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IXHROverride.ts index 7749b8cfe..137e2e6d1 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IXHROverride.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IXHROverride.ts @@ -10,7 +10,6 @@ export interface IPayloadData { disableXhrSync?: boolean; disableFetchKeepAlive?: boolean; sendReason?: SendRequestReason; - statsBeatData?: IStatsBeatEvent; } /** diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index d5005bdcb..b0f03bf22 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -1436,6 +1436,7 @@ export class AppInsightsCore im } public getStatsBeat(): IStatsBeat { + // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging return null; } From 31811e7c72c4e05cd60e97c0722c7d41315cf2fa Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 17 Mar 2025 15:37:19 -0700 Subject: [PATCH 09/62] refactor statsbeat --- .../JavaScriptSDK.Interfaces/IStatsBeat.ts | 4 +- .../JavaScriptSDK.Interfaces/IXHROverride.ts | 6 +-- .../src/JavaScriptSDK/StatsBeat.ts | 47 +++++++------------ 3 files changed, 19 insertions(+), 38 deletions(-) diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts index 6caa66813..4f5932251 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts @@ -1,8 +1,8 @@ -import { IChannelControls } from "./IChannelControls"; +import { IAppInsightsCore } from "./IAppInsightsCore"; import { IStatsBeatEvent } from "./IStatsBeatEvent"; export interface IStatsBeat { - initialize(ikey: string, channel: IChannelControls, endpoint: string, version?: string): void; + initialize(core: IAppInsightsCore, ikey: string, endpoint: string, version?: string) : void; isInitialized(): boolean; setInitialized(value: boolean): void; count(status: number, payloadData: IStatsBeatEvent, endpoint: string): void; diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IXHROverride.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IXHROverride.ts index 137e2e6d1..641dadde0 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IXHROverride.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IXHROverride.ts @@ -1,5 +1,5 @@ import { IPromise } from "@nevware21/ts-async"; -import { IStatsBeatEvent, SendRequestReason } from "../applicationinsights-core-js"; +import { SendRequestReason } from "../applicationinsights-core-js"; /** IPayloadData describes interface of payload sent via POST channel */ export interface IPayloadData { @@ -30,7 +30,3 @@ export type OnCompleteCallback = (status: number, headers: { [headerName: string export interface IXHROverride { sendPOST: SendPOSTFunction; } - - - - diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 5b69569f2..11c9b767b 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -2,13 +2,12 @@ import dynamicProto from "@microsoft/dynamicproto-js"; import { objKeys, strIncludes, utcNow } from "@nevware21/ts-utils"; import { IChannelControls } from "../JavaScriptSDK.Interfaces/IChannelControls"; import { IStatsBeat } from "../JavaScriptSDK.Interfaces/IStatsBeat"; -import { IStatsBeatEvent } from "../JavaScriptSDK.Interfaces/IStatsBeatEvent"; import { ITelemetryItem } from "../JavaScriptSDK.Interfaces/ITelemetryItem"; import { NetworkStatsbeat } from "./NetworkStatsbeat"; +import { IAppInsightsCore } from "../JavaScriptSDK.Interfaces/IAppInsightsCore"; const INSTRUMENTATION_KEY = "c4a29126-a7cb-47e5-b348-11414998b11e"; const STATS_COLLECTION_SHORT_INTERVAL: number = 900000; // 15 minutes -const NETWORK = "Network"; const STATSBEAT_LANGUAGE = "JavaScript"; const STATSBEAT_TYPE = "Browser"; @@ -16,9 +15,8 @@ export class Statsbeat implements IStatsBeat { constructor() { let _networkCounter: NetworkStatsbeat; let _handle: any; - let _statsbeatMetrics: { properties?: {} }; let _isEnabled: boolean; - let _channel: IChannelControls; + let _core: IAppInsightsCore; // Custom dimensions let _cikey: string; @@ -27,11 +25,10 @@ export class Statsbeat implements IStatsBeat { let _os: string; let _runTimeVersion: string; dynamicProto(Statsbeat, this, (_self, _base) => { - _self.initialize = (ikey: string, channel: IChannelControls, endpoint: string, version?: string) => { + _self.initialize = (core: IAppInsightsCore, ikey: string, endpoint: string, version?: string) => { + _core = core; _networkCounter = new NetworkStatsbeat(endpoint); - _statsbeatMetrics = {}; _isEnabled = true; - _channel = channel; _sdkVersion = version; _getCustomProperties(ikey); @@ -85,6 +82,7 @@ export class Statsbeat implements IStatsBeat { _self.trackShortIntervalStatsbeats = (): void => { _trackSendRequestDuration(); _trackSendRequestsCount(); + _networkCounter = new NetworkStatsbeat(_networkCounter.host); } function _checkEndpoint(endpoint: string) { @@ -111,21 +109,17 @@ export class Statsbeat implements IStatsBeat { "endpoint": "breeze", "host": _networkCounter.host } - if (objKeys(_statsbeatMetrics)) { - let statsbeat: ITelemetryItem = { - iKey: INSTRUMENTATION_KEY, + let statsbeatEvent: ITelemetryItem = { + iKey: INSTRUMENTATION_KEY, + name: name, + baseData: { name: name, - baseData: { - name: name, - average: val, - properties: {"host": _networkCounter.host, ...properties, ...baseProperties} - }, - baseType: "MetricData" - }; - _channel.processTelemetry(statsbeat); - } - _statsbeatMetrics = {}; - _channel.flush(true); + average: val, + properties: {"host": _networkCounter.host, ...properties, ...baseProperties} + }, + baseType: "MetricData" + }; + _core.track(statsbeatEvent); } function _trackSendRequestDuration() { @@ -136,41 +130,32 @@ export class Statsbeat implements IStatsBeat { var averageRequestExecutionTime = ((currentCounter.intervalRequestExecutionTime - currentCounter.lastIntervalRequestExecutionTime) / intervalRequests) || 0; currentCounter.lastIntervalRequestExecutionTime = currentCounter.intervalRequestExecutionTime; // reset if (elapsedMs > 0 && intervalRequests > 0) { - _statsbeatMetrics.properties = _statsbeatMetrics.properties || {}; _sendStatsbeats("Request_Duration", averageRequestExecutionTime); } - // Set last counters - currentCounter.lastRequestCount = currentCounter.totalRequestCount; - currentCounter.lastTime = currentCounter.time; } function _trackSendRequestsCount() { var currentCounter = _networkCounter; if (currentCounter.succesfulRequestCount > 0) { _sendStatsbeats("Request_Success_Count", currentCounter.succesfulRequestCount); - currentCounter.succesfulRequestCount = 0; //Reset } if (currentCounter.failedRequestCount > 0) { _sendStatsbeats("Requests_Failure_Count", currentCounter.failedRequestCount); - currentCounter.failedRequestCount = 0; //Reset } if (currentCounter.retryCount > 0) { _sendStatsbeats("Retry_Count", currentCounter.retryCount); - currentCounter.retryCount = 0; //Reset } if (currentCounter.throttleCount > 0) { _sendStatsbeats("Throttle_Count", currentCounter.throttleCount); - currentCounter.throttleCount = 0; //Reset } if (currentCounter.exceptionCount > 0) { _sendStatsbeats("Exception_Count", currentCounter.exceptionCount); - currentCounter.exceptionCount = 0; //Reset } } }) } - public initialize(ikey: string, channel: IChannelControls, endpoint: string, version?: string) { + public initialize(core: IAppInsightsCore, ikey: string, endpoint: string, version?: string) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } From a6ba0fb983abc3799c267bae875887c56d5aa367 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 17 Mar 2025 22:52:09 -0700 Subject: [PATCH 10/62] count in a different way --- .../src/Sender.ts | 19 +- common/config/rush/npm-shrinkwrap.json | 252 +++++++++--------- .../JavaScriptSDK.Interfaces/IStatsBeat.ts | 6 +- .../src/JavaScriptSDK/NetworkStatsbeat.ts | 7 + .../src/JavaScriptSDK/StatsBeat.ts | 45 ++-- 5 files changed, 177 insertions(+), 152 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 96988b63d..f7fd961b3 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -27,7 +27,6 @@ import { ArraySendBuffer, ISendBuffer, SessionStorageSendBuffer } from "./SendBu import { Serializer } from "./Serializer"; import { Sample } from "./TelemetryProcessors/Sample"; -const INSTRUMENTATION_KEY = "c4a29126-a7cb-47e5-b348-11414998b11e"; const UNDEFINED_VALUE: undefined = undefined; const EMPTY_STR = ""; @@ -274,17 +273,14 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let curExtUrl = senderConfig.endpointUrl; _statsBeat = core.getStatsBeat(); - if (config.disableStatsBeat !== false){ - _statsBeat.setInitialized(false); - } + if (_statsBeat && !_statsBeat.isInitialized()) { _statsBeat.setInitialized(true); // otherwise, it will fall into infinite loop of creating new sender - let senderConfig = {...config}; - senderConfig.instrumentationKey = INSTRUMENTATION_KEY; - let statsBeatSender = new Sender(); - statsBeatSender.initialize(senderConfig, core, extensions, pluginChain); var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - _statsBeat.initialize(senderConfig.instrumentationKey, statsBeatSender, endpointHost, EnvelopeCreator.Version); + _statsBeat.initialize(core, senderConfig.instrumentationKey, endpointHost, EnvelopeCreator.Version); + } + if (config.disableStatsBeat !== false){ + _statsBeat.setInitialized(false); } // if it is not inital change (_endpointUrl has value) // if current sender endpoint url is not changed directly @@ -746,7 +742,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { _self._buffer && _self._buffer.clearSent(payload); var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - _statsBeat.countException(endpointHost); + _statsBeat.countException(endpointHost, event); } /** * partial success handler @@ -946,7 +942,8 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { function _doSend(sendInterface: IXHROverride, payload: IInternalStorageItem[], isAsync: boolean, markAsSent: boolean = true): void | IPromise { let onComplete = (status: number, headers: {[headerName: string]: string;}, response?: string) => { console.log("onComplete", status, headers, response, payloadData.statsBeatData.startTime); - _statsBeat.count(status, headers, response, payloadData); + var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; + _statsBeat.count(status, payloadData, endpointHost); return _getOnComplete(payload, status, headers, response); } let payloadData = _getPayload(payload); diff --git a/common/config/rush/npm-shrinkwrap.json b/common/config/rush/npm-shrinkwrap.json index 6ae4cff99..31d234771 100644 --- a/common/config/rush/npm-shrinkwrap.json +++ b/common/config/rush/npm-shrinkwrap.json @@ -183,9 +183,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz", + "integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==", "peer": true, "dependencies": { "eslint-visitor-keys": "^3.4.3" @@ -235,6 +235,15 @@ "node": "*" } }, + "node_modules/@eslint/config-helpers": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.1.0.tgz", + "integrity": "sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA==", + "peer": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/core": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", @@ -305,9 +314,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.21.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz", - "integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==", + "version": "9.22.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.22.0.tgz", + "integrity": "sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==", "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -402,42 +411,42 @@ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" }, "node_modules/@microsoft/api-extractor": { - "version": "7.51.1", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.51.1.tgz", - "integrity": "sha512-VoFvIeYXme8QctXDkixy1KIn750kZaFy2snAEOB3nhDFfbBcJNEcvBrpCIQIV09MqI4g9egKUkg+/12WMRC77w==", + "version": "7.52.1", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.52.1.tgz", + "integrity": "sha512-m3I5uAwE05orsu3D1AGyisX5KxsgVXB+U4bWOOaX/Z7Ftp/2Cy41qsNhO6LPvSxHBaapyser5dVorF1t5M6tig==", "dependencies": { - "@microsoft/api-extractor-model": "7.30.3", + "@microsoft/api-extractor-model": "7.30.4", "@microsoft/tsdoc": "~0.15.1", "@microsoft/tsdoc-config": "~0.17.1", - "@rushstack/node-core-library": "5.11.0", + "@rushstack/node-core-library": "5.12.0", "@rushstack/rig-package": "0.5.3", - "@rushstack/terminal": "0.15.0", - "@rushstack/ts-command-line": "4.23.5", + "@rushstack/terminal": "0.15.1", + "@rushstack/ts-command-line": "4.23.6", "lodash": "~4.17.15", "minimatch": "~3.0.3", "resolve": "~1.22.1", "semver": "~7.5.4", "source-map": "~0.6.1", - "typescript": "5.7.3" + "typescript": "5.8.2" }, "bin": { "api-extractor": "bin/api-extractor" } }, "node_modules/@microsoft/api-extractor-model": { - "version": "7.30.3", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.30.3.tgz", - "integrity": "sha512-yEAvq0F78MmStXdqz9TTT4PZ05Xu5R8nqgwI5xmUmQjWBQ9E6R2n8HB/iZMRciG4rf9iwI2mtuQwIzDXBvHn1w==", + "version": "7.30.4", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.30.4.tgz", + "integrity": "sha512-RobC0gyVYsd2Fao9MTKOfTdBm41P/bCMUmzS5mQ7/MoAKEqy0FOBph3JOYdq4X4BsEnMEiSHc+0NUNmdzxCpjA==", "dependencies": { "@microsoft/tsdoc": "~0.15.1", "@microsoft/tsdoc-config": "~0.17.1", - "@rushstack/node-core-library": "5.11.0" + "@rushstack/node-core-library": "5.12.0" } }, "node_modules/@microsoft/api-extractor/node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -662,7 +671,7 @@ "node_modules/@rush-temp/1ds-core-js": { "version": "0.0.0", "resolved": "file:projects/1ds-core-js.tgz", - "integrity": "sha512-S568Ikc8mwbKh+kXzGMJc3+ddM2zq8TTvGc/tDxv7K7laMpX7LuA8wYOo3YwvRcnys4LWzucUy00ir0DZGXIgA==", + "integrity": "sha512-apLuWmv+yjEUMP5mpjXtNP/9KNnAmWRGcR5zpNE1IspJ4nkVA/Rrz4GsKAxRQ7Zwg22HnUISWc3Zb75rTcCUxA==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -691,7 +700,7 @@ "node_modules/@rush-temp/1ds-post-js": { "version": "0.0.0", "resolved": "file:projects/1ds-post-js.tgz", - "integrity": "sha512-6TjJhRfasCS9JwEIgK3deLCZF8sCJhofofeEHp8QpYGNJ+PeLfmM4z9/36s3ytiNVRtNyXMWQ7F1VcaiEtNWLg==", + "integrity": "sha512-ssnydCEmFp14fGC/lli2Tlot9+H7/HXy4RUXquWxqjKEyZRpjctumJ50qnnBL9eTnfPC7pTtpRXsIT/khmUlqA==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -714,7 +723,7 @@ "node_modules/@rush-temp/ai-test-framework": { "version": "0.0.0", "resolved": "file:projects/ai-test-framework.tgz", - "integrity": "sha512-tnX3vftQBLYYxbAp39K86joXD95A0WxZ5dIhL4RHkVH/7DO3pwphhpKh6H7y+N1EgHyDeJjZQ012EhTRLjxt4A==", + "integrity": "sha512-TqE51+8piRhz4DjMLIY1AS/sarejEInB9Anec71OhVcTSnJ/hFajNVkDGpbrM1fkcS1ipUWL5NDa63I4hIrs1g==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-ts-plugin": "^0.4.3", @@ -741,7 +750,7 @@ "node_modules/@rush-temp/applicationinsights-analytics-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-analytics-js.tgz", - "integrity": "sha512-VlzvYhv3aJJ6cRMoGqoQUyBPLNlyZDrQPi4Fcaa/oZlHPuUr/o4ul1sNP1gWVoFvJGpIw7CTRIoie1f7guquPQ==", + "integrity": "sha512-a+7tuwPO4548C8YIkkTuzdOTrCVExgC0OEWlxaoQi8A8V4mpLmNIKqZ/A5zlsmrpy92JBjJKojW4GclDQCKPtw==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -770,7 +779,7 @@ "node_modules/@rush-temp/applicationinsights-cfgsync-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-cfgsync-js.tgz", - "integrity": "sha512-KN+tyNwv1ZOI9zX8h2avQCKQ08WBEf44K0mU/zf8a8oTxuPHYDAteWfh4HSBZeWiXtsGIANfYylOsIu0y/nQYQ==", + "integrity": "sha512-Wg2KCxnGY3tZy0iadN3po2JgeMTVGpttdRhst9IqRwzkl10zdPoU7p/Ij4PYdt47BnEXCyxslgCqOoevWrzftA==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -800,7 +809,7 @@ "node_modules/@rush-temp/applicationinsights-channel-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-channel-js.tgz", - "integrity": "sha512-Rgsyi0vQ8jWCCgx7wwRwcgn8qX3RtUsvF61xj4UmllDmka0n8aepMstmoGTYSjZD+0HhJ6icOnQDygOsKY8cwQ==", + "integrity": "sha512-M07q5mg9sCV4aL4hDE6QXa8vYmpeEZKe57Gndn37MFYsDUsuyad2BdHQ7xvLR69RF6nValFPuP9GnlkrCCbYtg==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -828,7 +837,7 @@ "node_modules/@rush-temp/applicationinsights-chrome-debug-extension": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-chrome-debug-extension.tgz", - "integrity": "sha512-FQvXuPosQmB6R7W9R1xUGxaDs6FZiIX8pKx04u2ks8ySqttktcE5cNt0mpRNvhdas7mhfwh4hkPrSw5Htl5GIQ==", + "integrity": "sha512-DQ4Cd99QfhSTZ72oSpg/+Pt28Op/hSDNq4tuCjH9VUNL79DqDYEBk8BExZjdf2rQgWDcIA0OtW8jt0vDEd+X7Q==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -864,7 +873,7 @@ "node_modules/@rush-temp/applicationinsights-clickanalytics-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-clickanalytics-js.tgz", - "integrity": "sha512-MMWaGbWpcRqCQXWjTO79LwbOCFUCKTzXdReGZTMpQpfFtfgzdCvh7/zeBp6tz+FP+Ely4RtGspD3bnJ2v19iDg==", + "integrity": "sha512-ODDVcnd3e/Elzl8oDn+OV9sM7rvXMtRmd/FYZsjl9wZgLgPKBYAZmOQwNfk3muPQnLdKoK8kOAySy8KpCYmatw==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -890,7 +899,7 @@ "node_modules/@rush-temp/applicationinsights-common": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-common.tgz", - "integrity": "sha512-BEkeD4/QIm5UBlviSgMtA7r8jBW5kGzXxOlNJIO/CBotCsFvFXqVo9yMRPwP9PJQ+Hpz08HvsqhLFDnsFsNsww==", + "integrity": "sha512-8AYe2KAygw9vCHelkeFhXYB6mTmghdmRjDCppqLS9T71z1UBCZM2rwrqyigE65d/I3tssM1YM/udW3DZQ3eJ2g==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -917,7 +926,7 @@ "node_modules/@rush-temp/applicationinsights-core-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-core-js.tgz", - "integrity": "sha512-7S989coGnef/fK5+Y6BnXtiFpVLz6SJ6igNC4IZlVxnw8ii5DbqZvIZu6nXd/eGG3avwsGqqZh2+fdBWf36wrg==", + "integrity": "sha512-SrIFCEujUCzjvmkkDOnYee7H3FXRYBDG5wsAiDXWbrAokm43O3u3nU/sjv89N9MGKV3dRhTqzYWCpMiumey26Q==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -947,7 +956,7 @@ "node_modules/@rush-temp/applicationinsights-debugplugin-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-debugplugin-js.tgz", - "integrity": "sha512-5RP04u0Yfyim8hJE/RaHt4uAFXNKNfwgM1vX8c+qfjMCBUlNSASxRSKQek3yB9fPYwCz4Y+Auz9BG72FHUJoyg==", + "integrity": "sha512-2vrLuc0qsTfLrhrtzpnNGaSowayXeEnfAaBfr/oXRDJm4uIeu2q75fTwCjpLj3UAt2SxoPrQcTH7l1zj0ZtOGg==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -973,7 +982,7 @@ "node_modules/@rush-temp/applicationinsights-dependencies-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-dependencies-js.tgz", - "integrity": "sha512-k/xzf3VxNirpIs3ZAOjQ7bU3/EGBZVw0lYPodkGlVwjyTQbZeRSFmD2KbG5f67GqTlwP2FAYS58dMgnrBC0VQQ==", + "integrity": "sha512-FiGhevi/vN6+Y/kWzXwDK2bHeSRROPw/3tp1X0m0aTqcK78w4btr5C9y4W0zOTS0I6skMEcgfYyK9W1oObBXKg==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1002,7 +1011,7 @@ "node_modules/@rush-temp/applicationinsights-example-aisku": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-example-aisku.tgz", - "integrity": "sha512-niU+OZNuZnZK7xneran0RMcb7JNty5mzp41pKg7WYzkz8FGxFoUyKTt6jAVsaK32waKr7MxD0EdkaTZ0xtB7/Q==", + "integrity": "sha512-TRKQhyAP2oRg+C8VEIiS+mCwY2w0f11xV2u8gMK5RG/xgibno3c5PaYvlonGAE4jyi68R/BfD3Sqc9NfPpj7zg==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/ts-utils": ">= 0.11.8 < 2.x", @@ -1021,7 +1030,7 @@ "node_modules/@rush-temp/applicationinsights-example-cfgsync": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-example-cfgsync.tgz", - "integrity": "sha512-tJavCc9UL7In5l8jrgmFWu+x9kza63fg0F8o9IQDqlxpbqb9wEoHMgu/JG3fQn87E29Uo6xUZXWFmMnVZJ3cLA==", + "integrity": "sha512-z0VJUclAhw9Ybncy4LSWJdgi/tvfdiNIhqurRfgSRY1AdIw05RJAECA/P6WsxrKdtKSzs23BYS0zWUa0uXVexQ==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -1048,7 +1057,7 @@ "node_modules/@rush-temp/applicationinsights-example-dependencies": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-example-dependencies.tgz", - "integrity": "sha512-DNHJM7jDSsuPRDW4d46lkK9O/tLbBKzrp39g2Hnng6ak16UtQghMiFMxqrrPZwcx5MIT8WTN67/5dd8LDcln/Q==", + "integrity": "sha512-2oh3nLFqQpsVLU1wTY1nhvNGzsTOdE8cwzxhyKXAb7/7x9HBIVi37f+h8GibL6s5svH44m5u/yS5CKjb3MNdYg==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/ts-utils": ">= 0.11.8 < 2.x", @@ -1067,7 +1076,7 @@ "node_modules/@rush-temp/applicationinsights-example-shared-worker": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-example-shared-worker.tgz", - "integrity": "sha512-FGgqa6DjwP5E4D+fNltmaq3JB/D9I/eI/MyRPMnJQ6UDF1cnq7n54skGIC3QgVnHAfCGhYe8+cca9LJooDnScQ==", + "integrity": "sha512-JOhewF0omr64DyI/0u4UbmXW125GXMqY4kyxuLQgWQDpGlf5Tlc9vy823+YbcoDTjc8p1mj/gZ0aW8E0F81PUA==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -1094,7 +1103,7 @@ "node_modules/@rush-temp/applicationinsights-js-release-tools": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-js-release-tools.tgz", - "integrity": "sha512-e9jw61D/jeRuLlSL+dQ2bFp8iqw6Q9ZMeboqX0CX0iYwjAPRiN/59ZK66D0UOgggNkqYgSEqgDi+ycw9XRtGnA==", + "integrity": "sha512-6sVB5NMzKj/P9v9UvZlA/IjQSkGeupaDliSt2IZqy+SlR59Hv335Ekz/5f54xMHu+QiARXJATbjX7lDfCMG8qw==", "dependencies": { "globby": "^11.0.0", "grunt": "^1.5.3" @@ -1103,7 +1112,7 @@ "node_modules/@rush-temp/applicationinsights-offlinechannel-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-offlinechannel-js.tgz", - "integrity": "sha512-Fo2BA9ndAzApO+keiT43xRtpd/ZZU6MrQvFOdElynZBCgAjtsIy06EG+JlkrO5WkXe/DQFXo7uoDfr7ev93K9Q==", + "integrity": "sha512-FXcwTCrBzkFhbdl2MRl/ddAsISIIbjc7C2Os4q/81yAeTBf34oMSREkz3G/6rwgX5CHdGlsLxYoGZOr9N01O5w==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1131,7 +1140,7 @@ "node_modules/@rush-temp/applicationinsights-osplugin-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-osplugin-js.tgz", - "integrity": "sha512-GI+lfOwoDdEJZg8C84FbkEO1H8dAtu8zhrRO3ELUHHvyWDBlJ00m/GZ15f0GpiWIKLM1aGfvS3boJbeGXwsfwA==", + "integrity": "sha512-6t2U5fyBIZKTJbaBtTg/Npd7aqwqSSjhwPExQEDFB1QSe98g8M7U07q49S4o4j+w3jqrhVwrwLmFN5cDvQtuIw==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1154,7 +1163,7 @@ "node_modules/@rush-temp/applicationinsights-perfmarkmeasure-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-perfmarkmeasure-js.tgz", - "integrity": "sha512-UTKXee9IjxWV+/ndjIzGotNe1dprLJ6HoyOS8aTh+UwmkewwXYklFhC7RJ2DLaTj/4/EtJcTn9Jd9B1BMKqHCg==", + "integrity": "sha512-XQ0gCQt7Vxl3gn6Ux7Uq7rBh8l5/4XZPftXcAXKwkmPRMGDZObbjHfdCKys+0/bP2gQ09WifydjE5gXRQIQncQ==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1180,7 +1189,7 @@ "node_modules/@rush-temp/applicationinsights-properties-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-properties-js.tgz", - "integrity": "sha512-A1DteE1sHRnuHUYpta6aaQlgcuoWZJt8Xf5elql3PqMAT5F10IWBetxuLZknOTjdBzlVEVrFWLjeMji+U6vaSw==", + "integrity": "sha512-WNUzBixreiuaz8SdkXjd/C1xqtYEKAPPYovYPpmGIMb+Doxpzv6+fAwnLcGXNSlyLPBcRl6lvKGnr1mUw/TwIg==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1209,7 +1218,7 @@ "node_modules/@rush-temp/applicationinsights-rollup-es5": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-rollup-es5.tgz", - "integrity": "sha512-S5O9XK+Ezf+o4yg4ol6L8eDt13ZgbxN7zMxZ7mgyMn/kAw9KSASKM0AttiQ/+TlA6oVsyy60qxYYtxwtRNe1Hw==", + "integrity": "sha512-2KGwNRdd1Cj+HU+eymk4Vr9tCoCCiWAThd2nLi+DXCXRhgQgUFzygIDQTtbsFdQMpihK3xm+9Te22Som95XUow==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -1234,7 +1243,7 @@ "node_modules/@rush-temp/applicationinsights-rollup-plugin-uglify3-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-rollup-plugin-uglify3-js.tgz", - "integrity": "sha512-UlrHcg9syNUHkxSrHAA4R5rXZBF7UIZA6yTsEzpeAdq8IDaWPqqNixuNtuRuWFNDUCZoZ1IrLJvOBsLjdCu7mQ==", + "integrity": "sha512-jsh6Gf9Tf6RvCtdm8knaz6AkOo0cfinBcJY5xKQDMKTbd/rtrdjpZlrnjUCgu37/Tf2mPU729wW2bX5f4qESqA==", "dependencies": { "@nevware21/grunt-eslint-ts": "^0.2.2", "@nevware21/grunt-ts-plugin": "^0.4.3", @@ -1255,7 +1264,7 @@ "node_modules/@rush-temp/applicationinsights-shims": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-shims.tgz", - "integrity": "sha512-tfOkC4pH6vVoEyr60aHs/DfjXCLx5FS/xBBBgNHhxNZI7qRP7XzT7T14zZfnN8emQSRNo9i2QQ6lotPKXWw7Lw==", + "integrity": "sha512-78cuigGVsHDC+lYMYDG9ZwRaqwyWjiIOP/YOEuAfgOd+k9PgVzpiF5Ex7mCEJjs/SCylqaVpc4VRm1+Rf4psIw==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -1278,7 +1287,7 @@ "node_modules/@rush-temp/applicationinsights-teechannel-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-teechannel-js.tgz", - "integrity": "sha512-4YIz6YFExC07EfQjIwjH5b+EBYWH8e6mYjBRlksrnB/fnSCOJtPhGiHm2mH/HHZbwHBz+qGh15+K6yuUh3Q05w==", + "integrity": "sha512-ef9n8waBRzdPD7bnlCKDiJRhSMd0HifhAiM5QwGY4D/yN4bJmqwojfPIqB12SvZG79muL2+BAGezaOzS8kXjEg==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1306,7 +1315,7 @@ "node_modules/@rush-temp/applicationinsights-test-module-type-check": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-test-module-type-check.tgz", - "integrity": "sha512-J+t6FArFCQBHl8Cym4B7qUV/VioxLTVxTk3sZ+gbMkcxARQ3LdUKiDk0QYbxJwPFTeLbdwmVOBy5Any58i4Wbw==", + "integrity": "sha512-lqgC93TZ4TmUr3DhckDalb1eMZyODclD58JrmnARRwjhdMCe7svk0oR0T8i0jzrH2f+fAkflMU+7bOZYlUtZ/g==", "dependencies": { "tslib": ">= 1.0.0", "typescript": "^4.9.3" @@ -1315,7 +1324,7 @@ "node_modules/@rush-temp/applicationinsights-web": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-web.tgz", - "integrity": "sha512-dA3ZNHJCTvOgGSgJFPj+jjsKR+D1BtxGl97D31Ls35vCox2CVff8gxUBRSLmT97p2gk78wo/11Play6sWlBdEQ==", + "integrity": "sha512-F8CHRyJFzAleotnnMr8g/4UL1MoZmNHVr3WORvizh0rHsXRjO4kkGx6ofD5i/1umlFrlYZEkApaeULxBMRzBMw==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1348,7 +1357,7 @@ "node_modules/@rush-temp/applicationinsights-web-basic": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-web-basic.tgz", - "integrity": "sha512-UouzLYljf5hLoXdmck4c0HXm/qJJV19pzFfWTLZVO9G+RDhDSRTuO0/1XgWoetx9O8bWWxreUIz+Ruyv05/eHQ==", + "integrity": "sha512-m9vF95kYH38PxYrOTSkzYu/az7RoUIVod91KVMPzBARwulnKBzqvzABNfJiO3dmnlIRHr0A6eO8775jJwQWGqw==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1376,12 +1385,12 @@ "node_modules/@rush-temp/applicationinsights-web-config": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-web-config.tgz", - "integrity": "sha512-FwPOZ+esirRqdKg9s7VTxtWqGJ9CQ/gIJ0PfUvTolAF9JZCVw5wQeHD4Tv/KiziZhB50CNaGshnPmLpWGVzo9g==" + "integrity": "sha512-WwlTM/noixyLMqKFBLKa9o88N/2Z3dA9m0R6Qc9UvBNseZqPIpvl1vRMDnmwjMMV6lV3FsmeSmjD7LCJphXF2Q==" }, "node_modules/@rush-temp/applicationinsights-web-snippet": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-web-snippet.tgz", - "integrity": "sha512-XXGxNMapO2ZIzThyO9d4KqnddgY1yU7ojb2xsggVoJgiCH1DxAIRcL9QSG7wxfaQjfoXWuYH7Ighj2DjqA1N3Q==", + "integrity": "sha512-ySVDDbaBEIZYIKYKVpyWmVZcfCuYgqnGGlULpU3EnUvAI1L8VkvbxoOx6H+J4Nf+XO+/DbcmLW6i0kFTqVlLSg==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1404,9 +1413,9 @@ } }, "node_modules/@rushstack/node-core-library": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.11.0.tgz", - "integrity": "sha512-I8+VzG9A0F3nH2rLpPd7hF8F7l5Xb7D+ldrWVZYegXM6CsKkvWc670RlgK3WX8/AseZfXA/vVrh0bpXe2Y2UDQ==", + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.12.0.tgz", + "integrity": "sha512-QSwwzgzWoil1SCQse+yCHwlhRxNv2dX9siPnAb9zR/UmMhac4mjMrlMZpk64BlCeOFi1kJKgXRkihSwRMbboAQ==", "dependencies": { "ajv": "~8.13.0", "ajv-draft-04": "~1.0.0", @@ -1451,11 +1460,11 @@ } }, "node_modules/@rushstack/terminal": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.15.0.tgz", - "integrity": "sha512-vXQPRQ+vJJn4GVqxkwRe+UGgzNxdV8xuJZY2zem46Y0p3tlahucH9/hPmLGj2i9dQnUBFiRnoM9/KW7PYw8F4Q==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.15.1.tgz", + "integrity": "sha512-3vgJYwumcjoDOXU3IxZfd616lqOdmr8Ezj4OWgJZfhmiBK4Nh7eWcv8sU8N/HdzXcuHDXCRGn/6O2Q75QvaZMA==", "dependencies": { - "@rushstack/node-core-library": "5.11.0", + "@rushstack/node-core-library": "5.12.0", "supports-color": "~8.1.1" }, "peerDependencies": { @@ -1468,11 +1477,11 @@ } }, "node_modules/@rushstack/ts-command-line": { - "version": "4.23.5", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.23.5.tgz", - "integrity": "sha512-jg70HfoK44KfSP3MTiL5rxsZH7X1ktX3cZs9Sl8eDu1/LxJSbPsh0MOFRC710lIuYYSgxWjI5AjbCBAl7u3RxA==", + "version": "4.23.6", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.23.6.tgz", + "integrity": "sha512-7WepygaF3YPEoToh4MAL/mmHkiIImQq3/uAkQX46kVoKTNOOlCtFGyNnze6OYuWw2o9rxsyrHVfIBKxq/am2RA==", "dependencies": { - "@rushstack/terminal": "0.15.0", + "@rushstack/terminal": "0.15.1", "@types/argparse": "1.0.38", "argparse": "~1.0.9", "string-argv": "~0.3.1" @@ -1785,16 +1794,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.26.0.tgz", - "integrity": "sha512-cLr1J6pe56zjKYajK6SSSre6nl1Gj6xDp1TY0trpgPzjVbgDwd09v2Ws37LABxzkicmUjhEeg/fAUjPJJB1v5Q==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.26.1.tgz", + "integrity": "sha512-2X3mwqsj9Bd3Ciz508ZUtoQQYpOhU/kWoUqIf49H8Z0+Vbh6UF/y0OEYp0Q0axOGzaBGs7QxRwq0knSQ8khQNA==", "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.26.0", - "@typescript-eslint/type-utils": "8.26.0", - "@typescript-eslint/utils": "8.26.0", - "@typescript-eslint/visitor-keys": "8.26.0", + "@typescript-eslint/scope-manager": "8.26.1", + "@typescript-eslint/type-utils": "8.26.1", + "@typescript-eslint/utils": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1814,15 +1823,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.26.0.tgz", - "integrity": "sha512-mNtXP9LTVBy14ZF3o7JG69gRPBK/2QWtQd0j0oH26HcY/foyJJau6pNUez7QrM5UHnSvwlQcJXKsk0I99B9pOA==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.26.1.tgz", + "integrity": "sha512-w6HZUV4NWxqd8BdeFf81t07d7/YV9s7TCWrQQbG5uhuvGUAW+fq1usZ1Hmz9UPNLniFnD8GLSsDpjP0hm1S4lQ==", "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.26.0", - "@typescript-eslint/types": "8.26.0", - "@typescript-eslint/typescript-estree": "8.26.0", - "@typescript-eslint/visitor-keys": "8.26.0", + "@typescript-eslint/scope-manager": "8.26.1", + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/typescript-estree": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1", "debug": "^4.3.4" }, "engines": { @@ -1838,13 +1847,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.26.0.tgz", - "integrity": "sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.26.1.tgz", + "integrity": "sha512-6EIvbE5cNER8sqBu6V7+KeMZIC1664d2Yjt+B9EWUXrsyWpxx4lEZrmvxgSKRC6gX+efDL/UY9OpPZ267io3mg==", "peer": true, "dependencies": { - "@typescript-eslint/types": "8.26.0", - "@typescript-eslint/visitor-keys": "8.26.0" + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1855,13 +1864,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.26.0.tgz", - "integrity": "sha512-ruk0RNChLKz3zKGn2LwXuVoeBcUMh+jaqzN461uMMdxy5H9epZqIBtYj7UiPXRuOpaALXGbmRuZQhmwHhaS04Q==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.26.1.tgz", + "integrity": "sha512-Kcj/TagJLwoY/5w9JGEFV0dclQdyqw9+VMndxOJKtoFSjfZhLXhYjzsQEeyza03rwHx2vFEGvrJWJBXKleRvZg==", "peer": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.26.0", - "@typescript-eslint/utils": "8.26.0", + "@typescript-eslint/typescript-estree": "8.26.1", + "@typescript-eslint/utils": "8.26.1", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, @@ -1878,9 +1887,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.26.0.tgz", - "integrity": "sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.26.1.tgz", + "integrity": "sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ==", "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1891,13 +1900,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.0.tgz", - "integrity": "sha512-tiJ1Hvy/V/oMVRTbEOIeemA2XoylimlDQ03CgPPNaHYZbpsc78Hmngnt+WXZfJX1pjQ711V7g0H7cSJThGYfPQ==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.1.tgz", + "integrity": "sha512-yUwPpUHDgdrv1QJ7YQal3cMVBGWfnuCdKbXw1yyjArax3353rEJP1ZA+4F8nOlQ3RfS2hUN/wze3nlY+ZOhvoA==", "peer": true, "dependencies": { - "@typescript-eslint/types": "8.26.0", - "@typescript-eslint/visitor-keys": "8.26.0", + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/visitor-keys": "8.26.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -1953,15 +1962,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.26.0.tgz", - "integrity": "sha512-2L2tU3FVwhvU14LndnQCA2frYC8JnPDVKyQtWFPf8IYFMt/ykEN1bPolNhNbCVgOmdzTlWdusCTKA/9nKrf8Ig==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.26.1.tgz", + "integrity": "sha512-V4Urxa/XtSUroUrnI7q6yUTD3hDtfJ2jzVfeT3VK0ciizfK2q/zGC0iDh1lFMUZR8cImRrep6/q0xd/1ZGPQpg==", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.26.0", - "@typescript-eslint/types": "8.26.0", - "@typescript-eslint/typescript-estree": "8.26.0" + "@typescript-eslint/scope-manager": "8.26.1", + "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/typescript-estree": "8.26.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1976,12 +1985,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.26.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.0.tgz", - "integrity": "sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg==", + "version": "8.26.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.1.tgz", + "integrity": "sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg==", "peer": true, "dependencies": { - "@typescript-eslint/types": "8.26.0", + "@typescript-eslint/types": "8.26.1", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -2015,9 +2024,9 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "peer": true, "bin": { "acorn": "bin/acorn" @@ -2450,9 +2459,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001701", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001701.tgz", - "integrity": "sha512-faRs/AW3jA9nTwmJBSO1PQ6L/EOgsB5HMQQq4iCu5zhPgVVgO/pZRHlmatwijZKetFw8/Pr4q6dEN8sJuq8qTw==", + "version": "1.0.30001705", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001705.tgz", + "integrity": "sha512-S0uyMMiYvA7CxNgomYBwwwPUnWzFD83f3B1ce5jHUfHTH//QL6hHsreI8RVC5606R4ssqravelYO5TU6t8sEyg==", "funding": [ { "type": "opencollective", @@ -2898,9 +2907,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.5.110", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.110.tgz", - "integrity": "sha512-/p/OvOm6AfLtQteAHTUWwf+Vhh76PlluagzQlSnxMoOJ4R6SmAScWBrVev6rExJoUhP9zudN9+lBxoYUEmC1HQ==" + "version": "1.5.120", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.120.tgz", + "integrity": "sha512-oTUp3gfX1gZI+xfD2djr2rzQdHCwHzPQrrK0CD7WpTdF0nPdQ/INcRVjWgLdCT4a9W3jFObR9DAfsuyFQnI8CQ==" }, "node_modules/emoji-regex-xs": { "version": "1.0.0", @@ -2968,17 +2977,18 @@ } }, "node_modules/eslint": { - "version": "9.21.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.21.0.tgz", - "integrity": "sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg==", + "version": "9.22.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.22.0.tgz", + "integrity": "sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.2", + "@eslint/config-helpers": "^0.1.0", "@eslint/core": "^0.12.0", "@eslint/eslintrc": "^3.3.0", - "@eslint/js": "9.21.0", + "@eslint/js": "9.22.0", "@eslint/plugin-kit": "^0.2.7", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -2990,7 +3000,7 @@ "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.2.0", + "eslint-scope": "^8.3.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0", "esquery": "^1.5.0", @@ -3054,9 +3064,9 @@ } }, "node_modules/eslint-scope": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", - "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", "peer": true, "dependencies": { "esrecurse": "^4.3.0", diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts index 4f5932251..31535cba7 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts @@ -1,11 +1,11 @@ import { IAppInsightsCore } from "./IAppInsightsCore"; -import { IStatsBeatEvent } from "./IStatsBeatEvent"; +import { IPayloadData } from "./IXHROverride"; export interface IStatsBeat { initialize(core: IAppInsightsCore, ikey: string, endpoint: string, version?: string) : void; isInitialized(): boolean; setInitialized(value: boolean): void; - count(status: number, payloadData: IStatsBeatEvent, endpoint: string): void; - countException(endpoint: string): void; + count(status: number, payloadData: IPayloadData, endpoint: string): void; + countException(endpoint: string, event: ErrorEvent): void; trackShortIntervalStatsbeats(): void; } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts index e3ef4670d..ed845819c 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts @@ -26,6 +26,10 @@ export class NetworkStatsbeat { public lastIntervalRequestExecutionTime: number; + public requests_Failure_Count: Record; + public retry_Count: Record; + public exception_Count: Record; + constructor(host: string) { this.host = host; this.totalRequestCount = 0; @@ -38,5 +42,8 @@ export class NetworkStatsbeat { this.lastIntervalRequestExecutionTime = 0; this.lastTime = utcNow(); this.lastRequestCount = 0; + this.requests_Failure_Count = {}; + this.retry_Count = {}; + this.exception_Count = {}; } } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 11c9b767b..7add3093c 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -1,10 +1,10 @@ import dynamicProto from "@microsoft/dynamicproto-js"; -import { objKeys, strIncludes, utcNow } from "@nevware21/ts-utils"; -import { IChannelControls } from "../JavaScriptSDK.Interfaces/IChannelControls"; +import { strIncludes, utcNow } from "@nevware21/ts-utils"; +import { IAppInsightsCore } from "../JavaScriptSDK.Interfaces/IAppInsightsCore"; import { IStatsBeat } from "../JavaScriptSDK.Interfaces/IStatsBeat"; import { ITelemetryItem } from "../JavaScriptSDK.Interfaces/ITelemetryItem"; +import { IPayloadData } from "../JavaScriptSDK.Interfaces/IXHROverride"; import { NetworkStatsbeat } from "./NetworkStatsbeat"; -import { IAppInsightsCore } from "../JavaScriptSDK.Interfaces/IAppInsightsCore"; const INSTRUMENTATION_KEY = "c4a29126-a7cb-47e5-b348-11414998b11e"; const STATS_COLLECTION_SHORT_INTERVAL: number = 900000; // 15 minutes @@ -48,34 +48,36 @@ export class Statsbeat implements IStatsBeat { _isEnabled = value; } - _self.count = (status, payloadData, endpoint) => { + _self.count = (status: number, payloadData: IPayloadData, endpoint: string) => { if (!_isEnabled || !_checkEndpoint(endpoint)) { return; } _networkCounter.totalRequestCount++; - if (payloadData && payloadData.startTime) { - _networkCounter.intervalRequestExecutionTime += utcNow() - payloadData.startTime; + if (payloadData && payloadData["statsBeatData"] && payloadData["statsBeatData"]["startTime"]) { + _networkCounter.intervalRequestExecutionTime += utcNow() - payloadData["statsBeatData"]["startTime"]; } if (status === 200) { _networkCounter.succesfulRequestCount++; } else if (strIncludes("307,308,401,402,403,408,429,439,500,503", status.toString())) { // These statuses are not considered failures if (strIncludes("401,403,408,429,500,503", status.toString())) { - _networkCounter.retryCount++; + _networkCounter.retry_Count[status] = (_networkCounter.retry_Count[status] || 0) + 1; } if (strIncludes("402,439", status.toString())) { _networkCounter.throttleCount++; } } else { _networkCounter.failedRequestCount++; + _networkCounter.requests_Failure_Count[status] = (_networkCounter.requests_Failure_Count[status] || 0) + 1; } }; - _self.countException = (endpoint: string) => { + _self.countException = (endpoint: string, event: ErrorEvent) => { if (!_isEnabled || !_checkEndpoint(endpoint)) { return; } _networkCounter.exceptionCount++; + _networkCounter.exception_Count[event.error.name] = (_networkCounter.exception_Count[event.error.name] || 0) + 1; } @@ -133,24 +135,33 @@ export class Statsbeat implements IStatsBeat { _sendStatsbeats("Request_Duration", averageRequestExecutionTime); } } + function _trackSendRequestsCount() { var currentCounter = _networkCounter; if (currentCounter.succesfulRequestCount > 0) { _sendStatsbeats("Request_Success_Count", currentCounter.succesfulRequestCount); } - if (currentCounter.failedRequestCount > 0) { - _sendStatsbeats("Requests_Failure_Count", currentCounter.failedRequestCount); + + for (const code in currentCounter.requests_Failure_Count) { + const count = currentCounter.requests_Failure_Count[code]; + _sendStatsbeats("Requests_Failure_Count", count, { statusCode: code }); } - if (currentCounter.retryCount > 0) { - _sendStatsbeats("Retry_Count", currentCounter.retryCount); + + for (const code in currentCounter.retry_Count) { + const count = currentCounter.retry_Count[code]; + _sendStatsbeats("Retry_Count", count, { statusCode: code }); } + + for (const code in currentCounter.exception_Count) { + const count = currentCounter.exception_Count[code]; + _sendStatsbeats("Exception_Count", count, { exceptionType: code }); + } + if (currentCounter.throttleCount > 0) { _sendStatsbeats("Throttle_Count", currentCounter.throttleCount); } - if (currentCounter.exceptionCount > 0) { - _sendStatsbeats("Exception_Count", currentCounter.exceptionCount); - } + } }) } @@ -168,11 +179,11 @@ export class Statsbeat implements IStatsBeat { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } - public count(status: number, payloadData: any, endpoint: string) { + public count(status: number, payloadData: IPayloadData, endpoint: string) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } - public countException(endpoint: string) { + public countException(endpoint: string, event: ErrorEvent) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } From 0006c9b7c4a846d5378e23a938b5c28b841c182a Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 18 Mar 2025 00:12:47 -0700 Subject: [PATCH 11/62] call oncomplete manually --- .../applicationinsights-channel-js/src/Sender.ts | 12 ++++++------ .../src/JavaScriptSDK/AppInsightsCore.ts | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index f7fd961b3..f8f1a11e1 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -11,7 +11,7 @@ import { IXDomainRequest, IXHROverride, OnCompleteCallback, SendPOSTFunction, SendRequestReason, SenderPostManager, TransportType, _ISendPostMgrConfig, _ISenderOnComplete, _eInternalMessageId, _throwInternal, _warnToConsole, arrForEach, cfgDfBoolean, cfgDfValidate, createProcessTelemetryContext, createUniqueNamespace, dateNow, dumpObj, eLoggingSeverity, formatErrorMessageXdr, formatErrorMessageXhr, - getExceptionName, getIEVersion, isArray, isBeaconsSupported, isFetchSupported, isNullOrUndefined, mergeEvtNamespace, objExtend, + getExceptionName, getIEVersion, getResponseText, isArray, isBeaconsSupported, isFetchSupported, isNullOrUndefined, mergeEvtNamespace, objExtend, onConfigChange, parseResponse, prependTransports, runTargetUnload } from "@microsoft/applicationinsights-core-js"; import { IPromise } from "@nevware21/ts-async"; @@ -279,9 +279,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; _statsBeat.initialize(core, senderConfig.instrumentationKey, endpointHost, EnvelopeCreator.Version); } - if (config.disableStatsBeat !== false){ - _statsBeat.setInitialized(false); - } + // if it is not inital change (_endpointUrl has value) // if current sender endpoint url is not changed directly // means ExtCfg is not changed directly @@ -527,7 +525,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (_isStringArr(payload)) { return; } - return _xhrReadyStateChange(xhr, payload as IInternalStorageItem[], countOfItemsInPayload, statsBeat); + return _xhrReadyStateChange(xhr, payload as IInternalStorageItem[], countOfItemsInPayload); } @@ -654,7 +652,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (xdr && (responseText + "" === "200" || responseText === "")) { _consecutiveErrors = 0; _self._onSuccess(payload, 0); - var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; } else { const results = parseResponse(responseText); @@ -676,6 +673,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (!payloadArr) { return; } + // xdr could not pass in status code unless change the function signature return _xdrOnLoad(xdr, payloadArr); }, @@ -684,6 +682,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (!payloadArr) { return; } + onComplete(response.status, payload.headers, response.statusText); return _checkResponsStatus(response.status, payloadArr, response.url, payloadArr.length, response.statusText, resValue || ""); }, xhrOnComplete: (request: XMLHttpRequest, oncomplete: OnCompleteCallback, payload?: IPayloadData) => { @@ -691,6 +690,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (!payloadArr) { return; } + oncomplete(request.status, payload.headers, getResponseText(request)); return _xhrReadyStateChange(request, payloadArr, payloadArr.length); }, diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index b0f03bf22..191e05a04 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -362,6 +362,8 @@ export class AppInsightsCore im _initInMemoMaxSize = rootCfg.initInMemoMaxSize || maxInitQueueSize; if (config.disableStatsBeat === false){ _statsBeat = new Statsbeat(); + } else { + _statsBeat = null; } // app Insights core only handle ikey and endpointurl, aisku will handle cs let ikey = rootCfg.instrumentationKey; From 11b7e26476292feb726c0fd4d50c8e91032320a7 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 18 Mar 2025 00:44:14 -0700 Subject: [PATCH 12/62] Update Sender.ts --- .../src/Sender.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index f8f1a11e1..854968203 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -11,8 +11,8 @@ import { IXDomainRequest, IXHROverride, OnCompleteCallback, SendPOSTFunction, SendRequestReason, SenderPostManager, TransportType, _ISendPostMgrConfig, _ISenderOnComplete, _eInternalMessageId, _throwInternal, _warnToConsole, arrForEach, cfgDfBoolean, cfgDfValidate, createProcessTelemetryContext, createUniqueNamespace, dateNow, dumpObj, eLoggingSeverity, formatErrorMessageXdr, formatErrorMessageXhr, - getExceptionName, getIEVersion, getResponseText, isArray, isBeaconsSupported, isFetchSupported, isNullOrUndefined, mergeEvtNamespace, objExtend, - onConfigChange, parseResponse, prependTransports, runTargetUnload + getExceptionName, getIEVersion, getResponseText, isArray, isBeaconsSupported, isFetchSupported, isNullOrUndefined, mergeEvtNamespace, + objExtend, onConfigChange, parseResponse, prependTransports, runTargetUnload } from "@microsoft/applicationinsights-core-js"; import { IPromise } from "@nevware21/ts-async"; import { @@ -274,11 +274,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let curExtUrl = senderConfig.endpointUrl; _statsBeat = core.getStatsBeat(); - if (_statsBeat && !_statsBeat.isInitialized()) { - _statsBeat.setInitialized(true); // otherwise, it will fall into infinite loop of creating new sender - var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - _statsBeat.initialize(core, senderConfig.instrumentationKey, endpointHost, EnvelopeCreator.Version); - } + // if it is not inital change (_endpointUrl has value) // if current sender endpoint url is not changed directly @@ -293,6 +289,12 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } } + if (_statsBeat && !_statsBeat.isInitialized()) { + _statsBeat.setInitialized(true); // otherwise, it will fall into infinite loop of creating new sender + var endpointHost = urlParseUrl(senderConfig.endpointUrl).hostname; + _statsBeat.initialize(core, senderConfig.instrumentationKey, endpointHost, EnvelopeCreator.Version); + } + if(isPromiseLike(senderConfig.instrumentationKey)) { // if it is promise, means the endpoint url is from core.endpointurl senderConfig.instrumentationKey = config.instrumentationKey as any; @@ -941,7 +943,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { function _doSend(sendInterface: IXHROverride, payload: IInternalStorageItem[], isAsync: boolean, markAsSent: boolean = true): void | IPromise { let onComplete = (status: number, headers: {[headerName: string]: string;}, response?: string) => { - console.log("onComplete", status, headers, response, payloadData.statsBeatData.startTime); var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; _statsBeat.count(status, payloadData, endpointHost); return _getOnComplete(payload, status, headers, response); From ff8e0b6ae645aafed0a86f13d83b49c7b27ac0fe Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 18 Mar 2025 00:49:02 -0700 Subject: [PATCH 13/62] format change --- channels/applicationinsights-channel-js/src/Sender.ts | 3 --- .../src/JavaScriptSDK.Interfaces/IXHROverride.ts | 3 +++ .../src/JavaScriptSDK/NetworkStatsbeat.ts | 9 --------- shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts | 4 +--- 4 files changed, 4 insertions(+), 15 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 854968203..87b644893 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -274,8 +274,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let curExtUrl = senderConfig.endpointUrl; _statsBeat = core.getStatsBeat(); - - // if it is not inital change (_endpointUrl has value) // if current sender endpoint url is not changed directly // means ExtCfg is not changed directly @@ -727,7 +725,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { */ function _xhrReadyStateChange (xhr: XMLHttpRequest, payload: IInternalStorageItem[], countOfItemsInPayload: number) { if (xhr.readyState === 4) { - _checkResponsStatus(xhr.status, payload, xhr.responseURL, countOfItemsInPayload, formatErrorMessageXhr(xhr), _getResponseText(xhr) || xhr.response); } } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IXHROverride.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IXHROverride.ts index 641dadde0..4d34a9d49 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IXHROverride.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IXHROverride.ts @@ -30,3 +30,6 @@ export type OnCompleteCallback = (status: number, headers: { [headerName: string export interface IXHROverride { sendPOST: SendPOSTFunction; } + + + diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts index ed845819c..a90fd0440 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts @@ -14,12 +14,6 @@ export class NetworkStatsbeat { public succesfulRequestCount: number; - public failedRequestCount: number; - - public retryCount: number; - - public exceptionCount: number; - public throttleCount: number; public intervalRequestExecutionTime: number; @@ -34,9 +28,6 @@ export class NetworkStatsbeat { this.host = host; this.totalRequestCount = 0; this.succesfulRequestCount = 0; - this.failedRequestCount = 0; - this.retryCount = 0; - this.exceptionCount = 0; this.throttleCount = 0; this.intervalRequestExecutionTime = 0; this.lastIntervalRequestExecutionTime = 0; diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 7add3093c..178497b4f 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -67,7 +67,6 @@ export class Statsbeat implements IStatsBeat { _networkCounter.throttleCount++; } } else { - _networkCounter.failedRequestCount++; _networkCounter.requests_Failure_Count[status] = (_networkCounter.requests_Failure_Count[status] || 0) + 1; } }; @@ -76,7 +75,6 @@ export class Statsbeat implements IStatsBeat { if (!_isEnabled || !_checkEndpoint(endpoint)) { return; } - _networkCounter.exceptionCount++; _networkCounter.exception_Count[event.error.name] = (_networkCounter.exception_Count[event.error.name] || 0) + 1; } @@ -164,7 +162,7 @@ export class Statsbeat implements IStatsBeat { } }) - } + }; public initialize(core: IAppInsightsCore, ikey: string, endpoint: string, version?: string) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging From 2190c127a943a46680efbb66b7f17e670acb121e Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Wed, 19 Mar 2025 14:47:24 -0700 Subject: [PATCH 14/62] rename var and remove set initilize --- AISKU/Tests/Manual/testVersionConflict.html | 11 ++-- .../src/Sender.ts | 3 +- .../JavaScriptSDK.Interfaces/IStatsBeat.ts | 3 +- .../src/JavaScriptSDK/NetworkStatsbeat.ts | 43 ++++-------- .../src/JavaScriptSDK/StatsBeat.ts | 65 ++++++++----------- 5 files changed, 49 insertions(+), 76 deletions(-) diff --git a/AISKU/Tests/Manual/testVersionConflict.html b/AISKU/Tests/Manual/testVersionConflict.html index 2b7f4ca0e..fccf8c900 100644 --- a/AISKU/Tests/Manual/testVersionConflict.html +++ b/AISKU/Tests/Manual/testVersionConflict.html @@ -10,27 +10,30 @@

Microsoft Application Insights JavaScript SDK - AISKU

- --> \ No newline at end of file diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 87b644893..91d82e915 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -288,7 +288,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } if (_statsBeat && !_statsBeat.isInitialized()) { - _statsBeat.setInitialized(true); // otherwise, it will fall into infinite loop of creating new sender var endpointHost = urlParseUrl(senderConfig.endpointUrl).hostname; _statsBeat.initialize(core, senderConfig.instrumentationKey, endpointHost, EnvelopeCreator.Version); } @@ -741,7 +740,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { _self._buffer && _self._buffer.clearSent(payload); var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - _statsBeat.countException(endpointHost, event); + _statsBeat.countException(endpointHost, message); } /** * partial success handler diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts index 31535cba7..4c1f6b0ea 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts @@ -4,8 +4,7 @@ import { IPayloadData } from "./IXHROverride"; export interface IStatsBeat { initialize(core: IAppInsightsCore, ikey: string, endpoint: string, version?: string) : void; isInitialized(): boolean; - setInitialized(value: boolean): void; count(status: number, payloadData: IPayloadData, endpoint: string): void; - countException(endpoint: string, event: ErrorEvent): void; + countException(endpoint: string, message: string): void; trackShortIntervalStatsbeats(): void; } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts index a90fd0440..339ffa1b5 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts @@ -1,40 +1,25 @@ -import { utcNow } from "@nevware21/ts-utils"; export class NetworkStatsbeat { - public time: number; - - public lastTime: number; - public host: string; - public totalRequestCount: number; - - public lastRequestCount: number; - - public succesfulRequestCount: number; - - public throttleCount: number; - - public intervalRequestExecutionTime: number; - - public lastIntervalRequestExecutionTime: number; + public totalRequest: number; + public success: number; + public throttle: number; + public failure: Record; + public retry: Record; + public exception: Record; - public requests_Failure_Count: Record; - public retry_Count: Record; - public exception_Count: Record; + public requestDuration: number; constructor(host: string) { this.host = host; - this.totalRequestCount = 0; - this.succesfulRequestCount = 0; - this.throttleCount = 0; - this.intervalRequestExecutionTime = 0; - this.lastIntervalRequestExecutionTime = 0; - this.lastTime = utcNow(); - this.lastRequestCount = 0; - this.requests_Failure_Count = {}; - this.retry_Count = {}; - this.exception_Count = {}; + this.totalRequest = 0; + this.success = 0; + this.throttle = 0; + this.requestDuration = 0; + this.failure = {}; + this.retry = {}; + this.exception = {}; } } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 178497b4f..7a4a1a5bc 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -37,6 +37,7 @@ export class Statsbeat implements IStatsBeat { this.trackShortIntervalStatsbeats(); }, STATS_COLLECTION_SHORT_INTERVAL); } + _isEnabled = true; } @@ -44,38 +45,34 @@ export class Statsbeat implements IStatsBeat { return !!_isEnabled; } - _self.setInitialized = (value: boolean) => { - _isEnabled = value; - } - _self.count = (status: number, payloadData: IPayloadData, endpoint: string) => { if (!_isEnabled || !_checkEndpoint(endpoint)) { return; } - _networkCounter.totalRequestCount++; if (payloadData && payloadData["statsBeatData"] && payloadData["statsBeatData"]["startTime"]) { - _networkCounter.intervalRequestExecutionTime += utcNow() - payloadData["statsBeatData"]["startTime"]; + _networkCounter.totalRequest++; + _networkCounter.requestDuration += utcNow() - payloadData["statsBeatData"]["startTime"]; } if (status === 200) { - _networkCounter.succesfulRequestCount++; + _networkCounter.success++; } else if (strIncludes("307,308,401,402,403,408,429,439,500,503", status.toString())) { // These statuses are not considered failures if (strIncludes("401,403,408,429,500,503", status.toString())) { - _networkCounter.retry_Count[status] = (_networkCounter.retry_Count[status] || 0) + 1; + _networkCounter.retry[status] = (_networkCounter.retry[status] || 0) + 1; } if (strIncludes("402,439", status.toString())) { - _networkCounter.throttleCount++; + _networkCounter.throttle++; } } else { - _networkCounter.requests_Failure_Count[status] = (_networkCounter.requests_Failure_Count[status] || 0) + 1; + _networkCounter.failure[status] = (_networkCounter.failure[status] || 0) + 1; } }; - _self.countException = (endpoint: string, event: ErrorEvent) => { + _self.countException = (endpoint: string, message: string) => { if (!_isEnabled || !_checkEndpoint(endpoint)) { return; } - _networkCounter.exception_Count[event.error.name] = (_networkCounter.exception_Count[event.error.name] || 0) + 1; + _networkCounter.exception[message] = (_networkCounter.exception[message] || 0) + 1; } @@ -124,45 +121,39 @@ export class Statsbeat implements IStatsBeat { function _trackSendRequestDuration() { var currentCounter = _networkCounter; - currentCounter.time = utcNow(); - var intervalRequests = (currentCounter.totalRequestCount - currentCounter.lastRequestCount) || 0; - var elapsedMs = currentCounter.time - currentCounter.lastTime; - var averageRequestExecutionTime = ((currentCounter.intervalRequestExecutionTime - currentCounter.lastIntervalRequestExecutionTime) / intervalRequests) || 0; - currentCounter.lastIntervalRequestExecutionTime = currentCounter.intervalRequestExecutionTime; // reset - if (elapsedMs > 0 && intervalRequests > 0) { + if (currentCounter.totalRequest > 0 ) { + var averageRequestExecutionTime = currentCounter.requestDuration / currentCounter.totalRequest; _sendStatsbeats("Request_Duration", averageRequestExecutionTime); } } - function _trackSendRequestsCount() { var currentCounter = _networkCounter; - if (currentCounter.succesfulRequestCount > 0) { - _sendStatsbeats("Request_Success_Count", currentCounter.succesfulRequestCount); + if (currentCounter.success > 0) { + _sendStatsbeats("Request_Success_Count", currentCounter.success); } - for (const code in currentCounter.requests_Failure_Count) { - const count = currentCounter.requests_Failure_Count[code]; - _sendStatsbeats("Requests_Failure_Count", count, { statusCode: code }); + for (const code in currentCounter.failure) { + const count = currentCounter.failure[code]; + _sendStatsbeats("failure", count, { statusCode: code }); } - for (const code in currentCounter.retry_Count) { - const count = currentCounter.retry_Count[code]; - _sendStatsbeats("Retry_Count", count, { statusCode: code }); + for (const code in currentCounter.retry) { + const count = currentCounter.retry[code]; + _sendStatsbeats("retry", count, { statusCode: code }); } - for (const code in currentCounter.exception_Count) { - const count = currentCounter.exception_Count[code]; - _sendStatsbeats("Exception_Count", count, { exceptionType: code }); + for (const code in currentCounter.exception) { + const count = currentCounter.exception[code]; + _sendStatsbeats("exception", count, { exceptionType: code }); } - if (currentCounter.throttleCount > 0) { - _sendStatsbeats("Throttle_Count", currentCounter.throttleCount); + if (currentCounter.throttle > 0) { + _sendStatsbeats("Throttle_Count", currentCounter.throttle); } - } }) - }; + } public initialize(core: IAppInsightsCore, ikey: string, endpoint: string, version?: string) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging @@ -173,15 +164,11 @@ export class Statsbeat implements IStatsBeat { return false; } - public setInitialized(value: boolean) { - // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging - } - public count(status: number, payloadData: IPayloadData, endpoint: string) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } - public countException(endpoint: string, event: ErrorEvent) { + public countException(endpoint: string, message: string) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } From 28f2696c92cd4505ea529d08fe43655f0c3dba5c Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Wed, 19 Mar 2025 15:00:01 -0700 Subject: [PATCH 15/62] change class to interface --- .../src/Sender.ts | 12 +++-- .../src/JavaScriptSDK/NetworkStatsbeat.ts | 45 +++++++++---------- .../src/JavaScriptSDK/StatsBeat.ts | 6 +-- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 91d82e915..3f8cb74b4 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -739,8 +739,10 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { { message }); _self._buffer && _self._buffer.clearSent(payload); - var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - _statsBeat.countException(endpointHost, message); + if (_statsBeat) { + var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; + _statsBeat.countException(endpointHost, message); + } } /** * partial success handler @@ -939,8 +941,10 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { function _doSend(sendInterface: IXHROverride, payload: IInternalStorageItem[], isAsync: boolean, markAsSent: boolean = true): void | IPromise { let onComplete = (status: number, headers: {[headerName: string]: string;}, response?: string) => { - var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - _statsBeat.count(status, payloadData, endpointHost); + if (_statsBeat) { + var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; + _statsBeat.count(status, payloadData, endpointHost); + } return _getOnComplete(payload, status, headers, response); } let payloadData = _getPayload(payload); diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts index 339ffa1b5..a75a257e2 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts @@ -1,25 +1,22 @@ - -export class NetworkStatsbeat { - - public host: string; - - public totalRequest: number; - public success: number; - public throttle: number; - public failure: Record; - public retry: Record; - public exception: Record; - - public requestDuration: number; - - constructor(host: string) { - this.host = host; - this.totalRequest = 0; - this.success = 0; - this.throttle = 0; - this.requestDuration = 0; - this.failure = {}; - this.retry = {}; - this.exception = {}; - } +export interface NetworkStatsbeat { + host: string; + totalRequest: number; + success: number; + throttle: number; + failure: Record; + retry: Record; + exception: Record; + requestDuration: number; +} +export function createNetworkStatsbeat(host: string): NetworkStatsbeat { + return { + host, + totalRequest: 0, + success: 0, + throttle: 0, + failure: {}, + retry: {}, + exception: {}, + requestDuration: 0, + }; } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 7a4a1a5bc..ac648ea9d 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -4,7 +4,7 @@ import { IAppInsightsCore } from "../JavaScriptSDK.Interfaces/IAppInsightsCore"; import { IStatsBeat } from "../JavaScriptSDK.Interfaces/IStatsBeat"; import { ITelemetryItem } from "../JavaScriptSDK.Interfaces/ITelemetryItem"; import { IPayloadData } from "../JavaScriptSDK.Interfaces/IXHROverride"; -import { NetworkStatsbeat } from "./NetworkStatsbeat"; +import { NetworkStatsbeat, createNetworkStatsbeat } from "./NetworkStatsbeat"; const INSTRUMENTATION_KEY = "c4a29126-a7cb-47e5-b348-11414998b11e"; const STATS_COLLECTION_SHORT_INTERVAL: number = 900000; // 15 minutes @@ -27,7 +27,7 @@ export class Statsbeat implements IStatsBeat { dynamicProto(Statsbeat, this, (_self, _base) => { _self.initialize = (core: IAppInsightsCore, ikey: string, endpoint: string, version?: string) => { _core = core; - _networkCounter = new NetworkStatsbeat(endpoint); + _networkCounter = createNetworkStatsbeat(endpoint); _isEnabled = true; _sdkVersion = version; @@ -79,7 +79,7 @@ export class Statsbeat implements IStatsBeat { _self.trackShortIntervalStatsbeats = (): void => { _trackSendRequestDuration(); _trackSendRequestsCount(); - _networkCounter = new NetworkStatsbeat(_networkCounter.host); + _networkCounter = createNetworkStatsbeat(_networkCounter.host); } function _checkEndpoint(endpoint: string) { From c81ea69aa2ab8cfeb7086a1e93b22598923cc2e7 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Thu, 20 Mar 2025 13:05:30 -0700 Subject: [PATCH 16/62] set up timer --- .../src/JavaScriptSDK/StatsBeat.ts | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index ac648ea9d..48dfbee58 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -1,5 +1,5 @@ import dynamicProto from "@microsoft/dynamicproto-js"; -import { strIncludes, utcNow } from "@nevware21/ts-utils"; +import { ITimerHandler, utcNow, scheduleTimeout} from "@nevware21/ts-utils"; import { IAppInsightsCore } from "../JavaScriptSDK.Interfaces/IAppInsightsCore"; import { IStatsBeat } from "../JavaScriptSDK.Interfaces/IStatsBeat"; import { ITelemetryItem } from "../JavaScriptSDK.Interfaces/ITelemetryItem"; @@ -14,10 +14,9 @@ const STATSBEAT_TYPE = "Browser"; export class Statsbeat implements IStatsBeat { constructor() { let _networkCounter: NetworkStatsbeat; - let _handle: any; let _isEnabled: boolean; let _core: IAppInsightsCore; - + let _timeoutHandle: ITimerHandler; // Handle to the timer for delayed sending of batches of data. // Custom dimensions let _cikey: string; let _language: string; @@ -32,11 +31,9 @@ export class Statsbeat implements IStatsBeat { _sdkVersion = version; _getCustomProperties(ikey); - if (!_handle) { - _handle = setInterval(() => { - this.trackShortIntervalStatsbeats(); - }, STATS_COLLECTION_SHORT_INTERVAL); - } + + + _isEnabled = true; } @@ -53,28 +50,38 @@ export class Statsbeat implements IStatsBeat { _networkCounter.totalRequest++; _networkCounter.requestDuration += utcNow() - payloadData["statsBeatData"]["startTime"]; } + let retryArray = [401, 403, 408, 429, 500, 503]; + let throttleArray = [402, 439]; if (status === 200) { _networkCounter.success++; - } else if (strIncludes("307,308,401,402,403,408,429,439,500,503", status.toString())) { - // These statuses are not considered failures - if (strIncludes("401,403,408,429,500,503", status.toString())) { + } else if (retryArray.includes(status)) { _networkCounter.retry[status] = (_networkCounter.retry[status] || 0) + 1; - } - if (strIncludes("402,439", status.toString())) { + } else if (throttleArray.includes(status)) { _networkCounter.throttle++; - } - } else { + } else if (status !== 307 && status !== 308) { _networkCounter.failure[status] = (_networkCounter.failure[status] || 0) + 1; } + _setupTimer(); }; + + _self.countException = (endpoint: string, message: string) => { if (!_isEnabled || !_checkEndpoint(endpoint)) { return; } _networkCounter.exception[message] = (_networkCounter.exception[message] || 0) + 1; + _setupTimer(); + } + + function _setupTimer() { + if (!_timeoutHandle) { + _timeoutHandle = scheduleTimeout(() => { + _timeoutHandle = null; + this.trackShortIntervalStatsbeats(); + }, STATS_COLLECTION_SHORT_INTERVAL); + } } - _self.trackShortIntervalStatsbeats = (): void => { _trackSendRequestDuration(); From eb2392b0e7bf517eed01383b26986c8a262fddd3 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Thu, 20 Mar 2025 13:13:18 -0700 Subject: [PATCH 17/62] avoid duplicate init --- .../src/JavaScriptSDK/AppInsightsCore.ts | 2 +- .../AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts | 12 +++--------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index 191e05a04..a5323a955 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -361,7 +361,7 @@ export class AppInsightsCore im _initInMemoMaxSize = rootCfg.initInMemoMaxSize || maxInitQueueSize; if (config.disableStatsBeat === false){ - _statsBeat = new Statsbeat(); + _statsBeat = _statsBeat || new Statsbeat(); } else { _statsBeat = null; } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 48dfbee58..a690af46b 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -14,9 +14,9 @@ const STATSBEAT_TYPE = "Browser"; export class Statsbeat implements IStatsBeat { constructor() { let _networkCounter: NetworkStatsbeat; - let _isEnabled: boolean; + let _isEnabled: boolean = false; let _core: IAppInsightsCore; - let _timeoutHandle: ITimerHandler; // Handle to the timer for delayed sending of batches of data. + let _timeoutHandle: ITimerHandler; // Handle to the timer for sending telemetry. This way, we would not send telemetry when system sleep. // Custom dimensions let _cikey: string; let _language: string; @@ -29,13 +29,7 @@ export class Statsbeat implements IStatsBeat { _networkCounter = createNetworkStatsbeat(endpoint); _isEnabled = true; _sdkVersion = version; - _getCustomProperties(ikey); - - - - _isEnabled = true; - } _self.isInitialized = (): boolean => { @@ -159,7 +153,7 @@ export class Statsbeat implements IStatsBeat { _sendStatsbeats("Throttle_Count", currentCounter.throttle); } } - }) + }); } public initialize(core: IAppInsightsCore, ikey: string, endpoint: string, version?: string) { From 6dd75289826f0acfb2b4d55ebcdffa7f97b7a620 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Thu, 20 Mar 2025 14:11:03 -0700 Subject: [PATCH 18/62] rename exception --- .../src/SendBuffer.ts | 2 ++ .../applicationinsights-channel-js/src/Sender.ts | 4 ---- .../src/JavaScriptSDK.Interfaces/IStatsBeat.ts | 2 +- .../src/JavaScriptSDK/NetworkStatsbeat.ts | 2 +- .../AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts | 14 ++++++++------ 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/SendBuffer.ts b/channels/applicationinsights-channel-js/src/SendBuffer.ts index 91ea6d401..1be79d7ac 100644 --- a/channels/applicationinsights-channel-js/src/SendBuffer.ts +++ b/channels/applicationinsights-channel-js/src/SendBuffer.ts @@ -103,6 +103,8 @@ abstract class BaseSendBuffer { if (!isNullOrUndefined(_maxRetryCnt)) { if (payload.cnt > _maxRetryCnt) { // TODO: add log here on dropping payloads + // should log exception here + return; } } diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 3f8cb74b4..cf62b1fc6 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -739,10 +739,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { { message }); _self._buffer && _self._buffer.clearSent(payload); - if (_statsBeat) { - var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - _statsBeat.countException(endpointHost, message); - } } /** * partial success handler diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts index 4c1f6b0ea..3c9d051de 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts @@ -5,6 +5,6 @@ export interface IStatsBeat { initialize(core: IAppInsightsCore, ikey: string, endpoint: string, version?: string) : void; isInitialized(): boolean; count(status: number, payloadData: IPayloadData, endpoint: string): void; - countException(endpoint: string, message: string): void; + countException(endpoint: string, exceptionType: string): void; trackShortIntervalStatsbeats(): void; } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts index a75a257e2..f582c1762 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts @@ -17,6 +17,6 @@ export function createNetworkStatsbeat(host: string): NetworkStatsbeat { failure: {}, retry: {}, exception: {}, - requestDuration: 0, + requestDuration: 0 }; } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index a690af46b..aedeae040 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -1,5 +1,5 @@ import dynamicProto from "@microsoft/dynamicproto-js"; -import { ITimerHandler, utcNow, scheduleTimeout} from "@nevware21/ts-utils"; +import { ITimerHandler, scheduleTimeout, utcNow } from "@nevware21/ts-utils"; import { IAppInsightsCore } from "../JavaScriptSDK.Interfaces/IAppInsightsCore"; import { IStatsBeat } from "../JavaScriptSDK.Interfaces/IStatsBeat"; import { ITelemetryItem } from "../JavaScriptSDK.Interfaces/ITelemetryItem"; @@ -49,9 +49,9 @@ export class Statsbeat implements IStatsBeat { if (status === 200) { _networkCounter.success++; } else if (retryArray.includes(status)) { - _networkCounter.retry[status] = (_networkCounter.retry[status] || 0) + 1; + _networkCounter.retry[status] = (_networkCounter.retry[status] || 0) + 1; } else if (throttleArray.includes(status)) { - _networkCounter.throttle++; + _networkCounter.throttle++; } else if (status !== 307 && status !== 308) { _networkCounter.failure[status] = (_networkCounter.failure[status] || 0) + 1; } @@ -60,11 +60,11 @@ export class Statsbeat implements IStatsBeat { - _self.countException = (endpoint: string, message: string) => { + _self.countException = (endpoint: string, exceptionType: string) => { if (!_isEnabled || !_checkEndpoint(endpoint)) { return; } - _networkCounter.exception[message] = (_networkCounter.exception[message] || 0) + 1; + _networkCounter.exception[exceptionType] = (_networkCounter.exception[exceptionType] || 0) + 1; _setupTimer(); } @@ -81,6 +81,8 @@ export class Statsbeat implements IStatsBeat { _trackSendRequestDuration(); _trackSendRequestsCount(); _networkCounter = createNetworkStatsbeat(_networkCounter.host); + _timeoutHandle && _timeoutHandle.cancel(); + _timeoutHandle = null; } function _checkEndpoint(endpoint: string) { @@ -169,7 +171,7 @@ export class Statsbeat implements IStatsBeat { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } - public countException(endpoint: string, message: string) { + public countException(endpoint: string, exceptionType: string) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } From 96d50894445d808726c932486f3d069e502ade63 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Thu, 20 Mar 2025 14:14:57 -0700 Subject: [PATCH 19/62] Update testVersionConflict.html --- AISKU/Tests/Manual/testVersionConflict.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/AISKU/Tests/Manual/testVersionConflict.html b/AISKU/Tests/Manual/testVersionConflict.html index fccf8c900..1e1b5e997 100644 --- a/AISKU/Tests/Manual/testVersionConflict.html +++ b/AISKU/Tests/Manual/testVersionConflict.html @@ -16,13 +16,12 @@ // 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, // useXhr: 1, // Use XHR instead of fetch to report failures (if available), // dle: true, // Prevent the SDK from reporting load failure log - 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) sri: true, // Custom optional value to specify whether fetching the snippet from integrity file and do integrity check cfg: { // Application Insights Configuration disableStatsBeat: false, - connectionString: "InstrumentationKey=814a172a-92fd-4950-9023-9cf13bb65696;IngestionEndpoint=https://eastus-8.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus.livediagnostics.monitor.azure.com/" + connectionString: "YOUR_INSTRUMENTATION_KEY", } }); From 6131e9fad10fc82fd252747651edc79ed39eacd9 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Thu, 20 Mar 2025 16:01:35 -0700 Subject: [PATCH 20/62] add some comment --- .../src/Sender.ts | 18 ++++++++++++------ .../src/JavaScriptSDK/SenderPostManager.ts | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index cf62b1fc6..fe037f8f4 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -185,6 +185,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let _disableBeaconSplit: boolean; let _sendPostMgr: SenderPostManager; let _retryCodes: number[]; + let _core: IAppInsightsCore; dynamicProto(Sender, this, (_self, _base) => { @@ -260,7 +261,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let diagLog = _self.diagLog(); _evtNamespace = mergeEvtNamespace(createUniqueNamespace("Sender"), core.evtNamespace && core.evtNamespace()); _offlineListener = createOfflineListener(_evtNamespace); - + _core = core; // This function will be re-called whenever any referenced configuration is changed _self._addHook(onConfigChange(config, (details) => { let config = details.cfg; @@ -681,20 +682,24 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (!payloadArr) { return; } + let result = _checkResponsStatus(response.status, payloadArr, response.url, payloadArr.length, response.statusText, resValue || ""); onComplete(response.status, payload.headers, response.statusText); - return _checkResponsStatus(response.status, payloadArr, response.url, payloadArr.length, response.statusText, resValue || ""); + return result; }, xhrOnComplete: (request: XMLHttpRequest, oncomplete: OnCompleteCallback, payload?: IPayloadData) => { let payloadArr = _getPayloadArr(payload); if (!payloadArr) { return; } + let result = _xhrReadyStateChange(request, payloadArr, payloadArr.length); oncomplete(request.status, payload.headers, getResponseText(request)); - return _xhrReadyStateChange(request, payloadArr, payloadArr.length); + return result; }, beaconOnRetry: (data: IPayloadData, onComplete: OnCompleteCallback, canSend: (payload: IPayloadData, oncomplete: OnCompleteCallback, sync?: boolean) => boolean) => { - return _onBeaconRetry(data, onComplete, canSend); + let result = _onBeaconRetry(data, onComplete, canSend); + onComplete(-1, data.headers); // don't know status code here, but we know it's already a failued request + return result; } } as _ISenderOnComplete; @@ -937,9 +942,10 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { function _doSend(sendInterface: IXHROverride, payload: IInternalStorageItem[], isAsync: boolean, markAsSent: boolean = true): void | IPromise { let onComplete = (status: number, headers: {[headerName: string]: string;}, response?: string) => { - if (_statsBeat) { + let statsbeat = _core.getStatsBeat(); + if (statsbeat) { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - _statsBeat.count(status, payloadData, endpointHost); + statsbeat.count(status, payloadData, endpointHost); } return _getOnComplete(payload, status, headers, response); } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts b/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts index f27d1da09..f3fdd2bdc 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts @@ -249,7 +249,7 @@ export class SenderPostManager { } else { // if can send - _onSuccess(STR_EMPTY, oncomplete); + _onSuccess(STR_EMPTY, oncomplete); // if success, onComplete is called with status code 200 } } From b24c9fd9dca61de9aa66cc799243993336407478 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 24 Mar 2025 15:40:43 -0700 Subject: [PATCH 21/62] add count check --- shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts | 8 +++++--- tools/chrome-debug-extension/manifest.json | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index aedeae040..1c48d3cfe 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -97,6 +97,9 @@ export class Statsbeat implements IStatsBeat { } function _sendStatsbeats(name: string, val: number, properties?: {}) { + if (val <= 0){ + return; + } // Add extra properties let baseProperties = { "rp": "unknown", @@ -132,9 +135,8 @@ export class Statsbeat implements IStatsBeat { function _trackSendRequestsCount() { var currentCounter = _networkCounter; - if (currentCounter.success > 0) { - _sendStatsbeats("Request_Success_Count", currentCounter.success); - } + + _sendStatsbeats("Request_Success_Count", currentCounter.success); for (const code in currentCounter.failure) { const count = currentCounter.failure[code]; diff --git a/tools/chrome-debug-extension/manifest.json b/tools/chrome-debug-extension/manifest.json index 9b234f5a8..7ab3f42a4 100644 --- a/tools/chrome-debug-extension/manifest.json +++ b/tools/chrome-debug-extension/manifest.json @@ -2,8 +2,8 @@ "name": "Telemetry Viewer - M3", "short_name": "Telemetry Viewer M3", "description": "A browser extension that provides a real time view of what's happening in Application Insights including what telemetry is being logged by the web application", - "version": "0.7.5", - "version_name": "0.7.5", + "version": "0.7.6", + "version_name": "0.7.6", "manifest_version": 3, "icons": { "16": "images/icon-16.png", From ea2b96a8c5842be1ecc65eafff13eb6e1d6f0eca Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 24 Mar 2025 15:46:38 -0700 Subject: [PATCH 22/62] throttle count --- .../AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts | 4 ++-- shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts index f582c1762..a7dcdc835 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/NetworkStatsbeat.ts @@ -2,7 +2,7 @@ export interface NetworkStatsbeat { host: string; totalRequest: number; success: number; - throttle: number; + throttle: Record; failure: Record; retry: Record; exception: Record; @@ -13,7 +13,7 @@ export function createNetworkStatsbeat(host: string): NetworkStatsbeat { host, totalRequest: 0, success: 0, - throttle: 0, + throttle: {}, failure: {}, retry: {}, exception: {}, diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 1c48d3cfe..898e924f7 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -51,7 +51,7 @@ export class Statsbeat implements IStatsBeat { } else if (retryArray.includes(status)) { _networkCounter.retry[status] = (_networkCounter.retry[status] || 0) + 1; } else if (throttleArray.includes(status)) { - _networkCounter.throttle++; + _networkCounter.throttle[status] = (_networkCounter.throttle[status] || 0) + 1; } else if (status !== 307 && status !== 308) { _networkCounter.failure[status] = (_networkCounter.failure[status] || 0) + 1; } @@ -153,8 +153,9 @@ export class Statsbeat implements IStatsBeat { _sendStatsbeats("exception", count, { exceptionType: code }); } - if (currentCounter.throttle > 0) { - _sendStatsbeats("Throttle_Count", currentCounter.throttle); + for (const code in currentCounter.throttle) { + const count = currentCounter.throttle[code]; + _sendStatsbeats("Throttle_Count", count, { statusCode: code }); } } }); From 41cb9d7b98def9a01dc76c8e83d6a2a27105a9c4 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 24 Mar 2025 17:51:48 -0700 Subject: [PATCH 23/62] fix the ugilify not compile problem --- .../src/JavaScriptSDK/StatsBeat.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 898e924f7..829360ccb 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -41,16 +41,16 @@ export class Statsbeat implements IStatsBeat { return; } if (payloadData && payloadData["statsBeatData"] && payloadData["statsBeatData"]["startTime"]) { - _networkCounter.totalRequest++; + _networkCounter.totalRequest = (_networkCounter.totalRequest || 0) + 1; _networkCounter.requestDuration += utcNow() - payloadData["statsBeatData"]["startTime"]; } let retryArray = [401, 403, 408, 429, 500, 503]; let throttleArray = [402, 439]; if (status === 200) { _networkCounter.success++; - } else if (retryArray.includes(status)) { + } else if (retryArray.indexOf(status) !== -1) { _networkCounter.retry[status] = (_networkCounter.retry[status] || 0) + 1; - } else if (throttleArray.includes(status)) { + } else if (throttleArray.indexOf(status) !== -1) { _networkCounter.throttle[status] = (_networkCounter.throttle[status] || 0) + 1; } else if (status !== 307 && status !== 308) { _networkCounter.failure[status] = (_networkCounter.failure[status] || 0) + 1; @@ -126,11 +126,14 @@ export class Statsbeat implements IStatsBeat { } function _trackSendRequestDuration() { - var currentCounter = _networkCounter; - if (currentCounter.totalRequest > 0 ) { - var averageRequestExecutionTime = currentCounter.requestDuration / currentCounter.totalRequest; + + var totalRequest = _networkCounter.totalRequest; + + if (_networkCounter.totalRequest > 0 ) { + let averageRequestExecutionTime = _networkCounter.requestDuration / totalRequest; _sendStatsbeats("Request_Duration", averageRequestExecutionTime); } + } function _trackSendRequestsCount() { From d4755683bea416d0a6276e82642f3c05a4b0378b Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 25 Mar 2025 15:07:16 -0700 Subject: [PATCH 24/62] status code change --- .../applicationinsights-channel-js/src/Sender.ts | 12 ++++++------ .../AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index fe037f8f4..5dfd947ef 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -682,24 +682,24 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (!payloadArr) { return; } - let result = _checkResponsStatus(response.status, payloadArr, response.url, payloadArr.length, response.statusText, resValue || ""); + _checkResponsStatus(response.status, payloadArr, response.url, payloadArr.length, response.statusText, resValue || ""); onComplete(response.status, payload.headers, response.statusText); - return result; + return; }, xhrOnComplete: (request: XMLHttpRequest, oncomplete: OnCompleteCallback, payload?: IPayloadData) => { let payloadArr = _getPayloadArr(payload); if (!payloadArr) { return; } - let result = _xhrReadyStateChange(request, payloadArr, payloadArr.length); + _xhrReadyStateChange(request, payloadArr, payloadArr.length); oncomplete(request.status, payload.headers, getResponseText(request)); - return result; + return; }, beaconOnRetry: (data: IPayloadData, onComplete: OnCompleteCallback, canSend: (payload: IPayloadData, oncomplete: OnCompleteCallback, sync?: boolean) => boolean) => { - let result = _onBeaconRetry(data, onComplete, canSend); + _onBeaconRetry(data, onComplete, canSend); onComplete(-1, data.headers); // don't know status code here, but we know it's already a failued request - return result; + return; } } as _ISenderOnComplete; diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 829360ccb..316f109c4 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -44,7 +44,7 @@ export class Statsbeat implements IStatsBeat { _networkCounter.totalRequest = (_networkCounter.totalRequest || 0) + 1; _networkCounter.requestDuration += utcNow() - payloadData["statsBeatData"]["startTime"]; } - let retryArray = [401, 403, 408, 429, 500, 503]; + let retryArray = [401, 403, 408, 429, 500, 502, 503]; let throttleArray = [402, 439]; if (status === 200) { _networkCounter.success++; @@ -52,7 +52,7 @@ export class Statsbeat implements IStatsBeat { _networkCounter.retry[status] = (_networkCounter.retry[status] || 0) + 1; } else if (throttleArray.indexOf(status) !== -1) { _networkCounter.throttle[status] = (_networkCounter.throttle[status] || 0) + 1; - } else if (status !== 307 && status !== 308) { + } else if (status !== 307 && status !== 308 && status !== 206) { _networkCounter.failure[status] = (_networkCounter.failure[status] || 0) + 1; } _setupTimer(); From fae32956d78468921e9386e9aac26d31b1adc118 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 25 Mar 2025 15:54:45 -0700 Subject: [PATCH 25/62] add basic test --- .../Tests/Unit/src/StatsBeat.tests.ts | 79 +++++++++++++++++++ .../src/Sender.ts | 2 +- .../JavaScriptSDK.Interfaces/IStatsBeat.ts | 1 - .../src/JavaScriptSDK/StatsBeat.ts | 9 +-- 4 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts diff --git a/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts b/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts new file mode 100644 index 000000000..c126dd55b --- /dev/null +++ b/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts @@ -0,0 +1,79 @@ +import { AITestClass } from "@microsoft/ai-test-framework"; +import { AppInsightsCore } from "@microsoft/applicationinsights-core-js"; +import { Sender } from "../../../src/Sender"; + +export class StatsbeatTests extends AITestClass { + private _core: AppInsightsCore; + private _sender: Sender; + + public testInitialize() { + this._core = new AppInsightsCore(); + this._sender = new Sender(); + } + + public testFinishedCleanup() { + if (this._sender && this._sender.isInitialized()) { + this._sender.pause(); + this._sender._buffer.clear(); + this._sender.teardown(); + } + this._sender = null; + this._core = null; + + } + + public registerTests() { + this.testCase({ + name: "Statsbeat initializes when disableStatsBeat is false", + test: () => { + let config = { + disableStatsBeat: false, + instrumentationKey: "Test-iKey" + }; + + // Initialize core with the configuration + this._core.initialize(config, [this._sender]); + + // Get Statsbeat from core + const statsbeat = this._core.getStatsBeat(); + + // Assert that Statsbeat is initialized + QUnit.assert.ok(statsbeat, "Statsbeat is initialized"); + QUnit.assert.ok(statsbeat.isInitialized(), "Statsbeat is marked as initialized"); + } + }); + + this.testCase({ + name: "Statsbeat dynamically updates when disableStatsBeat changes", + useFakeTimers: true, + test: () => { + let config = { + disableStatsBeat: true, + instrumentationKey: "Test-iKey" + }; + + // Initialize core with the configuration + this._core.initialize(config, [this._sender]); + + // Initially, Statsbeat should be null + let statsbeat = this._core.getStatsBeat(); + QUnit.assert.ok(!statsbeat, "Statsbeat is null when disableStatsBeat is true"); + + // Dynamically enable Statsbeat + this._core.config.disableStatsBeat = false; + this.clock.tick(1); // Simulate time passing for dynamic config update + + statsbeat = this._core.getStatsBeat(); + QUnit.assert.ok(statsbeat, "Statsbeat is initialized after enabling disableStatsBeat"); + QUnit.assert.ok(statsbeat.isInitialized(), "Statsbeat is marked as initialized after enabling disableStatsBeat"); + + // Dynamically disable Statsbeat again + this._core.config.disableStatsBeat = true; + this.clock.tick(1); // Simulate time passing for dynamic config update + + statsbeat = this._core.getStatsBeat(); + QUnit.assert.ok(!statsbeat, "Statsbeat is null after disabling disableStatsBeat again"); + } + }); + } +} \ No newline at end of file diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 5dfd947ef..f0a63d183 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -288,7 +288,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } } - if (_statsBeat && !_statsBeat.isInitialized()) { + if (!config.disableStatsBeat && _statsBeat && !_statsBeat.isInitialized()) { var endpointHost = urlParseUrl(senderConfig.endpointUrl).hostname; _statsBeat.initialize(core, senderConfig.instrumentationKey, endpointHost, EnvelopeCreator.Version); } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts index 3c9d051de..c3209aed1 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts @@ -6,5 +6,4 @@ export interface IStatsBeat { isInitialized(): boolean; count(status: number, payloadData: IPayloadData, endpoint: string): void; countException(endpoint: string, exceptionType: string): void; - trackShortIntervalStatsbeats(): void; } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 316f109c4..0f4db673d 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -72,12 +72,12 @@ export class Statsbeat implements IStatsBeat { if (!_timeoutHandle) { _timeoutHandle = scheduleTimeout(() => { _timeoutHandle = null; - this.trackShortIntervalStatsbeats(); + trackStatsbeats(); }, STATS_COLLECTION_SHORT_INTERVAL); } } - _self.trackShortIntervalStatsbeats = (): void => { + function trackStatsbeats(){ _trackSendRequestDuration(); _trackSendRequestsCount(); _networkCounter = createNetworkStatsbeat(_networkCounter.host); @@ -180,9 +180,4 @@ export class Statsbeat implements IStatsBeat { public countException(endpoint: string, exceptionType: string) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } - - public trackShortIntervalStatsbeats() { - // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging - } - } From c94a7529c9988c087fd312176ff74784cf020124 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 25 Mar 2025 16:58:32 -0700 Subject: [PATCH 26/62] add counter test --- .../Tests/Unit/src/StatsBeat.Tests.ts | 241 ++++++++++++++++++ .../Tests/Unit/src/aiunittests.ts | 3 + .../src/JavaScriptSDK/StatsBeat.ts | 27 +- 3 files changed, 265 insertions(+), 6 deletions(-) create mode 100644 shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts diff --git a/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts new file mode 100644 index 000000000..487a3b940 --- /dev/null +++ b/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts @@ -0,0 +1,241 @@ +import { Assert, AITestClass } from "@microsoft/ai-test-framework"; +import { AppInsightsCore, IAppInsightsCore, IConfiguration, IPlugin, ITelemetryItem } from "../../../src/applicationinsights-core-js"; +import { Statsbeat } from "../../../src/JavaScriptSDK/StatsBeat"; +import { IPayloadData } from "../../../src/JavaScriptSDK.Interfaces/IXHROverride"; +import * as sinon from "sinon"; +const STATS_COLLECTION_SHORT_INTERVAL: number = 900000; // 15 minutes + +export class StatsBeatTests extends AITestClass { + private _core: AppInsightsCore; + private _config: IConfiguration; + private _statsbeat: Statsbeat; + private _trackSpy: sinon.SinonSpy; // Fix: Properly type the spy + + constructor(emulateIe: boolean) { + super("StatsBeatTests", emulateIe); + } + + public testInitialize() { + let _self = this; + super.testInitialize(); + + _self._config = { + instrumentationKey: "Test-iKey", + disableInstrumentationKeyValidation: true, + disableStatsBeat: false + }; + + _self._core = new AppInsightsCore(); + _self._statsbeat = new Statsbeat(); + + // Create spy for tracking telemetry + _self._trackSpy = this.sandbox.spy(_self._core, "track"); + } + + public testCleanup() { + super.testCleanup(); + this._core = null; + this._statsbeat = null; + } + + public registerTests() { + + this.testCase({ + name: "StatsBeat: Initialization", + test: () => { + // Test with no initialization + Assert.equal(false, this._statsbeat.isInitialized(), "StatsBeat should not be initialized by default"); + + // Initialize and test + this._statsbeat.initialize(this._core, "Test-iKey", "https://example.endpoint.com", "1.0.0"); + Assert.equal(true, this._statsbeat.isInitialized(), "StatsBeat should be initialized after initialization"); + } + }); + + this.testCase({ + name: "StatsBeat: count method tracks request metrics", + useFakeTimers: true, + test: () => { + // Initialize StatsBeat + this._statsbeat.initialize(this._core, "Test-iKey", "https://example.endpoint.com", "1.0.0"); + + // Create mock payload data with timing information + const payloadData = { + urlString: "https://example.endpoint.com", + data: "testData", + headers: {}, + timeout: 0, // Fix: Add required properties + disableXhrSync: false, // Fix: Add required properties + statsBeatData: { + startTime: "2023-10-01T00:00:00Z" // Simulated start time + } + } as IPayloadData; + + // Test successful request + this._statsbeat.count(200, payloadData, "https://example.endpoint.com"); + + // Test failed request + this._statsbeat.count(500, payloadData, "https://example.endpoint.com"); + + // Test throttled request + this._statsbeat.count(429, payloadData, "https://example.endpoint.com"); + + // Verify that trackStatsbeats is called when the timer fires + this.clock.tick(STATS_COLLECTION_SHORT_INTERVAL + 1); + + // Verify that track was called + Assert.ok(this._trackSpy.called, "track should be called when statsbeat timer fires"); + + // When the timer fires, multiple metrics should be sent + Assert.ok(this._trackSpy.callCount >= 3, "Multiple metrics should be tracked"); + } + }); + + this.testCase({ + name: "StatsBeat: countException method tracks exceptions", + useFakeTimers: true, + test: () => { + // Initialize StatsBeat + this._statsbeat.initialize(this._core, "Test-iKey", "https://example.endpoint.com", "1.0.0"); + + // Count an exception + this._statsbeat.countException("https://example.endpoint.com", "NetworkError"); + + // Verify that trackStatsbeats is called when the timer fires + this.clock.tick(900000 + 1); // STATS_COLLECTION_SHORT_INTERVAL + 1ms + + // Verify that track was called + Assert.ok(this._trackSpy.called, "track should be called when statsbeat timer fires"); + + // Check that exception metrics are tracked + let foundExceptionMetric = false; + for (let i = 0; i < this._trackSpy.callCount; i++) { + const call = this._trackSpy.getCall(i); + const item: ITelemetryItem = call.args[0]; + if (item.baseData && + item.baseData.properties && + item.baseData.properties.exceptionType === "NetworkError") { + foundExceptionMetric = true; + break; + } + } + + Assert.ok(foundExceptionMetric, "Exception metrics should be tracked"); + } + }); + + this.testCase({ + name: "StatsBeat: does not send metrics for different endpoints", + test: () => { + // Initialize StatsBeat for a specific endpoint + this._statsbeat.initialize(this._core, "Test-iKey", "https://example.endpoint.com", "1.0.0"); + + // Create mock payload data + const payloadData = { + urlString: "https://example.endpoint.com", + data: "testData", + headers: {}, + timeout: 0, // Fix: Add required properties + disableXhrSync: false, // Fix: Add required properties + statsBeatData: { + startTime: Date.now() + } + } as IPayloadData; + + // Set up spies to check internal calls + const countSpy = this.sandbox.spy(this._statsbeat, "count"); + + // Count metrics for a different endpoint + this._statsbeat.count(200, payloadData, "https://different.endpoint.com"); + + // The count method was called, but it should return early + Assert.equal(1, countSpy.callCount, "count method should be called"); + Assert.equal(0, this._trackSpy.callCount, "track should not be called for different endpoint"); + } + }); + + this.testCase({ + name: "StatsBeat: test dynamic configuration changes", + useFakeTimers: true, + test: () => { + // Setup core with statsbeat enabled + this._core.initialize(this._config, [new ChannelPlugin()]); + + // Verify that statsbeat is created + const statsbeat = this._core.getStatsBeat(); + Assert.ok(statsbeat, "Statsbeat should be created"); + + // Update configuration to disable statsbeat + this._core.config.disableStatsBeat = true; + this.clock.tick(1); // Allow time for config changes to propagate + + // Verify that statsbeat is removed + const updatedStatsbeat = this._core.getStatsBeat(); + Assert.ok(!updatedStatsbeat, "Statsbeat should be removed when disabled"); + + // Re-enable statsbeat + this._core.config.disableStatsBeat = false; + this.clock.tick(1); // Allow time for config changes to propagate + + // Verify that statsbeat is created again + const reenabledStatsbeat = this._core.getStatsBeat(); + Assert.ok(reenabledStatsbeat, "Statsbeat should be recreated when re-enabled"); + } + }); + } +} + +class ChannelPlugin implements IPlugin { + + public isFlushInvoked = false; + public isTearDownInvoked = false; + public isResumeInvoked = false; + public isPauseInvoked = false; + + public identifier = "Sender"; + + public priority: number = 1001; + + constructor() { + this.processTelemetry = this._processTelemetry.bind(this); + } + public pause(): void { + this.isPauseInvoked = true; + } + + public resume(): void { + this.isResumeInvoked = true; + } + + public teardown(): void { + this.isTearDownInvoked = true; + } + + flush(async?: boolean, callBack?: () => void): void { + this.isFlushInvoked = true; + if (callBack) { + callBack(); + } + } + + public processTelemetry(env: ITelemetryItem) {} + + setNextPlugin(next: any) { + // no next setup + } + + public initialize = (config: IConfiguration, core: IAppInsightsCore, plugin: IPlugin[]) => { + } + + private _processTelemetry(env: ITelemetryItem) { + + } +} + +class CustomTestError extends Error { + constructor(message = "") { + super(message); + this.name = "CustomTestError"; + this.message = message + " -- test error."; + } +} \ No newline at end of file diff --git a/shared/AppInsightsCore/Tests/Unit/src/aiunittests.ts b/shared/AppInsightsCore/Tests/Unit/src/aiunittests.ts index 6fc31aebc..11a062684 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/aiunittests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/aiunittests.ts @@ -11,6 +11,7 @@ import { UpdateConfigTests } from "./UpdateConfig.Tests"; import { EventsDiscardedReasonTests } from "./EventsDiscardedReason.Tests"; import { W3cTraceParentTests } from "./W3cTraceParentTests"; import { DynamicConfigTests } from "./DynamicConfig.Tests"; +import { StatsBeatTests } from './StatsBeat.Tests'; export function runTests() { new GlobalTestHooks().registerTests(); @@ -26,4 +27,6 @@ export function runTests() { new UpdateConfigTests().registerTests(); new EventsDiscardedReasonTests().registerTests(); new W3cTraceParentTests().registerTests(); + new StatsBeatTests(false).registerTests(); + new StatsBeatTests(true).registerTests(); } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 0f4db673d..9211badbd 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -96,8 +96,8 @@ export class Statsbeat implements IStatsBeat { _runTimeVersion = STATSBEAT_TYPE; } - function _sendStatsbeats(name: string, val: number, properties?: {}) { - if (val <= 0){ + function _sendStatsbeats(name: string, val: number, properties?: { [name: string]: any }) { + if (!val || val <= 0){ return; } // Add extra properties @@ -111,6 +111,24 @@ export class Statsbeat implements IStatsBeat { "version": _sdkVersion, "endpoint": "breeze", "host": _networkCounter.host + } as { [key: string]: any }; + + // Manually merge properties instead of using spread syntax + let combinedProps: { [key: string]: any } = { "host": _networkCounter.host }; + + // Add properties if present + if (properties) { + for (let key in properties) { + if (properties.hasOwnProperty(key)) { + combinedProps[key] = properties[key]; + } + } + } + // Add base properties + for (let key in baseProperties) { + if (baseProperties.hasOwnProperty(key)) { + combinedProps[key] = baseProperties[key]; + } } let statsbeatEvent: ITelemetryItem = { iKey: INSTRUMENTATION_KEY, @@ -118,7 +136,7 @@ export class Statsbeat implements IStatsBeat { baseData: { name: name, average: val, - properties: {"host": _networkCounter.host, ...properties, ...baseProperties} + properties: combinedProps }, baseType: "MetricData" }; @@ -126,19 +144,16 @@ export class Statsbeat implements IStatsBeat { } function _trackSendRequestDuration() { - var totalRequest = _networkCounter.totalRequest; if (_networkCounter.totalRequest > 0 ) { let averageRequestExecutionTime = _networkCounter.requestDuration / totalRequest; _sendStatsbeats("Request_Duration", averageRequestExecutionTime); } - } function _trackSendRequestsCount() { var currentCounter = _networkCounter; - _sendStatsbeats("Request_Success_Count", currentCounter.success); for (const code in currentCounter.failure) { From ee5faa9497b6094be51929d28329c1d62d615598 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Thu, 27 Mar 2025 13:19:02 -0700 Subject: [PATCH 27/62] Update Sender.ts --- channels/applicationinsights-channel-js/src/Sender.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index f0a63d183..b5daff8e8 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -950,7 +950,9 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { return _getOnComplete(payload, status, headers, response); } let payloadData = _getPayload(payload); - payloadData.statsBeatData = {startTime: dateNow()}; + if (payloadData) { + payloadData.statsBeatData = {startTime: dateNow()}; + } let sendPostFunc: SendPOSTFunction = sendInterface && sendInterface.sendPOST; if (sendPostFunc && payloadData) { // *********************************************************************************************** From 4b5ea4051648e7ba5cf06385b6f91cd8e14758f8 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 1 Apr 2025 12:27:27 -0700 Subject: [PATCH 28/62] signature changes --- .../src/Sender.ts | 11 ++++++--- .../Tests/Unit/src/StatsBeat.Tests.ts | 24 +++++++++++++++---- .../JavaScriptSDK.Interfaces/IStatsBeat.ts | 8 ++++++- .../src/JavaScriptSDK/StatsBeat.ts | 20 +++++++--------- .../src/applicationinsights-core-js.ts | 2 +- tools/chrome-debug-extension/manifest.json | 4 ++-- 6 files changed, 47 insertions(+), 22 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index b5daff8e8..52339ce6c 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -7,7 +7,7 @@ import { import { ActiveStatus, BaseTelemetryPlugin, IAppInsightsCore, IBackendResponse, IChannelControls, IConfigDefaults, IConfiguration, IDiagnosticLogger, IInternalOfflineSupport, INotificationManager, IPayloadData, IPlugin, IProcessTelemetryContext, - IProcessTelemetryUnloadContext, IStatsBeat, IStatsBeatEvent, ITelemetryItem, ITelemetryPluginChain, ITelemetryUnloadState, + IProcessTelemetryUnloadContext, IStatsBeat, IStatsBeatConfig, IStatsBeatEvent, ITelemetryItem, ITelemetryPluginChain, ITelemetryUnloadState, IXDomainRequest, IXHROverride, OnCompleteCallback, SendPOSTFunction, SendRequestReason, SenderPostManager, TransportType, _ISendPostMgrConfig, _ISenderOnComplete, _eInternalMessageId, _throwInternal, _warnToConsole, arrForEach, cfgDfBoolean, cfgDfValidate, createProcessTelemetryContext, createUniqueNamespace, dateNow, dumpObj, eLoggingSeverity, formatErrorMessageXdr, formatErrorMessageXhr, @@ -288,9 +288,14 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } } - if (!config.disableStatsBeat && _statsBeat && !_statsBeat.isInitialized()) { + if (config.disableStatsBeat === false && _statsBeat && !_statsBeat.isInitialized()) { var endpointHost = urlParseUrl(senderConfig.endpointUrl).hostname; - _statsBeat.initialize(core, senderConfig.instrumentationKey, endpointHost, EnvelopeCreator.Version); + let statsBeatConfig = { + ikey: senderConfig.instrumentationKey, + endpoint: senderConfig.endpointUrl, + version: EnvelopeCreator.Version + } as IStatsBeatConfig; + // _statsBeat.initialize(core, statsBeatConfig); // uncomment this until throttle is implemented } if(isPromiseLike(senderConfig.instrumentationKey)) { diff --git a/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts index 487a3b940..aae077428 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts @@ -47,7 +47,11 @@ export class StatsBeatTests extends AITestClass { Assert.equal(false, this._statsbeat.isInitialized(), "StatsBeat should not be initialized by default"); // Initialize and test - this._statsbeat.initialize(this._core, "Test-iKey", "https://example.endpoint.com", "1.0.0"); + this._statsbeat.initialize(this._core, { + ikey: "Test-iKey", + endpoint: "https://example.endpoint.com", + version: "1.0.0" + }); Assert.equal(true, this._statsbeat.isInitialized(), "StatsBeat should be initialized after initialization"); } }); @@ -57,7 +61,11 @@ export class StatsBeatTests extends AITestClass { useFakeTimers: true, test: () => { // Initialize StatsBeat - this._statsbeat.initialize(this._core, "Test-iKey", "https://example.endpoint.com", "1.0.0"); + this._statsbeat.initialize(this._core, { + ikey: "Test-iKey", + endpoint: "https://example.endpoint.com", + version: "1.0.0" + }); // Create mock payload data with timing information const payloadData = { @@ -96,7 +104,11 @@ export class StatsBeatTests extends AITestClass { useFakeTimers: true, test: () => { // Initialize StatsBeat - this._statsbeat.initialize(this._core, "Test-iKey", "https://example.endpoint.com", "1.0.0"); + this._statsbeat.initialize(this._core, { + ikey: "Test-iKey", + endpoint: "https://example.endpoint.com", + version: "1.0.0" + }); // Count an exception this._statsbeat.countException("https://example.endpoint.com", "NetworkError"); @@ -128,7 +140,11 @@ export class StatsBeatTests extends AITestClass { name: "StatsBeat: does not send metrics for different endpoints", test: () => { // Initialize StatsBeat for a specific endpoint - this._statsbeat.initialize(this._core, "Test-iKey", "https://example.endpoint.com", "1.0.0"); + this._statsbeat.initialize(this._core, { + ikey: "Test-iKey", + endpoint: "https://example.endpoint.com", + version: "1.0.0" + }); // Create mock payload data const payloadData = { diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts index c3209aed1..5362576b1 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IStatsBeat.ts @@ -2,8 +2,14 @@ import { IAppInsightsCore } from "./IAppInsightsCore"; import { IPayloadData } from "./IXHROverride"; export interface IStatsBeat { - initialize(core: IAppInsightsCore, ikey: string, endpoint: string, version?: string) : void; + initialize(core: IAppInsightsCore, statsBeatConfig: IStatsBeatConfig) : void; isInitialized(): boolean; count(status: number, payloadData: IPayloadData, endpoint: string): void; countException(endpoint: string, exceptionType: string): void; } + +export interface IStatsBeatConfig { + ikey: string; + endpoint: string; + version?: string; +} diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 9211badbd..26d30d9b1 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -1,7 +1,7 @@ import dynamicProto from "@microsoft/dynamicproto-js"; import { ITimerHandler, scheduleTimeout, utcNow } from "@nevware21/ts-utils"; import { IAppInsightsCore } from "../JavaScriptSDK.Interfaces/IAppInsightsCore"; -import { IStatsBeat } from "../JavaScriptSDK.Interfaces/IStatsBeat"; +import { IStatsBeat, IStatsBeatConfig } from "../JavaScriptSDK.Interfaces/IStatsBeat"; import { ITelemetryItem } from "../JavaScriptSDK.Interfaces/ITelemetryItem"; import { IPayloadData } from "../JavaScriptSDK.Interfaces/IXHROverride"; import { NetworkStatsbeat, createNetworkStatsbeat } from "./NetworkStatsbeat"; @@ -24,12 +24,12 @@ export class Statsbeat implements IStatsBeat { let _os: string; let _runTimeVersion: string; dynamicProto(Statsbeat, this, (_self, _base) => { - _self.initialize = (core: IAppInsightsCore, ikey: string, endpoint: string, version?: string) => { + _self.initialize = (core: IAppInsightsCore, statsBeatConfig: IStatsBeatConfig) => { _core = core; - _networkCounter = createNetworkStatsbeat(endpoint); + _networkCounter = createNetworkStatsbeat(statsBeatConfig.endpoint); _isEnabled = true; - _sdkVersion = version; - _getCustomProperties(ikey); + _sdkVersion = statsBeatConfig.version; + _getCustomProperties(statsBeatConfig.ikey); } _self.isInitialized = (): boolean => { @@ -44,15 +44,15 @@ export class Statsbeat implements IStatsBeat { _networkCounter.totalRequest = (_networkCounter.totalRequest || 0) + 1; _networkCounter.requestDuration += utcNow() - payloadData["statsBeatData"]["startTime"]; } - let retryArray = [401, 403, 408, 429, 500, 502, 503]; + let retryArray = [401, 403, 408, 429, 500, 502, 503, 504]; let throttleArray = [402, 439]; - if (status === 200) { + if (status >= 200 && status < 300) { _networkCounter.success++; } else if (retryArray.indexOf(status) !== -1) { _networkCounter.retry[status] = (_networkCounter.retry[status] || 0) + 1; } else if (throttleArray.indexOf(status) !== -1) { _networkCounter.throttle[status] = (_networkCounter.throttle[status] || 0) + 1; - } else if (status !== 307 && status !== 308 && status !== 206) { + } else if (status !== 307 && status !== 308) { _networkCounter.failure[status] = (_networkCounter.failure[status] || 0) + 1; } _setupTimer(); @@ -93,7 +93,6 @@ export class Statsbeat implements IStatsBeat { _cikey = ikey; _language = STATSBEAT_LANGUAGE; _os = STATSBEAT_TYPE; - _runTimeVersion = STATSBEAT_TYPE; } function _sendStatsbeats(name: string, val: number, properties?: { [name: string]: any }) { @@ -105,7 +104,6 @@ export class Statsbeat implements IStatsBeat { "rp": "unknown", "attach": "Manual", "cikey": _cikey, - "runtimeVersion": _runTimeVersion, "os": _os, "language": _language, "version": _sdkVersion, @@ -179,7 +177,7 @@ export class Statsbeat implements IStatsBeat { }); } - public initialize(core: IAppInsightsCore, ikey: string, endpoint: string, version?: string) { + public initialize(core: IAppInsightsCore, statsBeatConfig: IStatsBeatConfig) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } diff --git a/shared/AppInsightsCore/src/applicationinsights-core-js.ts b/shared/AppInsightsCore/src/applicationinsights-core-js.ts index a26af9beb..6af27edca 100644 --- a/shared/AppInsightsCore/src/applicationinsights-core-js.ts +++ b/shared/AppInsightsCore/src/applicationinsights-core-js.ts @@ -37,7 +37,7 @@ export { IXDomainRequest, IBackendResponse } from "./JavaScriptSDK.Interfaces/IX export { _ISenderOnComplete, _ISendPostMgrConfig, _ITimeoutOverrideWrapper, _IInternalXhrOverride } from "./JavaScriptSDK.Interfaces/ISenderPostManager"; export { SenderPostManager } from "./JavaScriptSDK/SenderPostManager"; export { IStatsBeatEvent } from "./JavaScriptSDK.Interfaces/IStatsBeatEvent"; -export { IStatsBeat } from "./JavaScriptSDK.Interfaces/IStatsBeat"; +export { IStatsBeat, IStatsBeatConfig } from "./JavaScriptSDK.Interfaces/IStatsBeat"; export { isArray, isTypeof, isUndefined, isNullOrUndefined, objHasOwnProperty as hasOwnProperty, isObject, isFunction, strEndsWith, strStartsWith, isDate, isError, isString, isNumber, isBoolean, arrForEach, arrIndexOf, diff --git a/tools/chrome-debug-extension/manifest.json b/tools/chrome-debug-extension/manifest.json index 7ab3f42a4..9b234f5a8 100644 --- a/tools/chrome-debug-extension/manifest.json +++ b/tools/chrome-debug-extension/manifest.json @@ -2,8 +2,8 @@ "name": "Telemetry Viewer - M3", "short_name": "Telemetry Viewer M3", "description": "A browser extension that provides a real time view of what's happening in Application Insights including what telemetry is being logged by the web application", - "version": "0.7.6", - "version_name": "0.7.6", + "version": "0.7.5", + "version_name": "0.7.5", "manifest_version": 3, "icons": { "16": "images/icon-16.png", From 8f0cb34eddbfa33d8f8ed550f3e93748913d34eb Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 1 Apr 2025 13:19:30 -0700 Subject: [PATCH 29/62] remove duplicate --- .../Unit/src/applicationinsights.e2e.tests.ts | 2 +- .../src/Sender.ts | 25 +- common/config/rush/npm-shrinkwrap.json | 274 +++++++++--------- 3 files changed, 151 insertions(+), 150 deletions(-) diff --git a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts index e4448490e..19521e0b9 100644 --- a/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts +++ b/AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts @@ -153,7 +153,7 @@ export class ApplicationInsightsTests extends AITestClass { } public registerTests() { - this.addDynamicConfigTests() + this.addDynamicConfigTests(); this.addGenericE2ETests(); this.addAnalyticsApiTests(); this.addAsyncTests(); diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 52339ce6c..dab962973 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -7,12 +7,12 @@ import { import { ActiveStatus, BaseTelemetryPlugin, IAppInsightsCore, IBackendResponse, IChannelControls, IConfigDefaults, IConfiguration, IDiagnosticLogger, IInternalOfflineSupport, INotificationManager, IPayloadData, IPlugin, IProcessTelemetryContext, - IProcessTelemetryUnloadContext, IStatsBeat, IStatsBeatConfig, IStatsBeatEvent, ITelemetryItem, ITelemetryPluginChain, ITelemetryUnloadState, - IXDomainRequest, IXHROverride, OnCompleteCallback, SendPOSTFunction, SendRequestReason, SenderPostManager, TransportType, - _ISendPostMgrConfig, _ISenderOnComplete, _eInternalMessageId, _throwInternal, _warnToConsole, arrForEach, cfgDfBoolean, cfgDfValidate, - createProcessTelemetryContext, createUniqueNamespace, dateNow, dumpObj, eLoggingSeverity, formatErrorMessageXdr, formatErrorMessageXhr, - getExceptionName, getIEVersion, getResponseText, isArray, isBeaconsSupported, isFetchSupported, isNullOrUndefined, mergeEvtNamespace, - objExtend, onConfigChange, parseResponse, prependTransports, runTargetUnload + IProcessTelemetryUnloadContext, IStatsBeat, IStatsBeatConfig, IStatsBeatEvent, ITelemetryItem, ITelemetryPluginChain, + ITelemetryUnloadState, IXDomainRequest, IXHROverride, OnCompleteCallback, SendPOSTFunction, SendRequestReason, SenderPostManager, + TransportType, _ISendPostMgrConfig, _ISenderOnComplete, _eInternalMessageId, _throwInternal, _warnToConsole, arrForEach, cfgDfBoolean, + cfgDfValidate, createProcessTelemetryContext, createUniqueNamespace, dateNow, dumpObj, eLoggingSeverity, formatErrorMessageXdr, + formatErrorMessageXhr, getExceptionName, getIEVersion, getResponseText, isArray, isBeaconsSupported, isFetchSupported, isNullOrUndefined, + mergeEvtNamespace, objExtend, onConfigChange, parseResponse, prependTransports, runTargetUnload } from "@microsoft/applicationinsights-core-js"; import { IPromise } from "@nevware21/ts-async"; import { @@ -934,17 +934,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { return _self._sample.isSampledIn(envelope); } - function _getOnComplete(payload: IInternalStorageItem[], status: number, headers: {[headerName: string]: string;}, response?: string) { - - // *********************************************************************************************** - //TODO: handle other status codes - if (status === 200 && payload) { - _self._onSuccess(payload, payload.length); - } else { - response && _self._onError(payload, response); - } - } - function _doSend(sendInterface: IXHROverride, payload: IInternalStorageItem[], isAsync: boolean, markAsSent: boolean = true): void | IPromise { let onComplete = (status: number, headers: {[headerName: string]: string;}, response?: string) => { let statsbeat = _core.getStatsBeat(); @@ -952,7 +941,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; statsbeat.count(status, payloadData, endpointHost); } - return _getOnComplete(payload, status, headers, response); + return; } let payloadData = _getPayload(payload); if (payloadData) { diff --git a/common/config/rush/npm-shrinkwrap.json b/common/config/rush/npm-shrinkwrap.json index 31d234771..cfc338d59 100644 --- a/common/config/rush/npm-shrinkwrap.json +++ b/common/config/rush/npm-shrinkwrap.json @@ -236,9 +236,9 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.1.0.tgz", - "integrity": "sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", + "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -257,9 +257,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.0.tgz", - "integrity": "sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "peer": true, "dependencies": { "ajv": "^6.12.4", @@ -314,9 +314,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.22.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.22.0.tgz", - "integrity": "sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==", + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.23.0.tgz", + "integrity": "sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==", "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -332,18 +332,30 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz", - "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==", + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", + "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", "peer": true, "dependencies": { - "@eslint/core": "^0.12.0", + "@eslint/core": "^0.13.0", "levn": "^0.4.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", + "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -411,17 +423,17 @@ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" }, "node_modules/@microsoft/api-extractor": { - "version": "7.52.1", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.52.1.tgz", - "integrity": "sha512-m3I5uAwE05orsu3D1AGyisX5KxsgVXB+U4bWOOaX/Z7Ftp/2Cy41qsNhO6LPvSxHBaapyser5dVorF1t5M6tig==", + "version": "7.52.2", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.52.2.tgz", + "integrity": "sha512-RX37V5uhBBPUvrrcmIxuQ8TPsohvr6zxo7SsLPOzBYcH9nbjbvtdXrts4cxHCXGOin9JR5ar37qfxtCOuEBTHA==", "dependencies": { - "@microsoft/api-extractor-model": "7.30.4", + "@microsoft/api-extractor-model": "7.30.5", "@microsoft/tsdoc": "~0.15.1", "@microsoft/tsdoc-config": "~0.17.1", - "@rushstack/node-core-library": "5.12.0", + "@rushstack/node-core-library": "5.13.0", "@rushstack/rig-package": "0.5.3", - "@rushstack/terminal": "0.15.1", - "@rushstack/ts-command-line": "4.23.6", + "@rushstack/terminal": "0.15.2", + "@rushstack/ts-command-line": "4.23.7", "lodash": "~4.17.15", "minimatch": "~3.0.3", "resolve": "~1.22.1", @@ -434,13 +446,13 @@ } }, "node_modules/@microsoft/api-extractor-model": { - "version": "7.30.4", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.30.4.tgz", - "integrity": "sha512-RobC0gyVYsd2Fao9MTKOfTdBm41P/bCMUmzS5mQ7/MoAKEqy0FOBph3JOYdq4X4BsEnMEiSHc+0NUNmdzxCpjA==", + "version": "7.30.5", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.30.5.tgz", + "integrity": "sha512-0ic4rcbcDZHz833RaTZWTGu+NpNgrxVNjVaor0ZDUymfDFzjA/Uuk8hYziIUIOEOSTfmIQqyzVwlzxZxPe7tOA==", "dependencies": { "@microsoft/tsdoc": "~0.15.1", "@microsoft/tsdoc-config": "~0.17.1", - "@rushstack/node-core-library": "5.12.0" + "@rushstack/node-core-library": "5.13.0" } }, "node_modules/@microsoft/api-extractor/node_modules/typescript": { @@ -671,7 +683,7 @@ "node_modules/@rush-temp/1ds-core-js": { "version": "0.0.0", "resolved": "file:projects/1ds-core-js.tgz", - "integrity": "sha512-apLuWmv+yjEUMP5mpjXtNP/9KNnAmWRGcR5zpNE1IspJ4nkVA/Rrz4GsKAxRQ7Zwg22HnUISWc3Zb75rTcCUxA==", + "integrity": "sha512-S568Ikc8mwbKh+kXzGMJc3+ddM2zq8TTvGc/tDxv7K7laMpX7LuA8wYOo3YwvRcnys4LWzucUy00ir0DZGXIgA==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -700,7 +712,7 @@ "node_modules/@rush-temp/1ds-post-js": { "version": "0.0.0", "resolved": "file:projects/1ds-post-js.tgz", - "integrity": "sha512-ssnydCEmFp14fGC/lli2Tlot9+H7/HXy4RUXquWxqjKEyZRpjctumJ50qnnBL9eTnfPC7pTtpRXsIT/khmUlqA==", + "integrity": "sha512-6TjJhRfasCS9JwEIgK3deLCZF8sCJhofofeEHp8QpYGNJ+PeLfmM4z9/36s3ytiNVRtNyXMWQ7F1VcaiEtNWLg==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -723,7 +735,7 @@ "node_modules/@rush-temp/ai-test-framework": { "version": "0.0.0", "resolved": "file:projects/ai-test-framework.tgz", - "integrity": "sha512-TqE51+8piRhz4DjMLIY1AS/sarejEInB9Anec71OhVcTSnJ/hFajNVkDGpbrM1fkcS1ipUWL5NDa63I4hIrs1g==", + "integrity": "sha512-tnX3vftQBLYYxbAp39K86joXD95A0WxZ5dIhL4RHkVH/7DO3pwphhpKh6H7y+N1EgHyDeJjZQ012EhTRLjxt4A==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-ts-plugin": "^0.4.3", @@ -750,7 +762,7 @@ "node_modules/@rush-temp/applicationinsights-analytics-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-analytics-js.tgz", - "integrity": "sha512-a+7tuwPO4548C8YIkkTuzdOTrCVExgC0OEWlxaoQi8A8V4mpLmNIKqZ/A5zlsmrpy92JBjJKojW4GclDQCKPtw==", + "integrity": "sha512-VlzvYhv3aJJ6cRMoGqoQUyBPLNlyZDrQPi4Fcaa/oZlHPuUr/o4ul1sNP1gWVoFvJGpIw7CTRIoie1f7guquPQ==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -779,7 +791,7 @@ "node_modules/@rush-temp/applicationinsights-cfgsync-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-cfgsync-js.tgz", - "integrity": "sha512-Wg2KCxnGY3tZy0iadN3po2JgeMTVGpttdRhst9IqRwzkl10zdPoU7p/Ij4PYdt47BnEXCyxslgCqOoevWrzftA==", + "integrity": "sha512-KN+tyNwv1ZOI9zX8h2avQCKQ08WBEf44K0mU/zf8a8oTxuPHYDAteWfh4HSBZeWiXtsGIANfYylOsIu0y/nQYQ==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -809,7 +821,7 @@ "node_modules/@rush-temp/applicationinsights-channel-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-channel-js.tgz", - "integrity": "sha512-M07q5mg9sCV4aL4hDE6QXa8vYmpeEZKe57Gndn37MFYsDUsuyad2BdHQ7xvLR69RF6nValFPuP9GnlkrCCbYtg==", + "integrity": "sha512-Rgsyi0vQ8jWCCgx7wwRwcgn8qX3RtUsvF61xj4UmllDmka0n8aepMstmoGTYSjZD+0HhJ6icOnQDygOsKY8cwQ==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -837,7 +849,7 @@ "node_modules/@rush-temp/applicationinsights-chrome-debug-extension": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-chrome-debug-extension.tgz", - "integrity": "sha512-DQ4Cd99QfhSTZ72oSpg/+Pt28Op/hSDNq4tuCjH9VUNL79DqDYEBk8BExZjdf2rQgWDcIA0OtW8jt0vDEd+X7Q==", + "integrity": "sha512-FQvXuPosQmB6R7W9R1xUGxaDs6FZiIX8pKx04u2ks8ySqttktcE5cNt0mpRNvhdas7mhfwh4hkPrSw5Htl5GIQ==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -873,7 +885,7 @@ "node_modules/@rush-temp/applicationinsights-clickanalytics-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-clickanalytics-js.tgz", - "integrity": "sha512-ODDVcnd3e/Elzl8oDn+OV9sM7rvXMtRmd/FYZsjl9wZgLgPKBYAZmOQwNfk3muPQnLdKoK8kOAySy8KpCYmatw==", + "integrity": "sha512-MMWaGbWpcRqCQXWjTO79LwbOCFUCKTzXdReGZTMpQpfFtfgzdCvh7/zeBp6tz+FP+Ely4RtGspD3bnJ2v19iDg==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -899,7 +911,7 @@ "node_modules/@rush-temp/applicationinsights-common": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-common.tgz", - "integrity": "sha512-8AYe2KAygw9vCHelkeFhXYB6mTmghdmRjDCppqLS9T71z1UBCZM2rwrqyigE65d/I3tssM1YM/udW3DZQ3eJ2g==", + "integrity": "sha512-BEkeD4/QIm5UBlviSgMtA7r8jBW5kGzXxOlNJIO/CBotCsFvFXqVo9yMRPwP9PJQ+Hpz08HvsqhLFDnsFsNsww==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -926,7 +938,7 @@ "node_modules/@rush-temp/applicationinsights-core-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-core-js.tgz", - "integrity": "sha512-SrIFCEujUCzjvmkkDOnYee7H3FXRYBDG5wsAiDXWbrAokm43O3u3nU/sjv89N9MGKV3dRhTqzYWCpMiumey26Q==", + "integrity": "sha512-7S989coGnef/fK5+Y6BnXtiFpVLz6SJ6igNC4IZlVxnw8ii5DbqZvIZu6nXd/eGG3avwsGqqZh2+fdBWf36wrg==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -956,7 +968,7 @@ "node_modules/@rush-temp/applicationinsights-debugplugin-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-debugplugin-js.tgz", - "integrity": "sha512-2vrLuc0qsTfLrhrtzpnNGaSowayXeEnfAaBfr/oXRDJm4uIeu2q75fTwCjpLj3UAt2SxoPrQcTH7l1zj0ZtOGg==", + "integrity": "sha512-5RP04u0Yfyim8hJE/RaHt4uAFXNKNfwgM1vX8c+qfjMCBUlNSASxRSKQek3yB9fPYwCz4Y+Auz9BG72FHUJoyg==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -982,7 +994,7 @@ "node_modules/@rush-temp/applicationinsights-dependencies-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-dependencies-js.tgz", - "integrity": "sha512-FiGhevi/vN6+Y/kWzXwDK2bHeSRROPw/3tp1X0m0aTqcK78w4btr5C9y4W0zOTS0I6skMEcgfYyK9W1oObBXKg==", + "integrity": "sha512-k/xzf3VxNirpIs3ZAOjQ7bU3/EGBZVw0lYPodkGlVwjyTQbZeRSFmD2KbG5f67GqTlwP2FAYS58dMgnrBC0VQQ==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1011,7 +1023,7 @@ "node_modules/@rush-temp/applicationinsights-example-aisku": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-example-aisku.tgz", - "integrity": "sha512-TRKQhyAP2oRg+C8VEIiS+mCwY2w0f11xV2u8gMK5RG/xgibno3c5PaYvlonGAE4jyi68R/BfD3Sqc9NfPpj7zg==", + "integrity": "sha512-niU+OZNuZnZK7xneran0RMcb7JNty5mzp41pKg7WYzkz8FGxFoUyKTt6jAVsaK32waKr7MxD0EdkaTZ0xtB7/Q==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/ts-utils": ">= 0.11.8 < 2.x", @@ -1030,7 +1042,7 @@ "node_modules/@rush-temp/applicationinsights-example-cfgsync": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-example-cfgsync.tgz", - "integrity": "sha512-z0VJUclAhw9Ybncy4LSWJdgi/tvfdiNIhqurRfgSRY1AdIw05RJAECA/P6WsxrKdtKSzs23BYS0zWUa0uXVexQ==", + "integrity": "sha512-tJavCc9UL7In5l8jrgmFWu+x9kza63fg0F8o9IQDqlxpbqb9wEoHMgu/JG3fQn87E29Uo6xUZXWFmMnVZJ3cLA==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -1057,7 +1069,7 @@ "node_modules/@rush-temp/applicationinsights-example-dependencies": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-example-dependencies.tgz", - "integrity": "sha512-2oh3nLFqQpsVLU1wTY1nhvNGzsTOdE8cwzxhyKXAb7/7x9HBIVi37f+h8GibL6s5svH44m5u/yS5CKjb3MNdYg==", + "integrity": "sha512-DNHJM7jDSsuPRDW4d46lkK9O/tLbBKzrp39g2Hnng6ak16UtQghMiFMxqrrPZwcx5MIT8WTN67/5dd8LDcln/Q==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/ts-utils": ">= 0.11.8 < 2.x", @@ -1076,7 +1088,7 @@ "node_modules/@rush-temp/applicationinsights-example-shared-worker": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-example-shared-worker.tgz", - "integrity": "sha512-JOhewF0omr64DyI/0u4UbmXW125GXMqY4kyxuLQgWQDpGlf5Tlc9vy823+YbcoDTjc8p1mj/gZ0aW8E0F81PUA==", + "integrity": "sha512-FGgqa6DjwP5E4D+fNltmaq3JB/D9I/eI/MyRPMnJQ6UDF1cnq7n54skGIC3QgVnHAfCGhYe8+cca9LJooDnScQ==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -1103,7 +1115,7 @@ "node_modules/@rush-temp/applicationinsights-js-release-tools": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-js-release-tools.tgz", - "integrity": "sha512-6sVB5NMzKj/P9v9UvZlA/IjQSkGeupaDliSt2IZqy+SlR59Hv335Ekz/5f54xMHu+QiARXJATbjX7lDfCMG8qw==", + "integrity": "sha512-e9jw61D/jeRuLlSL+dQ2bFp8iqw6Q9ZMeboqX0CX0iYwjAPRiN/59ZK66D0UOgggNkqYgSEqgDi+ycw9XRtGnA==", "dependencies": { "globby": "^11.0.0", "grunt": "^1.5.3" @@ -1112,7 +1124,7 @@ "node_modules/@rush-temp/applicationinsights-offlinechannel-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-offlinechannel-js.tgz", - "integrity": "sha512-FXcwTCrBzkFhbdl2MRl/ddAsISIIbjc7C2Os4q/81yAeTBf34oMSREkz3G/6rwgX5CHdGlsLxYoGZOr9N01O5w==", + "integrity": "sha512-Fo2BA9ndAzApO+keiT43xRtpd/ZZU6MrQvFOdElynZBCgAjtsIy06EG+JlkrO5WkXe/DQFXo7uoDfr7ev93K9Q==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1140,7 +1152,7 @@ "node_modules/@rush-temp/applicationinsights-osplugin-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-osplugin-js.tgz", - "integrity": "sha512-6t2U5fyBIZKTJbaBtTg/Npd7aqwqSSjhwPExQEDFB1QSe98g8M7U07q49S4o4j+w3jqrhVwrwLmFN5cDvQtuIw==", + "integrity": "sha512-GI+lfOwoDdEJZg8C84FbkEO1H8dAtu8zhrRO3ELUHHvyWDBlJ00m/GZ15f0GpiWIKLM1aGfvS3boJbeGXwsfwA==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1163,7 +1175,7 @@ "node_modules/@rush-temp/applicationinsights-perfmarkmeasure-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-perfmarkmeasure-js.tgz", - "integrity": "sha512-XQ0gCQt7Vxl3gn6Ux7Uq7rBh8l5/4XZPftXcAXKwkmPRMGDZObbjHfdCKys+0/bP2gQ09WifydjE5gXRQIQncQ==", + "integrity": "sha512-UTKXee9IjxWV+/ndjIzGotNe1dprLJ6HoyOS8aTh+UwmkewwXYklFhC7RJ2DLaTj/4/EtJcTn9Jd9B1BMKqHCg==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1189,7 +1201,7 @@ "node_modules/@rush-temp/applicationinsights-properties-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-properties-js.tgz", - "integrity": "sha512-WNUzBixreiuaz8SdkXjd/C1xqtYEKAPPYovYPpmGIMb+Doxpzv6+fAwnLcGXNSlyLPBcRl6lvKGnr1mUw/TwIg==", + "integrity": "sha512-A1DteE1sHRnuHUYpta6aaQlgcuoWZJt8Xf5elql3PqMAT5F10IWBetxuLZknOTjdBzlVEVrFWLjeMji+U6vaSw==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1218,7 +1230,7 @@ "node_modules/@rush-temp/applicationinsights-rollup-es5": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-rollup-es5.tgz", - "integrity": "sha512-2KGwNRdd1Cj+HU+eymk4Vr9tCoCCiWAThd2nLi+DXCXRhgQgUFzygIDQTtbsFdQMpihK3xm+9Te22Som95XUow==", + "integrity": "sha512-S5O9XK+Ezf+o4yg4ol6L8eDt13ZgbxN7zMxZ7mgyMn/kAw9KSASKM0AttiQ/+TlA6oVsyy60qxYYtxwtRNe1Hw==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -1243,7 +1255,7 @@ "node_modules/@rush-temp/applicationinsights-rollup-plugin-uglify3-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-rollup-plugin-uglify3-js.tgz", - "integrity": "sha512-jsh6Gf9Tf6RvCtdm8knaz6AkOo0cfinBcJY5xKQDMKTbd/rtrdjpZlrnjUCgu37/Tf2mPU729wW2bX5f4qESqA==", + "integrity": "sha512-UlrHcg9syNUHkxSrHAA4R5rXZBF7UIZA6yTsEzpeAdq8IDaWPqqNixuNtuRuWFNDUCZoZ1IrLJvOBsLjdCu7mQ==", "dependencies": { "@nevware21/grunt-eslint-ts": "^0.2.2", "@nevware21/grunt-ts-plugin": "^0.4.3", @@ -1264,7 +1276,7 @@ "node_modules/@rush-temp/applicationinsights-shims": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-shims.tgz", - "integrity": "sha512-78cuigGVsHDC+lYMYDG9ZwRaqwyWjiIOP/YOEuAfgOd+k9PgVzpiF5Ex7mCEJjs/SCylqaVpc4VRm1+Rf4psIw==", + "integrity": "sha512-tfOkC4pH6vVoEyr60aHs/DfjXCLx5FS/xBBBgNHhxNZI7qRP7XzT7T14zZfnN8emQSRNo9i2QQ6lotPKXWw7Lw==", "dependencies": { "@microsoft/dynamicproto-js": "^2.0.3", "@nevware21/grunt-eslint-ts": "^0.2.2", @@ -1287,7 +1299,7 @@ "node_modules/@rush-temp/applicationinsights-teechannel-js": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-teechannel-js.tgz", - "integrity": "sha512-ef9n8waBRzdPD7bnlCKDiJRhSMd0HifhAiM5QwGY4D/yN4bJmqwojfPIqB12SvZG79muL2+BAGezaOzS8kXjEg==", + "integrity": "sha512-4YIz6YFExC07EfQjIwjH5b+EBYWH8e6mYjBRlksrnB/fnSCOJtPhGiHm2mH/HHZbwHBz+qGh15+K6yuUh3Q05w==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1315,7 +1327,7 @@ "node_modules/@rush-temp/applicationinsights-test-module-type-check": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-test-module-type-check.tgz", - "integrity": "sha512-lqgC93TZ4TmUr3DhckDalb1eMZyODclD58JrmnARRwjhdMCe7svk0oR0T8i0jzrH2f+fAkflMU+7bOZYlUtZ/g==", + "integrity": "sha512-J+t6FArFCQBHl8Cym4B7qUV/VioxLTVxTk3sZ+gbMkcxARQ3LdUKiDk0QYbxJwPFTeLbdwmVOBy5Any58i4Wbw==", "dependencies": { "tslib": ">= 1.0.0", "typescript": "^4.9.3" @@ -1324,7 +1336,7 @@ "node_modules/@rush-temp/applicationinsights-web": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-web.tgz", - "integrity": "sha512-F8CHRyJFzAleotnnMr8g/4UL1MoZmNHVr3WORvizh0rHsXRjO4kkGx6ofD5i/1umlFrlYZEkApaeULxBMRzBMw==", + "integrity": "sha512-dA3ZNHJCTvOgGSgJFPj+jjsKR+D1BtxGl97D31Ls35vCox2CVff8gxUBRSLmT97p2gk78wo/11Play6sWlBdEQ==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1357,7 +1369,7 @@ "node_modules/@rush-temp/applicationinsights-web-basic": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-web-basic.tgz", - "integrity": "sha512-m9vF95kYH38PxYrOTSkzYu/az7RoUIVod91KVMPzBARwulnKBzqvzABNfJiO3dmnlIRHr0A6eO8775jJwQWGqw==", + "integrity": "sha512-UouzLYljf5hLoXdmck4c0HXm/qJJV19pzFfWTLZVO9G+RDhDSRTuO0/1XgWoetx9O8bWWxreUIz+Ruyv05/eHQ==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1385,12 +1397,12 @@ "node_modules/@rush-temp/applicationinsights-web-config": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-web-config.tgz", - "integrity": "sha512-WwlTM/noixyLMqKFBLKa9o88N/2Z3dA9m0R6Qc9UvBNseZqPIpvl1vRMDnmwjMMV6lV3FsmeSmjD7LCJphXF2Q==" + "integrity": "sha512-FwPOZ+esirRqdKg9s7VTxtWqGJ9CQ/gIJ0PfUvTolAF9JZCVw5wQeHD4Tv/KiziZhB50CNaGshnPmLpWGVzo9g==" }, "node_modules/@rush-temp/applicationinsights-web-snippet": { "version": "0.0.0", "resolved": "file:projects/applicationinsights-web-snippet.tgz", - "integrity": "sha512-ySVDDbaBEIZYIKYKVpyWmVZcfCuYgqnGGlULpU3EnUvAI1L8VkvbxoOx6H+J4Nf+XO+/DbcmLW6i0kFTqVlLSg==", + "integrity": "sha512-XXGxNMapO2ZIzThyO9d4KqnddgY1yU7ojb2xsggVoJgiCH1DxAIRcL9QSG7wxfaQjfoXWuYH7Ighj2DjqA1N3Q==", "dependencies": { "@microsoft/api-extractor": "^7.40.0", "@microsoft/dynamicproto-js": "^2.0.3", @@ -1413,9 +1425,9 @@ } }, "node_modules/@rushstack/node-core-library": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.12.0.tgz", - "integrity": "sha512-QSwwzgzWoil1SCQse+yCHwlhRxNv2dX9siPnAb9zR/UmMhac4mjMrlMZpk64BlCeOFi1kJKgXRkihSwRMbboAQ==", + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.13.0.tgz", + "integrity": "sha512-IGVhy+JgUacAdCGXKUrRhwHMTzqhWwZUI+qEPcdzsb80heOw0QPbhhoVsoiMF7Klp8eYsp7hzpScMXmOa3Uhfg==", "dependencies": { "ajv": "~8.13.0", "ajv-draft-04": "~1.0.0", @@ -1460,11 +1472,11 @@ } }, "node_modules/@rushstack/terminal": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.15.1.tgz", - "integrity": "sha512-3vgJYwumcjoDOXU3IxZfd616lqOdmr8Ezj4OWgJZfhmiBK4Nh7eWcv8sU8N/HdzXcuHDXCRGn/6O2Q75QvaZMA==", + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.15.2.tgz", + "integrity": "sha512-7Hmc0ysK5077R/IkLS9hYu0QuNafm+TbZbtYVzCMbeOdMjaRboLKrhryjwZSRJGJzu+TV1ON7qZHeqf58XfLpA==", "dependencies": { - "@rushstack/node-core-library": "5.12.0", + "@rushstack/node-core-library": "5.13.0", "supports-color": "~8.1.1" }, "peerDependencies": { @@ -1477,11 +1489,11 @@ } }, "node_modules/@rushstack/ts-command-line": { - "version": "4.23.6", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.23.6.tgz", - "integrity": "sha512-7WepygaF3YPEoToh4MAL/mmHkiIImQq3/uAkQX46kVoKTNOOlCtFGyNnze6OYuWw2o9rxsyrHVfIBKxq/am2RA==", + "version": "4.23.7", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.23.7.tgz", + "integrity": "sha512-Gr9cB7DGe6uz5vq2wdr89WbVDKz0UeuFEn5H2CfWDe7JvjFFaiV15gi6mqDBTbHhHCWS7w8mF1h3BnIfUndqdA==", "dependencies": { - "@rushstack/terminal": "0.15.1", + "@rushstack/terminal": "0.15.2", "@types/argparse": "1.0.38", "argparse": "~1.0.9", "string-argv": "~0.3.1" @@ -1629,9 +1641,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==" }, "node_modules/@types/file-saver": { "version": "2.0.7", @@ -1739,9 +1751,9 @@ "integrity": "sha512-II+C1wgzUia0g+tGAH+PBb4XiTm8/C/i6sN23r21NNskBYOYrv+qnW0tFQ/IxZzKVwrK4CTglf8YO3poJUclQA==" }, "node_modules/@types/react": { - "version": "16.14.62", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.62.tgz", - "integrity": "sha512-BWf7hqninZav6nerxXj+NeZT/mTpDeG6Lk2zREHAy63CrnXoOGPGtNqTFYFN/sqpSaREDP5otVV88axIXmKfGA==", + "version": "16.14.63", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.63.tgz", + "integrity": "sha512-s83gano0fRBVEw3ejdLpjgvU83F0LIeeuXqdxfPZF/Sc2bhr60tEqCK1zZ+aLirBwRSD6V5zCtOsEjcwKow3JQ==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "^0.16", @@ -1794,16 +1806,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.26.1.tgz", - "integrity": "sha512-2X3mwqsj9Bd3Ciz508ZUtoQQYpOhU/kWoUqIf49H8Z0+Vbh6UF/y0OEYp0Q0axOGzaBGs7QxRwq0knSQ8khQNA==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.29.0.tgz", + "integrity": "sha512-PAIpk/U7NIS6H7TEtN45SPGLQaHNgB7wSjsQV/8+KYokAb2T/gloOA/Bee2yd4/yKVhPKe5LlaUGhAZk5zmSaQ==", "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.26.1", - "@typescript-eslint/type-utils": "8.26.1", - "@typescript-eslint/utils": "8.26.1", - "@typescript-eslint/visitor-keys": "8.26.1", + "@typescript-eslint/scope-manager": "8.29.0", + "@typescript-eslint/type-utils": "8.29.0", + "@typescript-eslint/utils": "8.29.0", + "@typescript-eslint/visitor-keys": "8.29.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1823,15 +1835,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.26.1.tgz", - "integrity": "sha512-w6HZUV4NWxqd8BdeFf81t07d7/YV9s7TCWrQQbG5uhuvGUAW+fq1usZ1Hmz9UPNLniFnD8GLSsDpjP0hm1S4lQ==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.29.0.tgz", + "integrity": "sha512-8C0+jlNJOwQso2GapCVWWfW/rzaq7Lbme+vGUFKE31djwNncIpgXD7Cd4weEsDdkoZDjH0lwwr3QDQFuyrMg9g==", "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.26.1", - "@typescript-eslint/types": "8.26.1", - "@typescript-eslint/typescript-estree": "8.26.1", - "@typescript-eslint/visitor-keys": "8.26.1", + "@typescript-eslint/scope-manager": "8.29.0", + "@typescript-eslint/types": "8.29.0", + "@typescript-eslint/typescript-estree": "8.29.0", + "@typescript-eslint/visitor-keys": "8.29.0", "debug": "^4.3.4" }, "engines": { @@ -1847,13 +1859,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.26.1.tgz", - "integrity": "sha512-6EIvbE5cNER8sqBu6V7+KeMZIC1664d2Yjt+B9EWUXrsyWpxx4lEZrmvxgSKRC6gX+efDL/UY9OpPZ267io3mg==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.29.0.tgz", + "integrity": "sha512-aO1PVsq7Gm+tcghabUpzEnVSFMCU4/nYIgC2GOatJcllvWfnhrgW0ZEbnTxm36QsikmCN1K/6ZgM7fok2I7xNw==", "peer": true, "dependencies": { - "@typescript-eslint/types": "8.26.1", - "@typescript-eslint/visitor-keys": "8.26.1" + "@typescript-eslint/types": "8.29.0", + "@typescript-eslint/visitor-keys": "8.29.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1864,13 +1876,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.26.1.tgz", - "integrity": "sha512-Kcj/TagJLwoY/5w9JGEFV0dclQdyqw9+VMndxOJKtoFSjfZhLXhYjzsQEeyza03rwHx2vFEGvrJWJBXKleRvZg==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.29.0.tgz", + "integrity": "sha512-ahaWQ42JAOx+NKEf5++WC/ua17q5l+j1GFrbbpVKzFL/tKVc0aYY8rVSYUpUvt2hUP1YBr7mwXzx+E/DfUWI9Q==", "peer": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.26.1", - "@typescript-eslint/utils": "8.26.1", + "@typescript-eslint/typescript-estree": "8.29.0", + "@typescript-eslint/utils": "8.29.0", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, @@ -1887,9 +1899,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.26.1.tgz", - "integrity": "sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.29.0.tgz", + "integrity": "sha512-wcJL/+cOXV+RE3gjCyl/V2G877+2faqvlgtso/ZRbTCnZazh0gXhe+7gbAnfubzN2bNsBtZjDvlh7ero8uIbzg==", "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1900,13 +1912,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.26.1.tgz", - "integrity": "sha512-yUwPpUHDgdrv1QJ7YQal3cMVBGWfnuCdKbXw1yyjArax3353rEJP1ZA+4F8nOlQ3RfS2hUN/wze3nlY+ZOhvoA==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.29.0.tgz", + "integrity": "sha512-yOfen3jE9ISZR/hHpU/bmNvTtBW1NjRbkSFdZOksL1N+ybPEE7UVGMwqvS6CP022Rp00Sb0tdiIkhSCe6NI8ow==", "peer": true, "dependencies": { - "@typescript-eslint/types": "8.26.1", - "@typescript-eslint/visitor-keys": "8.26.1", + "@typescript-eslint/types": "8.29.0", + "@typescript-eslint/visitor-keys": "8.29.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -1962,15 +1974,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.26.1.tgz", - "integrity": "sha512-V4Urxa/XtSUroUrnI7q6yUTD3hDtfJ2jzVfeT3VK0ciizfK2q/zGC0iDh1lFMUZR8cImRrep6/q0xd/1ZGPQpg==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.29.0.tgz", + "integrity": "sha512-gX/A0Mz9Bskm8avSWFcK0gP7cZpbY4AIo6B0hWYFCaIsz750oaiWR4Jr2CI+PQhfW1CpcQr9OlfPS+kMFegjXA==", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.26.1", - "@typescript-eslint/types": "8.26.1", - "@typescript-eslint/typescript-estree": "8.26.1" + "@typescript-eslint/scope-manager": "8.29.0", + "@typescript-eslint/types": "8.29.0", + "@typescript-eslint/typescript-estree": "8.29.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1985,12 +1997,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.26.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.26.1.tgz", - "integrity": "sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.29.0.tgz", + "integrity": "sha512-Sne/pVz8ryR03NFK21VpN88dZ2FdQXOlq3VIklbrTYEt8yXtRFr9tvUhqvCeKjqYk5FSim37sHbooT6vzBTZcg==", "peer": true, "dependencies": { - "@typescript-eslint/types": "8.26.1", + "@typescript-eslint/types": "8.29.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -2459,9 +2471,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001705", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001705.tgz", - "integrity": "sha512-S0uyMMiYvA7CxNgomYBwwwPUnWzFD83f3B1ce5jHUfHTH//QL6hHsreI8RVC5606R4ssqravelYO5TU6t8sEyg==", + "version": "1.0.30001707", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001707.tgz", + "integrity": "sha512-3qtRjw/HQSMlDWf+X79N206fepf4SOOU6SQLMaq/0KkZLmSjPxAkBOQQ+FxbHKfHmYLZFfdWsO3KA90ceHPSnw==", "funding": [ { "type": "opencollective", @@ -2907,9 +2919,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.5.120", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.120.tgz", - "integrity": "sha512-oTUp3gfX1gZI+xfD2djr2rzQdHCwHzPQrrK0CD7WpTdF0nPdQ/INcRVjWgLdCT4a9W3jFObR9DAfsuyFQnI8CQ==" + "version": "1.5.129", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.129.tgz", + "integrity": "sha512-JlXUemX4s0+9f8mLqib/bHH8gOHf5elKS6KeWG3sk3xozb/JTq/RLXIv8OKUWiK4Ah00Wm88EFj5PYkFr4RUPA==" }, "node_modules/emoji-regex-xs": { "version": "1.0.0", @@ -2977,18 +2989,18 @@ } }, "node_modules/eslint": { - "version": "9.22.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.22.0.tgz", - "integrity": "sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==", + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.23.0.tgz", + "integrity": "sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==", "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.19.2", - "@eslint/config-helpers": "^0.1.0", + "@eslint/config-helpers": "^0.2.0", "@eslint/core": "^0.12.0", - "@eslint/eslintrc": "^3.3.0", - "@eslint/js": "9.22.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.23.0", "@eslint/plugin-kit": "^0.2.7", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -6570,9 +6582,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", - "integrity": "sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", "peer": true, "engines": { "node": ">=18.12" @@ -6663,9 +6675,9 @@ } }, "node_modules/typedoc/node_modules/yaml": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", - "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", + "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", "bin": { "yaml": "bin.mjs" }, From 4bf7c056dba0fb3dcbf775c41bb26fd87249f4bf Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Wed, 2 Apr 2025 14:37:10 -0700 Subject: [PATCH 30/62] refactor config --- .../Tests/Unit/src/StatsBeat.tests.ts | 24 +++++++++-------- .../src/SendBuffer.ts | 2 +- .../src/Sender.ts | 10 ++++--- .../Tests/Unit/src/StatsBeat.Tests.ts | 27 ++++++++++--------- .../IConfiguration.ts | 20 +++++++++++++- .../src/JavaScriptSDK/AppInsightsCore.ts | 8 ++++-- 6 files changed, 60 insertions(+), 31 deletions(-) diff --git a/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts b/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts index c126dd55b..bab11742f 100644 --- a/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts +++ b/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts @@ -19,15 +19,14 @@ export class StatsbeatTests extends AITestClass { } this._sender = null; this._core = null; - } public registerTests() { this.testCase({ - name: "Statsbeat initializes when disableStatsBeat is false", + name: "Statsbeat initializes when intStats is true", test: () => { let config = { - disableStatsBeat: false, + _sdk: {intStats: true}, instrumentationKey: "Test-iKey" }; @@ -44,11 +43,11 @@ export class StatsbeatTests extends AITestClass { }); this.testCase({ - name: "Statsbeat dynamically updates when disableStatsBeat changes", + name: "Statsbeat dynamically updates when intStats changes", useFakeTimers: true, test: () => { let config = { - disableStatsBeat: true, + _sdk: {intStats: false}, instrumentationKey: "Test-iKey" }; @@ -57,18 +56,21 @@ export class StatsbeatTests extends AITestClass { // Initially, Statsbeat should be null let statsbeat = this._core.getStatsBeat(); - QUnit.assert.ok(!statsbeat, "Statsbeat is null when disableStatsBeat is true"); + QUnit.assert.ok(!statsbeat, "Statsbeat is null when _sdk.intStats is false"); - // Dynamically enable Statsbeat - this._core.config.disableStatsBeat = false; + // Dynamically enable Statsbeat using _sdk.intStats + if (!this._core.config._sdk) { + this._core.config._sdk = {}; + } + this._core.config._sdk.intStats = true; this.clock.tick(1); // Simulate time passing for dynamic config update statsbeat = this._core.getStatsBeat(); - QUnit.assert.ok(statsbeat, "Statsbeat is initialized after enabling disableStatsBeat"); - QUnit.assert.ok(statsbeat.isInitialized(), "Statsbeat is marked as initialized after enabling disableStatsBeat"); + QUnit.assert.ok(statsbeat, "Statsbeat is initialized after enabling _sdk.intStats"); + QUnit.assert.ok(statsbeat.isInitialized(), "Statsbeat is marked as initialized after enabling _sdk.intStats"); // Dynamically disable Statsbeat again - this._core.config.disableStatsBeat = true; + this._core.config._sdk.intStats = false; this.clock.tick(1); // Simulate time passing for dynamic config update statsbeat = this._core.getStatsBeat(); diff --git a/channels/applicationinsights-channel-js/src/SendBuffer.ts b/channels/applicationinsights-channel-js/src/SendBuffer.ts index 1be79d7ac..239425269 100644 --- a/channels/applicationinsights-channel-js/src/SendBuffer.ts +++ b/channels/applicationinsights-channel-js/src/SendBuffer.ts @@ -103,7 +103,7 @@ abstract class BaseSendBuffer { if (!isNullOrUndefined(_maxRetryCnt)) { if (payload.cnt > _maxRetryCnt) { // TODO: add log here on dropping payloads - // should log exception here + // will log statsbeat exception later here return; } diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index dab962973..fffb49b60 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -288,14 +288,16 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } } - if (config.disableStatsBeat === false && _statsBeat && !_statsBeat.isInitialized()) { - var endpointHost = urlParseUrl(senderConfig.endpointUrl).hostname; + + console.log("do we have statsbeat?", _statsBeat) + if (config._sdk && config._sdk.intStats === true && _statsBeat && !_statsBeat.isInitialized()) { + console.log("yes") let statsBeatConfig = { ikey: senderConfig.instrumentationKey, - endpoint: senderConfig.endpointUrl, + endpoint: urlParseUrl(senderConfig.endpointUrl).hostname, version: EnvelopeCreator.Version } as IStatsBeatConfig; - // _statsBeat.initialize(core, statsBeatConfig); // uncomment this until throttle is implemented + _statsBeat.initialize(core, statsBeatConfig); } if(isPromiseLike(senderConfig.instrumentationKey)) { diff --git a/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts index aae077428..166c63ab5 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts @@ -9,7 +9,7 @@ export class StatsBeatTests extends AITestClass { private _core: AppInsightsCore; private _config: IConfiguration; private _statsbeat: Statsbeat; - private _trackSpy: sinon.SinonSpy; // Fix: Properly type the spy + private _trackSpy: sinon.SinonSpy; constructor(emulateIe: boolean) { super("StatsBeatTests", emulateIe); @@ -22,7 +22,9 @@ export class StatsBeatTests extends AITestClass { _self._config = { instrumentationKey: "Test-iKey", disableInstrumentationKeyValidation: true, - disableStatsBeat: false + _sdk: { + intStats: true // Enable statsbeat by default + } }; _self._core = new AppInsightsCore(); @@ -72,8 +74,8 @@ export class StatsBeatTests extends AITestClass { urlString: "https://example.endpoint.com", data: "testData", headers: {}, - timeout: 0, // Fix: Add required properties - disableXhrSync: false, // Fix: Add required properties + timeout: 0, + disableXhrSync: false, statsBeatData: { startTime: "2023-10-01T00:00:00Z" // Simulated start time } @@ -114,7 +116,7 @@ export class StatsBeatTests extends AITestClass { this._statsbeat.countException("https://example.endpoint.com", "NetworkError"); // Verify that trackStatsbeats is called when the timer fires - this.clock.tick(900000 + 1); // STATS_COLLECTION_SHORT_INTERVAL + 1ms + this.clock.tick(STATS_COLLECTION_SHORT_INTERVAL + 1); // Verify that track was called Assert.ok(this._trackSpy.called, "track should be called when statsbeat timer fires"); @@ -151,8 +153,8 @@ export class StatsBeatTests extends AITestClass { urlString: "https://example.endpoint.com", data: "testData", headers: {}, - timeout: 0, // Fix: Add required properties - disableXhrSync: false, // Fix: Add required properties + timeout: 0, + disableXhrSync: false, statsBeatData: { startTime: Date.now() } @@ -182,7 +184,10 @@ export class StatsBeatTests extends AITestClass { Assert.ok(statsbeat, "Statsbeat should be created"); // Update configuration to disable statsbeat - this._core.config.disableStatsBeat = true; +if (!this._core.config._sdk) { + this._core.config._sdk = {}; + } + this._core.config._sdk.intStats = false; this.clock.tick(1); // Allow time for config changes to propagate // Verify that statsbeat is removed @@ -190,7 +195,7 @@ export class StatsBeatTests extends AITestClass { Assert.ok(!updatedStatsbeat, "Statsbeat should be removed when disabled"); // Re-enable statsbeat - this._core.config.disableStatsBeat = false; + this._core.config._sdk.intStats = true; this.clock.tick(1); // Allow time for config changes to propagate // Verify that statsbeat is created again @@ -202,19 +207,18 @@ export class StatsBeatTests extends AITestClass { } class ChannelPlugin implements IPlugin { - public isFlushInvoked = false; public isTearDownInvoked = false; public isResumeInvoked = false; public isPauseInvoked = false; public identifier = "Sender"; - public priority: number = 1001; constructor() { this.processTelemetry = this._processTelemetry.bind(this); } + public pause(): void { this.isPauseInvoked = true; } @@ -244,7 +248,6 @@ class ChannelPlugin implements IPlugin { } private _processTelemetry(env: ITelemetryItem) { - } } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IConfiguration.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IConfiguration.ts index 99f4eb946..5b5712cf4 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IConfiguration.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IConfiguration.ts @@ -211,5 +211,23 @@ export interface IConfiguration { * @since 3.3.2 */ expCfg?: IExceptionConfig; - disableStatsBeat?: boolean; + + + /** + * [Optional] Internal SDK configuration for developers + * @internal + */ + _sdk?: IInternalSdkConfiguration; } + +/** + * Internal SDK configuration options + * @internal + */ +export interface IInternalSdkConfiguration { + /** + * [Optional] Enable Internal StatsBeat + * @internal + */ + intStats?: boolean; +} \ No newline at end of file diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index a5323a955..d8e5b96bc 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -78,7 +78,8 @@ const defaultConfig: IConfigDefaults = objDeepFreeze({ [STR_EXTENSION_CONFIG]: { ref: true, v: {} }, [STR_CREATE_PERF_MGR]: UNDEFINED_VALUE, loggingLevelConsole: eLoggingSeverity.DISABLED, - diagnosticLogInterval: UNDEFINED_VALUE + diagnosticLogInterval: UNDEFINED_VALUE, + _sdk: {intStats:false} }); /** @@ -360,11 +361,14 @@ export class AppInsightsCore im } _initInMemoMaxSize = rootCfg.initInMemoMaxSize || maxInitQueueSize; - if (config.disableStatsBeat === false){ + + // uncomment this until throttle is implemented + if (config._sdk.intStats === true){ _statsBeat = _statsBeat || new Statsbeat(); } else { _statsBeat = null; } + // app Insights core only handle ikey and endpointurl, aisku will handle cs let ikey = rootCfg.instrumentationKey; let endpointUrl = rootCfg.endpointUrl; // do not need to validate endpoint url, if it is null, default one will be set by sender From bfd5178d73e70106c35880d6ea37cbeb373502a4 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Wed, 2 Apr 2025 15:25:39 -0700 Subject: [PATCH 31/62] Update Sender.ts --- .../applicationinsights-channel-js/src/Sender.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index fffb49b60..caf716ab5 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -289,9 +289,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } - console.log("do we have statsbeat?", _statsBeat) if (config._sdk && config._sdk.intStats === true && _statsBeat && !_statsBeat.isInitialized()) { - console.log("yes") let statsBeatConfig = { ikey: senderConfig.instrumentationKey, endpoint: urlParseUrl(senderConfig.endpointUrl).hostname, @@ -936,6 +934,17 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { return _self._sample.isSampledIn(envelope); } + function _getOnComplete(payload: IInternalStorageItem[], status: number, headers: {[headerName: string]: string;}, response?: string) { + + // *********************************************************************************************** + //TODO: handle other status codes + if (status === 200 && payload) { + _self._onSuccess(payload, payload.length); + } else { + response && _self._onError(payload, response); + } + } + function _doSend(sendInterface: IXHROverride, payload: IInternalStorageItem[], isAsync: boolean, markAsSent: boolean = true): void | IPromise { let onComplete = (status: number, headers: {[headerName: string]: string;}, response?: string) => { let statsbeat = _core.getStatsBeat(); @@ -943,7 +952,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; statsbeat.count(status, payloadData, endpointHost); } - return; + return _getOnComplete(payload, status, headers, response); } let payloadData = _getPayload(payload); if (payloadData) { From 1d7fe05efdb0cfb57890dda986c957481e231305 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Wed, 2 Apr 2025 15:33:45 -0700 Subject: [PATCH 32/62] Update Sender.ts --- .../applicationinsights-channel-js/src/Sender.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index fffb49b60..793c19537 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -288,10 +288,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } } - - console.log("do we have statsbeat?", _statsBeat) if (config._sdk && config._sdk.intStats === true && _statsBeat && !_statsBeat.isInitialized()) { - console.log("yes") let statsBeatConfig = { ikey: senderConfig.instrumentationKey, endpoint: urlParseUrl(senderConfig.endpointUrl).hostname, @@ -936,6 +933,17 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { return _self._sample.isSampledIn(envelope); } + function _getOnComplete(payload: IInternalStorageItem[], status: number, headers: {[headerName: string]: string;}, response?: string) { + + // *********************************************************************************************** + //TODO: handle other status codes + if (status === 200 && payload) { + _self._onSuccess(payload, payload.length); + } else { + response && _self._onError(payload, response); + } + } + function _doSend(sendInterface: IXHROverride, payload: IInternalStorageItem[], isAsync: boolean, markAsSent: boolean = true): void | IPromise { let onComplete = (status: number, headers: {[headerName: string]: string;}, response?: string) => { let statsbeat = _core.getStatsBeat(); @@ -943,7 +951,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; statsbeat.count(status, payloadData, endpointHost); } - return; + return _getOnComplete(payload, status, headers, response); } let payloadData = _getPayload(payload); if (payloadData) { From e79f02c1df4c44b3ec081f40dbf98d9b3837b413 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Wed, 2 Apr 2025 16:26:11 -0700 Subject: [PATCH 33/62] size change and a trick --- AISKU/Tests/Unit/src/AISKUSize.Tests.ts | 4 ++-- channels/applicationinsights-channel-js/src/Sender.ts | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/AISKU/Tests/Unit/src/AISKUSize.Tests.ts b/AISKU/Tests/Unit/src/AISKUSize.Tests.ts index a1a231906..7fae45547 100644 --- a/AISKU/Tests/Unit/src/AISKUSize.Tests.ts +++ b/AISKU/Tests/Unit/src/AISKUSize.Tests.ts @@ -56,8 +56,8 @@ function _checkSize(checkType: string, maxSize: number, size: number, isNightly: export class AISKUSizeCheck extends AITestClass { private readonly MAX_RAW_SIZE = 145; private readonly MAX_BUNDLE_SIZE = 145; - private readonly MAX_RAW_DEFLATE_SIZE = 58; - private readonly MAX_BUNDLE_DEFLATE_SIZE = 58; + private readonly MAX_RAW_DEFLATE_SIZE = 59; + private readonly MAX_BUNDLE_DEFLATE_SIZE = 59; private readonly rawFilePath = "../dist/es5/applicationinsights-web.min.js"; // Automatically updated by version scripts private readonly currentVer = "3.3.6"; diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 90a5c6cd7..a149a763d 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -297,6 +297,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { version: EnvelopeCreator.Version } as IStatsBeatConfig; _statsBeat.initialize(core, statsBeatConfig); + } let corsPolicy = senderConfig.corsPolicy; if (corsPolicy){ if (corsPolicy === "same-origin" || corsPolicy === "same-site" || corsPolicy === "cross-origin") { @@ -696,7 +697,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { return; } _checkResponsStatus(response.status, payloadArr, response.url, payloadArr.length, response.statusText, resValue || ""); - onComplete(response.status, payload.headers, response.statusText); + onComplete(-Math.abs(response.status), payload.headers, response.statusText); return; }, xhrOnComplete: (request: XMLHttpRequest, oncomplete: OnCompleteCallback, payload?: IPayloadData) => { @@ -705,7 +706,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { return; } _xhrReadyStateChange(request, payloadArr, payloadArr.length); - oncomplete(request.status, payload.headers, getResponseText(request)); + oncomplete(-Math.abs(request.status), payload.headers, getResponseText(request)); return; }, @@ -955,12 +956,16 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { function _doSend(sendInterface: IXHROverride, payload: IInternalStorageItem[], isAsync: boolean, markAsSent: boolean = true): void | IPromise { let onComplete = (status: number, headers: {[headerName: string]: string;}, response?: string) => { + if (status >= 0){ + _getOnComplete(payload, status, headers, response); + } + status = Math.abs(status); let statsbeat = _core.getStatsBeat(); if (statsbeat) { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; statsbeat.count(status, payloadData, endpointHost); } - return _getOnComplete(payload, status, headers, response); + return; } let payloadData = _getPayload(payload); if (payloadData) { From bc0ff2cfa6b8eda5cbf2372ccbc070ddf94f2bcc Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Wed, 2 Apr 2025 16:26:30 -0700 Subject: [PATCH 34/62] Update AISKUSize.Tests.ts --- AISKU/Tests/Unit/src/AISKUSize.Tests.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AISKU/Tests/Unit/src/AISKUSize.Tests.ts b/AISKU/Tests/Unit/src/AISKUSize.Tests.ts index 7fae45547..965b28d13 100644 --- a/AISKU/Tests/Unit/src/AISKUSize.Tests.ts +++ b/AISKU/Tests/Unit/src/AISKUSize.Tests.ts @@ -54,8 +54,8 @@ function _checkSize(checkType: string, maxSize: number, size: number, isNightly: } export class AISKUSizeCheck extends AITestClass { - private readonly MAX_RAW_SIZE = 145; - private readonly MAX_BUNDLE_SIZE = 145; + private readonly MAX_RAW_SIZE = 146; + private readonly MAX_BUNDLE_SIZE = 146; private readonly MAX_RAW_DEFLATE_SIZE = 59; private readonly MAX_BUNDLE_DEFLATE_SIZE = 59; private readonly rawFilePath = "../dist/es5/applicationinsights-web.min.js"; From 7fa1123dbcdaacc39e6dc202f7c778eb7bfa3c07 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Thu, 3 Apr 2025 14:07:28 -0700 Subject: [PATCH 35/62] size change --- AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts | 4 ++-- shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts b/AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts index 80cf44a22..ab5e74f0b 100644 --- a/AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts +++ b/AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts @@ -51,8 +51,8 @@ function _checkSize(checkType: string, maxSize: number, size: number, isNightly: } export class AISKULightSizeCheck extends AITestClass { - private readonly MAX_RAW_SIZE = 91; - private readonly MAX_BUNDLE_SIZE = 91; + private readonly MAX_RAW_SIZE = 92; + private readonly MAX_BUNDLE_SIZE = 92; private readonly MAX_RAW_DEFLATE_SIZE = 38; private readonly MAX_BUNDLE_DEFLATE_SIZE = 38; private readonly rawFilePath = "../dist/es5/applicationinsights-web-basic.min.js"; diff --git a/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts b/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts index bac557272..d2fa9d3ac 100644 --- a/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts +++ b/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts @@ -51,7 +51,7 @@ function _checkSize(checkType: string, maxSize: number, size: number, isNightly: } export class FileSizeCheckTest extends AITestClass { - private readonly MAX_BUNDLE_SIZE = 68; + private readonly MAX_BUNDLE_SIZE = 69; private readonly MAX_DEFLATE_SIZE = 29; private readonly bundleFilePath = "../bundle/es5/ms.core.min.js"; From 2dd95a5ea1b99eecdbc2eaabe8d83d81311989e8 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Thu, 3 Apr 2025 14:25:45 -0700 Subject: [PATCH 36/62] Update AISKULightSize.Tests.ts --- AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts b/AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts index ab5e74f0b..f82ac6fb7 100644 --- a/AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts +++ b/AISKULight/Tests/Unit/src/AISKULightSize.Tests.ts @@ -51,8 +51,8 @@ function _checkSize(checkType: string, maxSize: number, size: number, isNightly: } export class AISKULightSizeCheck extends AITestClass { - private readonly MAX_RAW_SIZE = 92; - private readonly MAX_BUNDLE_SIZE = 92; + private readonly MAX_RAW_SIZE = 93; + private readonly MAX_BUNDLE_SIZE = 93; private readonly MAX_RAW_DEFLATE_SIZE = 38; private readonly MAX_BUNDLE_DEFLATE_SIZE = 38; private readonly rawFilePath = "../dist/es5/applicationinsights-web-basic.min.js"; From 50939a710b8629c3e622c4efdef6a0c7484c5da4 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 7 Apr 2025 14:54:10 -0700 Subject: [PATCH 37/62] Update Sender.ts --- .../src/Sender.ts | 62 ++++++++++++++----- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index a149a763d..f787ce4d1 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -11,7 +11,7 @@ import { ITelemetryUnloadState, IXDomainRequest, IXHROverride, OnCompleteCallback, SendPOSTFunction, SendRequestReason, SenderPostManager, TransportType, _ISendPostMgrConfig, _ISenderOnComplete, _eInternalMessageId, _throwInternal, _warnToConsole, arrForEach, cfgDfBoolean, cfgDfValidate, createProcessTelemetryContext, createUniqueNamespace, dateNow, dumpObj, eLoggingSeverity, formatErrorMessageXdr, - formatErrorMessageXhr, getExceptionName, getIEVersion, getResponseText, isArray, isBeaconsSupported, isFetchSupported, isNullOrUndefined, + formatErrorMessageXhr, getExceptionName, getIEVersion, isArray, isBeaconsSupported, isFetchSupported, isNullOrUndefined, mergeEvtNamespace, objExtend, onConfigChange, parseResponse, prependTransports, runTargetUnload } from "@microsoft/applicationinsights-core-js"; import { IPromise } from "@nevware21/ts-async"; @@ -687,7 +687,28 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (!payloadArr) { return; } - // xdr could not pass in status code unless change the function signature + console.log("XDR onComplete", xdr, payloadArr); + const responseText = _getResponseText(xdr); + let statsbeat = _core.getStatsBeat(); + var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; + if (xdr && (responseText + "" === "200" || responseText === "")) { + _consecutiveErrors = 0; + if (statsbeat) { + statsbeat.count(200, payload, endpointHost); + } + } else { + const results = parseResponse(responseText); + + if (results && results.itemsReceived && results.itemsReceived > results.itemsAccepted + && !_isRetryDisabled) { + if (statsbeat) { + statsbeat.count(201, payload, endpointHost); + } + } else { + statsbeat.count(201, payload, endpointHost); + } + } + return _xdrOnLoad(xdr, payloadArr); }, @@ -696,24 +717,35 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (!payloadArr) { return; } - _checkResponsStatus(response.status, payloadArr, response.url, payloadArr.length, response.statusText, resValue || ""); - onComplete(-Math.abs(response.status), payload.headers, response.statusText); - return; + console.log("Fetch onComplete", response, payloadArr); + let statsbeat = _core.getStatsBeat(); + if (statsbeat) { + var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; + statsbeat.count(response.status, payload, endpointHost); + } + return _checkResponsStatus(response.status, payloadArr, response.url, payloadArr.length, response.statusText, resValue || ""); }, xhrOnComplete: (request: XMLHttpRequest, oncomplete: OnCompleteCallback, payload?: IPayloadData) => { let payloadArr = _getPayloadArr(payload); if (!payloadArr) { return; } - _xhrReadyStateChange(request, payloadArr, payloadArr.length); - oncomplete(-Math.abs(request.status), payload.headers, getResponseText(request)); - return; - + console.log("XHR onComplete", request, payloadArr); + let statsbeat = _core.getStatsBeat(); + if (statsbeat && request.readyState === 4) { + var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; + statsbeat.count(request.status, payload, endpointHost); + } + return _xhrReadyStateChange(request, payloadArr, payloadArr.length); }, beaconOnRetry: (data: IPayloadData, onComplete: OnCompleteCallback, canSend: (payload: IPayloadData, oncomplete: OnCompleteCallback, sync?: boolean) => boolean) => { - _onBeaconRetry(data, onComplete, canSend); - onComplete(-1, data.headers); // don't know status code here, but we know it's already a failued request - return; + let statsbeat = _core.getStatsBeat(); + if (statsbeat) { + var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; + statsbeat.count(-1, data, endpointHost); + } + console.log("Beacon onRetry", data, canSend); + return _onBeaconRetry(data, onComplete, canSend); } } as _ISenderOnComplete; @@ -956,16 +988,12 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { function _doSend(sendInterface: IXHROverride, payload: IInternalStorageItem[], isAsync: boolean, markAsSent: boolean = true): void | IPromise { let onComplete = (status: number, headers: {[headerName: string]: string;}, response?: string) => { - if (status >= 0){ - _getOnComplete(payload, status, headers, response); - } - status = Math.abs(status); let statsbeat = _core.getStatsBeat(); if (statsbeat) { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; statsbeat.count(status, payloadData, endpointHost); } - return; + return _getOnComplete(payload, status, headers, response); } let payloadData = _getPayload(payload); if (payloadData) { From 162a5d383bf160d142af1e410382f32bf11aa53a Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 7 Apr 2025 15:27:09 -0700 Subject: [PATCH 38/62] rename and change the way to call statsbeat --- AISKU/Tests/Unit/src/AISKUSize.Tests.ts | 4 ++-- .../Tests/Unit/src/StatsBeat.tests.ts | 20 +++++++++---------- .../Tests/Unit/src/aichannel.tests.ts | 2 ++ .../src/Sender.ts | 5 +---- .../Tests/Unit/src/cfgsynchelper.tests.ts | 2 ++ .../Tests/Unit/src/StatsBeat.Tests.ts | 6 +++--- .../IConfiguration.ts | 2 +- .../src/JavaScriptSDK/AppInsightsCore.ts | 4 ++-- 8 files changed, 23 insertions(+), 22 deletions(-) diff --git a/AISKU/Tests/Unit/src/AISKUSize.Tests.ts b/AISKU/Tests/Unit/src/AISKUSize.Tests.ts index 965b28d13..1ad6ccc32 100644 --- a/AISKU/Tests/Unit/src/AISKUSize.Tests.ts +++ b/AISKU/Tests/Unit/src/AISKUSize.Tests.ts @@ -54,8 +54,8 @@ function _checkSize(checkType: string, maxSize: number, size: number, isNightly: } export class AISKUSizeCheck extends AITestClass { - private readonly MAX_RAW_SIZE = 146; - private readonly MAX_BUNDLE_SIZE = 146; + private readonly MAX_RAW_SIZE = 147; + private readonly MAX_BUNDLE_SIZE = 147; private readonly MAX_RAW_DEFLATE_SIZE = 59; private readonly MAX_BUNDLE_DEFLATE_SIZE = 59; private readonly rawFilePath = "../dist/es5/applicationinsights-web.min.js"; diff --git a/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts b/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts index bab11742f..9e2cbb5ae 100644 --- a/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts +++ b/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts @@ -23,10 +23,10 @@ export class StatsbeatTests extends AITestClass { public registerTests() { this.testCase({ - name: "Statsbeat initializes when intStats is true", + name: "Statsbeat initializes when stats is true", test: () => { let config = { - _sdk: {intStats: true}, + _sdk: {stats: true}, instrumentationKey: "Test-iKey" }; @@ -43,11 +43,11 @@ export class StatsbeatTests extends AITestClass { }); this.testCase({ - name: "Statsbeat dynamically updates when intStats changes", + name: "Statsbeat dynamically updates when stats changes", useFakeTimers: true, test: () => { let config = { - _sdk: {intStats: false}, + _sdk: {stats: false}, instrumentationKey: "Test-iKey" }; @@ -56,21 +56,21 @@ export class StatsbeatTests extends AITestClass { // Initially, Statsbeat should be null let statsbeat = this._core.getStatsBeat(); - QUnit.assert.ok(!statsbeat, "Statsbeat is null when _sdk.intStats is false"); + QUnit.assert.ok(!statsbeat, "Statsbeat is null when _sdk.stats is false"); - // Dynamically enable Statsbeat using _sdk.intStats + // Dynamically enable Statsbeat using _sdk.stats if (!this._core.config._sdk) { this._core.config._sdk = {}; } - this._core.config._sdk.intStats = true; + this._core.config._sdk.stats = true; this.clock.tick(1); // Simulate time passing for dynamic config update statsbeat = this._core.getStatsBeat(); - QUnit.assert.ok(statsbeat, "Statsbeat is initialized after enabling _sdk.intStats"); - QUnit.assert.ok(statsbeat.isInitialized(), "Statsbeat is marked as initialized after enabling _sdk.intStats"); + QUnit.assert.ok(statsbeat, "Statsbeat is initialized after enabling _sdk.stats"); + QUnit.assert.ok(statsbeat.isInitialized(), "Statsbeat is marked as initialized after enabling _sdk.stats"); // Dynamically disable Statsbeat again - this._core.config._sdk.intStats = false; + this._core.config._sdk.stats = false; this.clock.tick(1); // Simulate time passing for dynamic config update statsbeat = this._core.getStatsBeat(); diff --git a/channels/applicationinsights-channel-js/Tests/Unit/src/aichannel.tests.ts b/channels/applicationinsights-channel-js/Tests/Unit/src/aichannel.tests.ts index b4dd43ee5..8f64142fd 100644 --- a/channels/applicationinsights-channel-js/Tests/Unit/src/aichannel.tests.ts +++ b/channels/applicationinsights-channel-js/Tests/Unit/src/aichannel.tests.ts @@ -1,9 +1,11 @@ import { SenderTests } from "./Sender.tests"; import { SampleTests } from "./Sample.tests"; import { GlobalTestHooks } from "./GlobalTestHooks.Test"; +import { StatsbeatTests } from "./StatsBeat.tests"; export function runTests() { new GlobalTestHooks().registerTests(); new SenderTests().registerTests(); new SampleTests().registerTests(); + new StatsbeatTests().registerTests(); } \ No newline at end of file diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index f787ce4d1..897d3bec6 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -290,7 +290,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } } - if (config._sdk && config._sdk.intStats === true && _statsBeat && !_statsBeat.isInitialized()) { + if (config._sdk && config._sdk.stats === true && _statsBeat && !_statsBeat.isInitialized()) { let statsBeatConfig = { ikey: senderConfig.instrumentationKey, endpoint: urlParseUrl(senderConfig.endpointUrl).hostname, @@ -687,7 +687,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (!payloadArr) { return; } - console.log("XDR onComplete", xdr, payloadArr); const responseText = _getResponseText(xdr); let statsbeat = _core.getStatsBeat(); var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; @@ -717,7 +716,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (!payloadArr) { return; } - console.log("Fetch onComplete", response, payloadArr); let statsbeat = _core.getStatsBeat(); if (statsbeat) { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; @@ -730,7 +728,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (!payloadArr) { return; } - console.log("XHR onComplete", request, payloadArr); let statsbeat = _core.getStatsBeat(); if (statsbeat && request.readyState === 4) { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; diff --git a/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsynchelper.tests.ts b/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsynchelper.tests.ts index 5aafcea69..2305b6318 100644 --- a/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsynchelper.tests.ts +++ b/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsynchelper.tests.ts @@ -102,6 +102,8 @@ export class CfgSyncHelperTests extends AITestClass { extensions:[{isFlushInvoked:false,isTearDownInvoked:false,isResumeInvoked:false,isPauseInvoked:false,identifier:"Sender",priority:1001}], channels:[], extensionConfig:{}, + _sdk: { + stats: false}, enableDebug: false } diff --git a/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts index 166c63ab5..c0213aa4d 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts @@ -23,7 +23,7 @@ export class StatsBeatTests extends AITestClass { instrumentationKey: "Test-iKey", disableInstrumentationKeyValidation: true, _sdk: { - intStats: true // Enable statsbeat by default + stats: true // Enable statsbeat by default } }; @@ -187,7 +187,7 @@ export class StatsBeatTests extends AITestClass { if (!this._core.config._sdk) { this._core.config._sdk = {}; } - this._core.config._sdk.intStats = false; + this._core.config._sdk.stats = false; this.clock.tick(1); // Allow time for config changes to propagate // Verify that statsbeat is removed @@ -195,7 +195,7 @@ if (!this._core.config._sdk) { Assert.ok(!updatedStatsbeat, "Statsbeat should be removed when disabled"); // Re-enable statsbeat - this._core.config._sdk.intStats = true; + this._core.config._sdk.stats = true; this.clock.tick(1); // Allow time for config changes to propagate // Verify that statsbeat is created again diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IConfiguration.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IConfiguration.ts index 5b5712cf4..36bf23971 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IConfiguration.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IConfiguration.ts @@ -229,5 +229,5 @@ export interface IInternalSdkConfiguration { * [Optional] Enable Internal StatsBeat * @internal */ - intStats?: boolean; + stats?: boolean; } \ No newline at end of file diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index d8e5b96bc..fd480ec67 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -79,7 +79,7 @@ const defaultConfig: IConfigDefaults = objDeepFreeze({ [STR_CREATE_PERF_MGR]: UNDEFINED_VALUE, loggingLevelConsole: eLoggingSeverity.DISABLED, diagnosticLogInterval: UNDEFINED_VALUE, - _sdk: {intStats:false} + _sdk: {stats:false} }); /** @@ -363,7 +363,7 @@ export class AppInsightsCore im _initInMemoMaxSize = rootCfg.initInMemoMaxSize || maxInitQueueSize; // uncomment this until throttle is implemented - if (config._sdk.intStats === true){ + if (config._sdk.stats === true){ _statsBeat = _statsBeat || new Statsbeat(); } else { _statsBeat = null; From 6a65e0032a7ad57ab0c11292802edf966febc1d2 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 7 Apr 2025 15:48:13 -0700 Subject: [PATCH 39/62] Update cfgsynchelper.tests.ts --- .../Tests/Unit/src/cfgsynchelper.tests.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsynchelper.tests.ts b/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsynchelper.tests.ts index 2305b6318..f786e5039 100644 --- a/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsynchelper.tests.ts +++ b/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsynchelper.tests.ts @@ -1,9 +1,8 @@ import { AITestClass, Assert } from "@microsoft/ai-test-framework"; import { NonOverrideCfg } from "../../../src/Interfaces/ICfgSyncConfig"; -import { AppInsightsCore, CdnFeatureMode, FeatureOptInMode, IAppInsightsCore, IConfiguration, IFeatureOptIn, IFeatureOptInDetails, INotificationManager, IPlugin, ITelemetryItem, PerfManager } from "@microsoft/applicationinsights-core-js"; +import { ICookieMgrConfig, AppInsightsCore, CdnFeatureMode, FeatureOptInMode, IAppInsightsCore, IConfiguration, IFeatureOptIn, IFeatureOptInDetails, INotificationManager, IPlugin, ITelemetryItem, PerfManager } from "@microsoft/applicationinsights-core-js"; import { IConfig, IStorageBuffer } from "@microsoft/applicationinsights-common"; import { resolveCdnFeatureCfg, replaceByNonOverrideCfg, applyCdnfeatureCfg } from "../../../src/CfgSyncHelperFuncs"; -import { ICookieMgrConfig } from "@microsoft/applicationinsights-core-js/src/applicationinsights-core-js"; import { ICfgSyncCdnConfig } from "../../../src/Interfaces/ICfgSyncCdnConfig"; export class CfgSyncHelperTests extends AITestClass { From 3a6eea0afd1d548aecee1becaba575229624208b Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 7 Apr 2025 18:33:52 -0700 Subject: [PATCH 40/62] Update AppInsightsCore.ts --- shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index 65864131c..983e0c9d9 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -362,9 +362,6 @@ export class AppInsightsCore im _statsBeat = null; } - // app Insights core only handle ikey and endpointurl, aisku will handle cs - let ikey = rootCfg.instrumentationKey; - let endpointUrl = rootCfg.endpointUrl; // do not need to validate endpoint url, if it is null, default one will be set by sender _handleIKeyEndpointPromises(rootCfg); // Mark the extensionConfig and all first level keys as referenced From a60cfdb3839ceb1fef8a893da5ea53b30c98db65 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 7 Apr 2025 18:34:03 -0700 Subject: [PATCH 41/62] Update StatsBeat.tests.ts --- .../Tests/Unit/src/StatsBeat.tests.ts | 201 +++++++++++++++++- 1 file changed, 197 insertions(+), 4 deletions(-) diff --git a/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts b/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts index 9e2cbb5ae..d3e5e50a2 100644 --- a/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts +++ b/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts @@ -1,14 +1,20 @@ -import { AITestClass } from "@microsoft/ai-test-framework"; -import { AppInsightsCore } from "@microsoft/applicationinsights-core-js"; +import { AITestClass, Assert, PollingAssert } from "@microsoft/ai-test-framework"; +import { AppInsightsCore, getWindow, IPayloadData, ITelemetryItem, strContains, TransportType } from "@microsoft/applicationinsights-core-js"; import { Sender } from "../../../src/Sender"; - +import { SinonSpy } from 'sinon'; +import { ISenderConfig } from "../../../types/applicationinsights-channel-js"; +import { isBeaconApiSupported } from "@microsoft/applicationinsights-common"; export class StatsbeatTests extends AITestClass { private _core: AppInsightsCore; private _sender: Sender; - + private statsbeatCountSpy: SinonSpy; + private fetchStub: sinon.SinonStub; + private fakeXMLHttpRequest: any; + private trackSpy: SinonSpy; public testInitialize() { this._core = new AppInsightsCore(); this._sender = new Sender(); + this.fakeXMLHttpRequest = (window as any).XMLHttpRequest; } public testFinishedCleanup() { @@ -19,6 +25,16 @@ export class StatsbeatTests extends AITestClass { } this._sender = null; this._core = null; + if (this.statsbeatCountSpy) { + this.statsbeatCountSpy.restore(); + } + if (this.fetchStub) { + this.fetchStub.restore(); + } + if (this.trackSpy) { + this.trackSpy.restore(); + } + (window as any).XMLHttpRequest = this.fakeXMLHttpRequest; } public registerTests() { @@ -77,5 +93,182 @@ export class StatsbeatTests extends AITestClass { QUnit.assert.ok(!statsbeat, "Statsbeat is null after disabling disableStatsBeat again"); } }); + + this.testCaseAsync({ + name: "Statsbeat increments success count when fetch sender is called once", + useFakeTimers: true, + stepDelay: 100, + steps: [ + () => { + let sendBeaconCalled = false; + this.hookSendBeacon((url: string) => { + sendBeaconCalled = true; + return false; + }); + this.fetchStub = this.sandbox.stub(window, "fetch").callsFake(() => { + return Promise.resolve(new Response("{}", { + status: 200, + statusText: "OK" + })); + }); + let config = { + endpointUrl: "https//:test", + emitLineDelimitedJson: false, + maxBatchInterval: 15000, + maxBatchSizeInBytes: 102400, + disableTelemetry: false, + enableSessionStorageBuffer: true, + isRetryDisabled: false, + isBeaconApiDisabled:true, + disableXhr: false, + onunloadDisableFetch: false, + onunloadDisableBeacon: false, + namePrefix: "", + samplingPercentage: 100, + customHeaders: [{header:"header",value:"val" }], + convertUndefined: "", + eventsLimitInMem: 10000, + transports: [TransportType.Fetch] + } as ISenderConfig; + + const sender = new Sender(); + const cr = new AppInsightsCore(); + var coreConfig = { + instrumentationKey: "000e0000-e000-0000-a000-000000000000", + _sdk: { stats: true }, + extensionConfig: {[sender.identifier]: config} + }; + + cr.initialize(coreConfig, [sender]); + this.statsbeatCountSpy = this.sandbox.spy(cr.getStatsBeat(), 'count'); + this.trackSpy = this.sandbox.spy(cr, 'track'); + this.onDone(() => { + sender.teardown(); + }); + + const telemetryItem: ITelemetryItem = { + name: 'fake item', + iKey: 'testIkey2;ingestionendpoint=testUrl1', + baseType: 'some type', + baseData: {} + }; + + QUnit.assert.ok(isBeaconApiSupported(), "Beacon API is supported"); + QUnit.assert.equal(false, sendBeaconCalled, "Beacon API was not called before"); + QUnit.assert.equal(0, this._getXhrRequests().length, "xhr sender was not called before"); + + try { + sender.processTelemetry(telemetryItem, null); + sender.flush(); + } catch(e) { + QUnit.assert.ok(false); + } + this.clock.tick(900000); // Simulate time passing for statsbeat to be sent + } + ].concat(PollingAssert.createPollingAssert(() => { + if (this.statsbeatCountSpy.called && this.fetchStub.called) { + Assert.equal(this.statsbeatCountSpy.callCount, 1, "Statsbeat count should be calledonce"); + Assert.equal(this.fetchStub.callCount, 1, "Fetch sender should be called once"); + Assert.equal(this.statsbeatCountSpy.firstCall.args[0], 200, "Statsbeat count should be called with status 200"); + let data = JSON.stringify(this.statsbeatCountSpy.firstCall.args[1]); + Assert.ok(strContains(data, "startTime"), "Statsbeat count should be called with startTime set"); + Assert.equal(this.statsbeatCountSpy.firstCall.args[2], "localhost", "Statsbeat count should be called with host localhost"); + // console.log("this.trackSpy", this.trackSpy.called); + let statsbeatEvent = this.trackSpy.firstCall.args[0]; + Assert.equal(statsbeatEvent.baseType, "MetricData", "Statsbeat event should be of type MetricData"); + Assert.equal(statsbeatEvent.baseData.name, "Request_Success_Count", "Statsbeat event should be of type Request_Success_Count"); + return true; + } + return false; + }, "Waiting for fetch sender and Statsbeat count to be called") as any) + }); + + this.testCaseAsync({ + name: "Statsbeat increments retry count when fetch sender is called once", + useFakeTimers: true, + stepDelay: 100, + steps: [ + () => { + let sendBeaconCalled = false; + this.hookSendBeacon((url: string) => { + sendBeaconCalled = true; + return false; + }); + this.fetchStub = this.sandbox.stub(window, "fetch").callsFake(() => { + return Promise.resolve(new Response("{}", { + status: 439, + statusText: "not a success response" // this result fetch api throw out an error and status code will be changed to 400 + })); + }); + let config = { + endpointUrl: "https//:test", + emitLineDelimitedJson: false, + maxBatchInterval: 15000, + maxBatchSizeInBytes: 102400, + disableTelemetry: false, + enableSessionStorageBuffer: true, + isRetryDisabled: false, + isBeaconApiDisabled:true, + disableXhr: false, + onunloadDisableFetch: false, + onunloadDisableBeacon: false, + namePrefix: "", + samplingPercentage: 100, + customHeaders: [{header:"header",value:"val" }], + convertUndefined: "", + eventsLimitInMem: 10000, + transports: [TransportType.Fetch] + } as ISenderConfig; + + const sender = new Sender(); + const cr = new AppInsightsCore(); + var coreConfig = { + instrumentationKey: "000e0000-e000-0000-a000-000000000000", + _sdk: { stats: true }, + extensionConfig: {[sender.identifier]: config} + }; + + cr.initialize(coreConfig, [sender]); + this.statsbeatCountSpy = this.sandbox.spy(cr.getStatsBeat(), 'count'); + this.trackSpy = this.sandbox.spy(cr, 'track'); + this.onDone(() => { + sender.teardown(); + }); + + const telemetryItem: ITelemetryItem = { + name: 'fake item', + iKey: 'testIkey2;ingestionendpoint=testUrl1', + baseType: 'some type', + baseData: {} + }; + + QUnit.assert.ok(isBeaconApiSupported(), "Beacon API is supported"); + QUnit.assert.equal(false, sendBeaconCalled, "Beacon API was not called before"); + QUnit.assert.equal(0, this._getXhrRequests().length, "xhr sender was not called before"); + + try { + sender.processTelemetry(telemetryItem, null); + sender.flush(); + } catch(e) { + QUnit.assert.ok(false); + } + this.clock.tick(900000); // Simulate time passing for statsbeat to be sent + } + ].concat(PollingAssert.createPollingAssert(() => { + if (this.statsbeatCountSpy.called && this.fetchStub.called) { + Assert.equal(this.statsbeatCountSpy.callCount, 1, "Statsbeat count should be calledonce"); + Assert.equal(this.fetchStub.callCount, 1, "Fetch sender should be called once"); + Assert.equal(this.statsbeatCountSpy.firstCall.args[0], 400, "Statsbeat count should be called with status 400"); + let data = JSON.stringify(this.statsbeatCountSpy.firstCall.args); + Assert.ok(strContains(data, "startTime"), "Statsbeat count should be called with startTime set"); + let statsbeatEvent = this.trackSpy.firstCall.args[0]; + Assert.equal(statsbeatEvent.baseType, "MetricData", "Statsbeat event should be of type MetricData"); + Assert.equal(statsbeatEvent.baseData.name, "failure", "Statsbeat event should be of type failure"); + (window as any).XMLHttpRequest = this.fakeXMLHttpRequest; + return true; + } + return false; + }, "Waiting for fetch sender and Statsbeat count to be called", 60, 1000) as any) + }); } } \ No newline at end of file From 23d4771aa30b2b251fffe4462cf652ea08a1d931 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 7 Apr 2025 19:40:06 -0700 Subject: [PATCH 42/62] comment out statsbeat test, set statsbeat to null by default --- .../Tests/Unit/src/StatsBeat.tests.ts | 328 ++++++++---------- .../Tests/Unit/src/aichannel.tests.ts | 2 +- .../Tests/Unit/src/aiunittests.ts | 4 +- .../src/JavaScriptSDK/AppInsightsCore.ts | 10 +- 4 files changed, 158 insertions(+), 186 deletions(-) diff --git a/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts b/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts index d3e5e50a2..574c43986 100644 --- a/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts +++ b/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts @@ -1,20 +1,21 @@ import { AITestClass, Assert, PollingAssert } from "@microsoft/ai-test-framework"; -import { AppInsightsCore, getWindow, IPayloadData, ITelemetryItem, strContains, TransportType } from "@microsoft/applicationinsights-core-js"; +import { AppInsightsCore, IPayloadData, ITelemetryItem, TransportType } from "@microsoft/applicationinsights-core-js"; import { Sender } from "../../../src/Sender"; -import { SinonSpy } from 'sinon'; +import { SinonSpy, SinonStub } from "sinon"; import { ISenderConfig } from "../../../types/applicationinsights-channel-js"; import { isBeaconApiSupported } from "@microsoft/applicationinsights-common"; + export class StatsbeatTests extends AITestClass { private _core: AppInsightsCore; private _sender: Sender; private statsbeatCountSpy: SinonSpy; private fetchStub: sinon.SinonStub; - private fakeXMLHttpRequest: any; + private beaconStub: sinon.SinonStub; private trackSpy: SinonSpy; + public testInitialize() { this._core = new AppInsightsCore(); this._sender = new Sender(); - this.fakeXMLHttpRequest = (window as any).XMLHttpRequest; } public testFinishedCleanup() { @@ -31,152 +32,118 @@ export class StatsbeatTests extends AITestClass { if (this.fetchStub) { this.fetchStub.restore(); } + if (this.beaconStub) { + this.beaconStub.restore(); + } if (this.trackSpy) { this.trackSpy.restore(); } - (window as any).XMLHttpRequest = this.fakeXMLHttpRequest; + } + + private initializeCoreAndSender(config: any, instrumentationKey: string) { + const sender = new Sender(); + const core = new AppInsightsCore(); + const coreConfig = { + instrumentationKey, + _sdk: { stats: true }, + extensionConfig: { [sender.identifier]: config } + }; + + core.initialize(coreConfig, [sender]); + this.statsbeatCountSpy = this.sandbox.spy(core.getStatsBeat(), "count"); + this.trackSpy = this.sandbox.spy(core, "track"); + + this.onDone(() => { + sender.teardown(); + }); + + return { core, sender }; + } + + private createSenderConfig(transportType: TransportType) { + return { + endpointUrl: "https://test", + emitLineDelimitedJson: false, + maxBatchInterval: 15000, + maxBatchSizeInBytes: 102400, + disableTelemetry: false, + enableSessionStorageBuffer: true, + isRetryDisabled: false, + isBeaconApiDisabled: false, + disableXhr: false, + onunloadDisableFetch: false, + onunloadDisableBeacon: false, + namePrefix: "", + samplingPercentage: 100, + customHeaders: [{ header: "header", value: "val" }], + convertUndefined: "", + eventsLimitInMem: 10000, + transports: [transportType] + }; + } + + private processTelemetryAndFlush(sender: Sender, telemetryItem: ITelemetryItem) { + try { + sender.processTelemetry(telemetryItem, null); + sender.flush(); + } catch (e) { + QUnit.assert.ok(false, "Unexpected error during telemetry processing"); + } + this.clock.tick(900000); // Simulate time passing for statsbeat to be sent + } + + private assertStatsbeatCall(statusCode: number, eventName: string) { + Assert.equal(this.statsbeatCountSpy.callCount, 1, "Statsbeat count should be called once"); + Assert.equal(this.statsbeatCountSpy.firstCall.args[0], statusCode, `Statsbeat count should be called with status ${statusCode}`); + const data = JSON.stringify(this.statsbeatCountSpy.firstCall.args[1]); + Assert.ok(data.includes("startTime"), "Statsbeat count should be called with startTime set"); + const statsbeatEvent = this.trackSpy.firstCall.args[0]; + Assert.equal(statsbeatEvent.baseType, "MetricData", "Statsbeat event should be of type MetricData"); + Assert.equal(statsbeatEvent.baseData.name, eventName, `Statsbeat event should be of type ${eventName}`); } public registerTests() { this.testCase({ name: "Statsbeat initializes when stats is true", test: () => { - let config = { - _sdk: {stats: true}, + const config = { + _sdk: { stats: true }, instrumentationKey: "Test-iKey" }; - // Initialize core with the configuration this._core.initialize(config, [this._sender]); - - // Get Statsbeat from core const statsbeat = this._core.getStatsBeat(); - // Assert that Statsbeat is initialized QUnit.assert.ok(statsbeat, "Statsbeat is initialized"); QUnit.assert.ok(statsbeat.isInitialized(), "Statsbeat is marked as initialized"); } }); - this.testCase({ - name: "Statsbeat dynamically updates when stats changes", - useFakeTimers: true, - test: () => { - let config = { - _sdk: {stats: false}, - instrumentationKey: "Test-iKey" - }; - - // Initialize core with the configuration - this._core.initialize(config, [this._sender]); - - // Initially, Statsbeat should be null - let statsbeat = this._core.getStatsBeat(); - QUnit.assert.ok(!statsbeat, "Statsbeat is null when _sdk.stats is false"); - - // Dynamically enable Statsbeat using _sdk.stats - if (!this._core.config._sdk) { - this._core.config._sdk = {}; - } - this._core.config._sdk.stats = true; - this.clock.tick(1); // Simulate time passing for dynamic config update - - statsbeat = this._core.getStatsBeat(); - QUnit.assert.ok(statsbeat, "Statsbeat is initialized after enabling _sdk.stats"); - QUnit.assert.ok(statsbeat.isInitialized(), "Statsbeat is marked as initialized after enabling _sdk.stats"); - - // Dynamically disable Statsbeat again - this._core.config._sdk.stats = false; - this.clock.tick(1); // Simulate time passing for dynamic config update - - statsbeat = this._core.getStatsBeat(); - QUnit.assert.ok(!statsbeat, "Statsbeat is null after disabling disableStatsBeat again"); - } - }); - this.testCaseAsync({ name: "Statsbeat increments success count when fetch sender is called once", useFakeTimers: true, stepDelay: 100, steps: [ () => { - let sendBeaconCalled = false; - this.hookSendBeacon((url: string) => { - sendBeaconCalled = true; - return false; - }); this.fetchStub = this.sandbox.stub(window, "fetch").callsFake(() => { - return Promise.resolve(new Response("{}", { - status: 200, - statusText: "OK" - })); + return Promise.resolve(new Response("{}", { status: 200, statusText: "OK" })); }); - let config = { - endpointUrl: "https//:test", - emitLineDelimitedJson: false, - maxBatchInterval: 15000, - maxBatchSizeInBytes: 102400, - disableTelemetry: false, - enableSessionStorageBuffer: true, - isRetryDisabled: false, - isBeaconApiDisabled:true, - disableXhr: false, - onunloadDisableFetch: false, - onunloadDisableBeacon: false, - namePrefix: "", - samplingPercentage: 100, - customHeaders: [{header:"header",value:"val" }], - convertUndefined: "", - eventsLimitInMem: 10000, - transports: [TransportType.Fetch] - } as ISenderConfig; - const sender = new Sender(); - const cr = new AppInsightsCore(); - var coreConfig = { - instrumentationKey: "000e0000-e000-0000-a000-000000000000", - _sdk: { stats: true }, - extensionConfig: {[sender.identifier]: config} - }; - - cr.initialize(coreConfig, [sender]); - this.statsbeatCountSpy = this.sandbox.spy(cr.getStatsBeat(), 'count'); - this.trackSpy = this.sandbox.spy(cr, 'track'); - this.onDone(() => { - sender.teardown(); - }); + const config = this.createSenderConfig(TransportType.Fetch); + const { sender } = this.initializeCoreAndSender(config, "000e0000-e000-0000-a000-000000000000"); const telemetryItem: ITelemetryItem = { - name: 'fake item', - iKey: 'testIkey2;ingestionendpoint=testUrl1', - baseType: 'some type', + name: "fake item", + iKey: "testIkey2;ingestionendpoint=testUrl1", + baseType: "some type", baseData: {} }; - QUnit.assert.ok(isBeaconApiSupported(), "Beacon API is supported"); - QUnit.assert.equal(false, sendBeaconCalled, "Beacon API was not called before"); - QUnit.assert.equal(0, this._getXhrRequests().length, "xhr sender was not called before"); - - try { - sender.processTelemetry(telemetryItem, null); - sender.flush(); - } catch(e) { - QUnit.assert.ok(false); - } - this.clock.tick(900000); // Simulate time passing for statsbeat to be sent + this.processTelemetryAndFlush(sender, telemetryItem); } ].concat(PollingAssert.createPollingAssert(() => { if (this.statsbeatCountSpy.called && this.fetchStub.called) { - Assert.equal(this.statsbeatCountSpy.callCount, 1, "Statsbeat count should be calledonce"); - Assert.equal(this.fetchStub.callCount, 1, "Fetch sender should be called once"); - Assert.equal(this.statsbeatCountSpy.firstCall.args[0], 200, "Statsbeat count should be called with status 200"); - let data = JSON.stringify(this.statsbeatCountSpy.firstCall.args[1]); - Assert.ok(strContains(data, "startTime"), "Statsbeat count should be called with startTime set"); - Assert.equal(this.statsbeatCountSpy.firstCall.args[2], "localhost", "Statsbeat count should be called with host localhost"); - // console.log("this.trackSpy", this.trackSpy.called); - let statsbeatEvent = this.trackSpy.firstCall.args[0]; - Assert.equal(statsbeatEvent.baseType, "MetricData", "Statsbeat event should be of type MetricData"); - Assert.equal(statsbeatEvent.baseData.name, "Request_Success_Count", "Statsbeat event should be of type Request_Success_Count"); + this.assertStatsbeatCall(200, "Request_Success_Count"); return true; } return false; @@ -189,86 +156,91 @@ export class StatsbeatTests extends AITestClass { stepDelay: 100, steps: [ () => { - let sendBeaconCalled = false; - this.hookSendBeacon((url: string) => { - sendBeaconCalled = true; - return false; - }); this.fetchStub = this.sandbox.stub(window, "fetch").callsFake(() => { - return Promise.resolve(new Response("{}", { - status: 439, - statusText: "not a success response" // this result fetch api throw out an error and status code will be changed to 400 - })); + return Promise.resolve(new Response("{}", { status: 439, statusText: "Too Many Requests" })); }); - let config = { - endpointUrl: "https//:test", - emitLineDelimitedJson: false, - maxBatchInterval: 15000, - maxBatchSizeInBytes: 102400, - disableTelemetry: false, - enableSessionStorageBuffer: true, - isRetryDisabled: false, - isBeaconApiDisabled:true, - disableXhr: false, - onunloadDisableFetch: false, - onunloadDisableBeacon: false, - namePrefix: "", - samplingPercentage: 100, - customHeaders: [{header:"header",value:"val" }], - convertUndefined: "", - eventsLimitInMem: 10000, - transports: [TransportType.Fetch] - } as ISenderConfig; - const sender = new Sender(); - const cr = new AppInsightsCore(); - var coreConfig = { - instrumentationKey: "000e0000-e000-0000-a000-000000000000", - _sdk: { stats: true }, - extensionConfig: {[sender.identifier]: config} + const config = this.createSenderConfig(TransportType.Fetch); + const { sender } = this.initializeCoreAndSender(config, "000e0000-e000-0000-a000-000000000000"); + + const telemetryItem: ITelemetryItem = { + name: "fake item", + iKey: "testIkey2;ingestionendpoint=testUrl1", + baseType: "some type", + baseData: {} }; - cr.initialize(coreConfig, [sender]); - this.statsbeatCountSpy = this.sandbox.spy(cr.getStatsBeat(), 'count'); - this.trackSpy = this.sandbox.spy(cr, 'track'); - this.onDone(() => { - sender.teardown(); - }); + this.processTelemetryAndFlush(sender, telemetryItem); + } + ].concat(PollingAssert.createPollingAssert(() => { + if (this.statsbeatCountSpy.called && this.fetchStub.called) { + this.assertStatsbeatCall(400, "failure"); + return true; + } + return false; + }, "Waiting for fetch sender and Statsbeat count to be called") as any) + }); + + + + // this.testCaseAsync({ + // name: "Statsbeat increments success count for xhr sender",useFakeTimers: true, + // stepDelay: 100, + // steps: [ + // () => { + // let config = this.createSenderConfig(TransportType.Xhr) && {disableSendBeaconSplit: true}; + // const { sender } = this.initializeCoreAndSender(config, "000e0000-e000-0000-a000-000000000000"); + + // const telemetryItem: ITelemetryItem = { + // name: "fake item", + // iKey: "testIkey2;ingestionendpoint=testUrl1", + // baseType: "some type", + // baseData: {} + // }; + // this.processTelemetryAndFlush(sender, telemetryItem); + // QUnit.assert.equal(1, this._getXhrRequests().length, "xhr sender is called"); + + // } + // ].concat(PollingAssert.createPollingAssert(() => { + // if (this.statsbeatCountSpy.called) { + // // this.assertStatsbeatCall(200, "Request_Success_Count"); + // console.log("Statsbeat count called with success count for xhr sender"); + // return true; + // } + // return false; + // }, "Waiting for xhr sender and Statsbeat count to be called", 60, 1000) as any) + // }); + + this.testCaseAsync({ + name: "Statsbeat increments success count for beacon sender", + useFakeTimers: true, + stepDelay: 100, + steps: [ + () => { + const config = this.createSenderConfig(TransportType.Beacon); + const { sender } = this.initializeCoreAndSender(config, "000e0000-e000-0000-a000-000000000000"); const telemetryItem: ITelemetryItem = { - name: 'fake item', - iKey: 'testIkey2;ingestionendpoint=testUrl1', - baseType: 'some type', + name: "fake item", + iKey: "testIkey2;ingestionendpoint=testUrl1", + baseType: "some type", baseData: {} }; - + let sendBeaconCalled = false; + this.hookSendBeacon((url: string) => { + sendBeaconCalled = true; + return true; + }); QUnit.assert.ok(isBeaconApiSupported(), "Beacon API is supported"); - QUnit.assert.equal(false, sendBeaconCalled, "Beacon API was not called before"); - QUnit.assert.equal(0, this._getXhrRequests().length, "xhr sender was not called before"); - - try { - sender.processTelemetry(telemetryItem, null); - sender.flush(); - } catch(e) { - QUnit.assert.ok(false); - } - this.clock.tick(900000); // Simulate time passing for statsbeat to be sent + this.processTelemetryAndFlush(sender, telemetryItem); } ].concat(PollingAssert.createPollingAssert(() => { - if (this.statsbeatCountSpy.called && this.fetchStub.called) { - Assert.equal(this.statsbeatCountSpy.callCount, 1, "Statsbeat count should be calledonce"); - Assert.equal(this.fetchStub.callCount, 1, "Fetch sender should be called once"); - Assert.equal(this.statsbeatCountSpy.firstCall.args[0], 400, "Statsbeat count should be called with status 400"); - let data = JSON.stringify(this.statsbeatCountSpy.firstCall.args); - Assert.ok(strContains(data, "startTime"), "Statsbeat count should be called with startTime set"); - let statsbeatEvent = this.trackSpy.firstCall.args[0]; - Assert.equal(statsbeatEvent.baseType, "MetricData", "Statsbeat event should be of type MetricData"); - Assert.equal(statsbeatEvent.baseData.name, "failure", "Statsbeat event should be of type failure"); - (window as any).XMLHttpRequest = this.fakeXMLHttpRequest; + if (this.statsbeatCountSpy.called) { + this.assertStatsbeatCall(200, "Request_Success_Count"); return true; } return false; - }, "Waiting for fetch sender and Statsbeat count to be called", 60, 1000) as any) + }, "Waiting for beacon sender and Statsbeat count to be called") as any) }); } } \ No newline at end of file diff --git a/channels/applicationinsights-channel-js/Tests/Unit/src/aichannel.tests.ts b/channels/applicationinsights-channel-js/Tests/Unit/src/aichannel.tests.ts index 8f64142fd..97061376c 100644 --- a/channels/applicationinsights-channel-js/Tests/Unit/src/aichannel.tests.ts +++ b/channels/applicationinsights-channel-js/Tests/Unit/src/aichannel.tests.ts @@ -7,5 +7,5 @@ export function runTests() { new GlobalTestHooks().registerTests(); new SenderTests().registerTests(); new SampleTests().registerTests(); - new StatsbeatTests().registerTests(); + // new StatsbeatTests().registerTests(); } \ No newline at end of file diff --git a/shared/AppInsightsCore/Tests/Unit/src/aiunittests.ts b/shared/AppInsightsCore/Tests/Unit/src/aiunittests.ts index 11a062684..8a1f8bbdb 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/aiunittests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/aiunittests.ts @@ -27,6 +27,6 @@ export function runTests() { new UpdateConfigTests().registerTests(); new EventsDiscardedReasonTests().registerTests(); new W3cTraceParentTests().registerTests(); - new StatsBeatTests(false).registerTests(); - new StatsBeatTests(true).registerTests(); + // new StatsBeatTests(false).registerTests(); + // new StatsBeatTests(true).registerTests(); } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index 983e0c9d9..016b45bc5 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -356,11 +356,11 @@ export class AppInsightsCore im _initInMemoMaxSize = rootCfg.initInMemoMaxSize || maxInitQueueSize; // uncomment this until throttle is implemented - if (config._sdk.stats === true){ - _statsBeat = _statsBeat || new Statsbeat(); - } else { - _statsBeat = null; - } + // if (config._sdk.stats === true){ + // _statsBeat = _statsBeat || new Statsbeat(); + // } else { + // _statsBeat = null; + // } _handleIKeyEndpointPromises(rootCfg); From 3598def7c53683825d638892da0ab37ff32af1b9 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 7 Apr 2025 23:03:38 -0700 Subject: [PATCH 43/62] Update AppInsightsCore.ts --- shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index 016b45bc5..bc9ee29bb 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -52,7 +52,7 @@ import { PerfManager, doPerf, getGblPerfMgr } from "./PerfManager"; import { createProcessTelemetryContext, createProcessTelemetryUnloadContext, createProcessTelemetryUpdateContext, createTelemetryProxyChain } from "./ProcessTelemetryContext"; -import { Statsbeat } from "./StatsBeat"; +// import { Statsbeat } from "./StatsBeat"; import { _getPluginState, createDistributedTraceContext, initializePlugins, sortPlugins } from "./TelemetryHelpers"; import { TelemetryInitializerPlugin } from "./TelemetryInitializerPlugin"; import { IUnloadHandlerContainer, UnloadHandler, createUnloadHandlerContainer } from "./UnloadHandlerContainer"; From 1acb33fe35938f534f795f302596dc3eb6aebedd Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 14 Apr 2025 16:12:48 -0700 Subject: [PATCH 44/62] change based on comments --- .../src/Sender.ts | 16 +++++++++------- .../Tests/Unit/src/StatsBeat.Tests.ts | 4 ++-- .../src/JavaScriptSDK/AppInsightsCore.ts | 19 +++++++++++-------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 897d3bec6..6b5b7653f 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -188,7 +188,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let _disableBeaconSplit: boolean; let _sendPostMgr: SenderPostManager; let _retryCodes: number[]; - let _core: IAppInsightsCore; dynamicProto(Sender, this, (_self, _base) => { @@ -264,7 +263,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let diagLog = _self.diagLog(); _evtNamespace = mergeEvtNamespace(createUniqueNamespace("Sender"), core.evtNamespace && core.evtNamespace()); _offlineListener = createOfflineListener(_evtNamespace); - _core = core; // This function will be re-called whenever any referenced configuration is changed _self._addHook(onConfigChange(config, (details) => { let config = details.cfg; @@ -661,6 +659,10 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } + function _getStatsBeat() { + return _self.core.getStatsBeat(); + } + function _xdrOnLoad (xdr: IXDomainRequest, payload: IInternalStorageItem[]) { const responseText = _getResponseText(xdr); if (xdr && (responseText + "" === "200" || responseText === "")) { @@ -688,7 +690,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { return; } const responseText = _getResponseText(xdr); - let statsbeat = _core.getStatsBeat(); + let statsbeat = _getStatsBeat(); var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; if (xdr && (responseText + "" === "200" || responseText === "")) { _consecutiveErrors = 0; @@ -716,7 +718,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (!payloadArr) { return; } - let statsbeat = _core.getStatsBeat(); + let statsbeat = _getStatsBeat(); if (statsbeat) { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; statsbeat.count(response.status, payload, endpointHost); @@ -728,7 +730,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { if (!payloadArr) { return; } - let statsbeat = _core.getStatsBeat(); + let statsbeat = _getStatsBeat(); if (statsbeat && request.readyState === 4) { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; statsbeat.count(request.status, payload, endpointHost); @@ -736,7 +738,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { return _xhrReadyStateChange(request, payloadArr, payloadArr.length); }, beaconOnRetry: (data: IPayloadData, onComplete: OnCompleteCallback, canSend: (payload: IPayloadData, oncomplete: OnCompleteCallback, sync?: boolean) => boolean) => { - let statsbeat = _core.getStatsBeat(); + let statsbeat = _getStatsBeat(); if (statsbeat) { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; statsbeat.count(-1, data, endpointHost); @@ -985,7 +987,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { function _doSend(sendInterface: IXHROverride, payload: IInternalStorageItem[], isAsync: boolean, markAsSent: boolean = true): void | IPromise { let onComplete = (status: number, headers: {[headerName: string]: string;}, response?: string) => { - let statsbeat = _core.getStatsBeat(); + let statsbeat = _getStatsBeat(); if (statsbeat) { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; statsbeat.count(status, payloadData, endpointHost); diff --git a/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts index c0213aa4d..d1b28b258 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts @@ -184,8 +184,8 @@ export class StatsBeatTests extends AITestClass { Assert.ok(statsbeat, "Statsbeat should be created"); // Update configuration to disable statsbeat -if (!this._core.config._sdk) { - this._core.config._sdk = {}; + if (!this._core.config._sdk) { + this._core.config._sdk = {}; } this._core.config._sdk.stats = false; this.clock.tick(1); // Allow time for config changes to propagate diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index bc9ee29bb..b589f9ef1 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -8,6 +8,7 @@ import { ITimerHandler, arrAppend, arrForEach, arrIndexOf, createTimeout, deepExtend, hasDocument, isFunction, isNullOrUndefined, isPlainObject, isPromiseLike, objDeepFreeze, objDefine, objForEachKey, objFreeze, objHasOwn, scheduleTimeout, throwError } from "@nevware21/ts-utils"; +import { cfgDfMerge } from "../Config/ConfigDefaultHelpers"; import { createDynamicConfig, onConfigChange } from "../Config/DynamicConfig"; import { IConfigDefaults } from "../Config/IConfigDefaults"; import { IDynamicConfigHandler, _IInternalDynamicConfigHandler } from "../Config/IDynamicConfigHandler"; @@ -21,7 +22,7 @@ import { TelemetryUpdateReason } from "../JavaScriptSDK.Enums/TelemetryUpdateRea import { IAppInsightsCore, ILoadedPlugin } from "../JavaScriptSDK.Interfaces/IAppInsightsCore"; import { IChannelControls } from "../JavaScriptSDK.Interfaces/IChannelControls"; import { IChannelControlsHost } from "../JavaScriptSDK.Interfaces/IChannelControlsHost"; -import { IConfiguration } from "../JavaScriptSDK.Interfaces/IConfiguration"; +import { IConfiguration, IInternalSdkConfiguration } from "../JavaScriptSDK.Interfaces/IConfiguration"; import { ICookieMgr } from "../JavaScriptSDK.Interfaces/ICookieMgr"; import { IDiagnosticLogger } from "../JavaScriptSDK.Interfaces/IDiagnosticLogger"; import { IDistributedTraceContext } from "../JavaScriptSDK.Interfaces/IDistributedTraceContext"; @@ -52,7 +53,7 @@ import { PerfManager, doPerf, getGblPerfMgr } from "./PerfManager"; import { createProcessTelemetryContext, createProcessTelemetryUnloadContext, createProcessTelemetryUpdateContext, createTelemetryProxyChain } from "./ProcessTelemetryContext"; -// import { Statsbeat } from "./StatsBeat"; +import { Statsbeat } from "./StatsBeat"; import { _getPluginState, createDistributedTraceContext, initializePlugins, sortPlugins } from "./TelemetryHelpers"; import { TelemetryInitializerPlugin } from "./TelemetryInitializerPlugin"; import { IUnloadHandlerContainer, UnloadHandler, createUnloadHandlerContainer } from "./UnloadHandlerContainer"; @@ -79,7 +80,9 @@ const defaultConfig: IConfigDefaults = objDeepFreeze({ [STR_CREATE_PERF_MGR]: UNDEFINED_VALUE, loggingLevelConsole: eLoggingSeverity.DISABLED, diagnosticLogInterval: UNDEFINED_VALUE, - _sdk: {stats:false} + _sdk: cfgDfMerge({ + stats: false + }) }); /** @@ -356,11 +359,11 @@ export class AppInsightsCore im _initInMemoMaxSize = rootCfg.initInMemoMaxSize || maxInitQueueSize; // uncomment this until throttle is implemented - // if (config._sdk.stats === true){ - // _statsBeat = _statsBeat || new Statsbeat(); - // } else { - // _statsBeat = null; - // } + if (config._sdk.stats === true){ + _statsBeat = _statsBeat || new Statsbeat(); + } else { + _statsBeat = null; + } _handleIKeyEndpointPromises(rootCfg); From b7a19da269fd7bf4dd4ab886998d4c6b6e306c7f Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 14 Apr 2025 16:36:45 -0700 Subject: [PATCH 45/62] Update StatsBeat.Tests.ts --- shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts index d1b28b258..bd1d25e6e 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts @@ -140,6 +140,7 @@ export class StatsBeatTests extends AITestClass { this.testCase({ name: "StatsBeat: does not send metrics for different endpoints", + useFakeTimers: true, test: () => { // Initialize StatsBeat for a specific endpoint this._statsbeat.initialize(this._core, { @@ -165,7 +166,9 @@ export class StatsBeatTests extends AITestClass { // Count metrics for a different endpoint this._statsbeat.count(200, payloadData, "https://different.endpoint.com"); - + + // Verify that trackStatsbeats is called when the timer fires + this.clock.tick(STATS_COLLECTION_SHORT_INTERVAL + 1); // The count method was called, but it should return early Assert.equal(1, countSpy.callCount, "count method should be called"); Assert.equal(0, this._trackSpy.callCount, "track should not be called for different endpoint"); From 3c18763285faf2f42d3a32ef60728717cf8c8ffd Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 14 Apr 2025 16:41:30 -0700 Subject: [PATCH 46/62] Update StatsBeat.Tests.ts --- .../Tests/Unit/src/StatsBeat.Tests.ts | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts index bd1d25e6e..dafedc25f 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/StatsBeat.Tests.ts @@ -186,10 +186,6 @@ export class StatsBeatTests extends AITestClass { const statsbeat = this._core.getStatsBeat(); Assert.ok(statsbeat, "Statsbeat should be created"); - // Update configuration to disable statsbeat - if (!this._core.config._sdk) { - this._core.config._sdk = {}; - } this._core.config._sdk.stats = false; this.clock.tick(1); // Allow time for config changes to propagate @@ -204,6 +200,27 @@ export class StatsBeatTests extends AITestClass { // Verify that statsbeat is created again const reenabledStatsbeat = this._core.getStatsBeat(); Assert.ok(reenabledStatsbeat, "Statsbeat should be recreated when re-enabled"); + + // Test that statsbeat is not created when disabled with undefined + this._core.config._sdk.stats = undefined; + this.clock.tick(1); // Allow time for config changes to propagate + + // Verify that statsbeat is removed + Assert.ok(!this._core.getStatsBeat(), "Statsbeat should be removed when disabled"); + + // Re-enable statsbeat + this._core.config._sdk.stats = true; + this.clock.tick(1); // Allow time for config changes to propagate + + // Verify that statsbeat is created again + Assert.ok( this._core.getStatsBeat(), "Statsbeat should be recreated when re-enabled"); + + // Test that statsbeat is not created when disabled with null value + this._core.config._sdk.stats = null; + this.clock.tick(1); // Allow time for config changes to propagate + + // Verify that statsbeat is removed + Assert.ok(!this._core.getStatsBeat(), "Statsbeat should be removed when disabled"); } }); } From afd15de84022a395e0cbb17e71e0a323520d7a5f Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 14 Apr 2025 23:35:19 -0700 Subject: [PATCH 47/62] Update StatsBeat.tests.ts --- .../Tests/Unit/src/StatsBeat.tests.ts | 77 +++++++++++-------- 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts b/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts index 574c43986..c1c63cb59 100644 --- a/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts +++ b/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts @@ -1,5 +1,5 @@ import { AITestClass, Assert, PollingAssert } from "@microsoft/ai-test-framework"; -import { AppInsightsCore, IPayloadData, ITelemetryItem, TransportType } from "@microsoft/applicationinsights-core-js"; +import { AppInsightsCore, getWindow, IPayloadData, ITelemetryItem, TransportType } from "@microsoft/applicationinsights-core-js"; import { Sender } from "../../../src/Sender"; import { SinonSpy, SinonStub } from "sinon"; import { ISenderConfig } from "../../../types/applicationinsights-channel-js"; @@ -122,10 +122,11 @@ export class StatsbeatTests extends AITestClass { this.testCaseAsync({ name: "Statsbeat increments success count when fetch sender is called once", useFakeTimers: true, + useFakeServer: true, stepDelay: 100, steps: [ () => { - this.fetchStub = this.sandbox.stub(window, "fetch").callsFake(() => { + this.fetchStub = this.sandbox.stub(window, "fetch").callsFake(() => { // only fetch is supported to stub, why? return Promise.resolve(new Response("{}", { status: 200, statusText: "OK" })); }); @@ -140,6 +141,7 @@ export class StatsbeatTests extends AITestClass { }; this.processTelemetryAndFlush(sender, telemetryItem); + } ].concat(PollingAssert.createPollingAssert(() => { if (this.statsbeatCountSpy.called && this.fetchStub.called) { @@ -181,37 +183,7 @@ export class StatsbeatTests extends AITestClass { }, "Waiting for fetch sender and Statsbeat count to be called") as any) }); - - - // this.testCaseAsync({ - // name: "Statsbeat increments success count for xhr sender",useFakeTimers: true, - // stepDelay: 100, - // steps: [ - // () => { - // let config = this.createSenderConfig(TransportType.Xhr) && {disableSendBeaconSplit: true}; - // const { sender } = this.initializeCoreAndSender(config, "000e0000-e000-0000-a000-000000000000"); - - // const telemetryItem: ITelemetryItem = { - // name: "fake item", - // iKey: "testIkey2;ingestionendpoint=testUrl1", - // baseType: "some type", - // baseData: {} - // }; - // this.processTelemetryAndFlush(sender, telemetryItem); - // QUnit.assert.equal(1, this._getXhrRequests().length, "xhr sender is called"); - - // } - // ].concat(PollingAssert.createPollingAssert(() => { - // if (this.statsbeatCountSpy.called) { - // // this.assertStatsbeatCall(200, "Request_Success_Count"); - // console.log("Statsbeat count called with success count for xhr sender"); - // return true; - // } - // return false; - // }, "Waiting for xhr sender and Statsbeat count to be called", 60, 1000) as any) - // }); - - this.testCaseAsync({ + this.testCaseAsync({ name: "Statsbeat increments success count for beacon sender", useFakeTimers: true, stepDelay: 100, @@ -242,5 +214,42 @@ export class StatsbeatTests extends AITestClass { return false; }, "Waiting for beacon sender and Statsbeat count to be called") as any) }); - } + + + this.testCaseAsync({ + name: "Statsbeat increments success count for xhr sender", + useFakeTimers: true, + useFakeServer: true, + stepDelay: 100, + fakeServerAutoRespond: true, + steps: [ + () => { + let window = getWindow(); + let fakeXMLHttpRequest = (window as any).XMLHttpRequest; // why we do this? + let config = this.createSenderConfig(TransportType.Xhr) && {disableSendBeaconSplit: true}; + const { sender } = this.initializeCoreAndSender(config, "000e0000-e000-0000-a000-000000000000"); + console.log("xhr sender called", this._getXhrRequests().length); + + const telemetryItem: ITelemetryItem = { + name: "fake item", + iKey: "testIkey2;ingestionendpoint=testUrl1", + baseType: "some type", + baseData: {} + }; + this.processTelemetryAndFlush(sender, telemetryItem); + QUnit.assert.equal(1, this._getXhrRequests().length, "xhr sender is called"); + console.log("xhr sender is called", this._getXhrRequests().length); + (window as any).XMLHttpRequest = fakeXMLHttpRequest; + + } + ].concat(PollingAssert.createPollingAssert(() => { + if (this.statsbeatCountSpy.called) { + this.assertStatsbeatCall(200, "Request_Success_Count"); + console.log("Statsbeat count called with success count for xhr sender"); + return true; + } + return false; + }, "Waiting for xhr sender and Statsbeat count to be called", 60, 1000) as any) + }); +} } \ No newline at end of file From b3a684aa8c8dbf123e4064208b40c74f132410a9 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 14 Apr 2025 23:49:59 -0700 Subject: [PATCH 48/62] Update Sender.ts --- .../src/Sender.ts | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 6b5b7653f..2c6fca910 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -585,6 +585,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { "Telemetry transmission failed, some telemetry will be lost: " + getExceptionName(e), { exception: dumpObj(e) }); } + // potential place to call countException q3 } } @@ -691,25 +692,25 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } const responseText = _getResponseText(xdr); let statsbeat = _getStatsBeat(); - var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - if (xdr && (responseText + "" === "200" || responseText === "")) { - _consecutiveErrors = 0; - if (statsbeat) { + if (statsbeat) { + var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; + if (xdr && (responseText + "" === "200" || responseText === "")) { + _consecutiveErrors = 0; statsbeat.count(200, payload, endpointHost); - } - } else { - const results = parseResponse(responseText); - - if (results && results.itemsReceived && results.itemsReceived > results.itemsAccepted - && !_isRetryDisabled) { - if (statsbeat) { - statsbeat.count(201, payload, endpointHost); - } } else { - statsbeat.count(201, payload, endpointHost); + const results = parseResponse(responseText); + + if (results && results.itemsReceived && results.itemsReceived > results.itemsAccepted + && !_isRetryDisabled) { + statsbeat.count(206, payload, endpointHost); + } else { + // should count error code here, but we don't have error code ?q1 + } } } + + return _xdrOnLoad(xdr, payloadArr); }, @@ -741,9 +742,8 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let statsbeat = _getStatsBeat(); if (statsbeat) { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - statsbeat.count(-1, data, endpointHost); + statsbeat.count(-1, data, endpointHost); // do not have error code here ?q2 } - console.log("Beacon onRetry", data, canSend); return _onBeaconRetry(data, onComplete, canSend); } From fafad407e0593e80395f2a49024890dfcc983f86 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 14 Apr 2025 23:52:52 -0700 Subject: [PATCH 49/62] Update Sender.ts --- channels/applicationinsights-channel-js/src/Sender.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 2c6fca910..ec705e25e 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -273,7 +273,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { // getExtCfg only finds undefined values from core let senderConfig = ctx.getExtCfg(identifier, defaultAppInsightsChannelConfig); let curExtUrl = senderConfig.endpointUrl; - _statsBeat = core.getStatsBeat(); + _statsBeat = _getStatsBeat(); // if it is not inital change (_endpointUrl has value) // if current sender endpoint url is not changed directly From 94539c1b46cdbcdee383ea95c66acd84770bbf50 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 14 Apr 2025 23:53:11 -0700 Subject: [PATCH 50/62] Update AppInsightsCore.ts --- .../src/JavaScriptSDK/AppInsightsCore.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index b589f9ef1..8331ede86 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -359,11 +359,11 @@ export class AppInsightsCore im _initInMemoMaxSize = rootCfg.initInMemoMaxSize || maxInitQueueSize; // uncomment this until throttle is implemented - if (config._sdk.stats === true){ - _statsBeat = _statsBeat || new Statsbeat(); - } else { - _statsBeat = null; - } + // if (config._sdk.stats === true){ + // _statsBeat = _statsBeat || new Statsbeat(); + // } else { + // _statsBeat = null; + // } _handleIKeyEndpointPromises(rootCfg); From ce2070b97feb88b57f8f6fd40e76335621738bb7 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 15 Apr 2025 14:25:35 -0700 Subject: [PATCH 51/62] Update AnalyticsExtensionSize.tests.ts --- .../Tests/Unit/src/AnalyticsExtensionSize.tests.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/applicationinsights-analytics-js/Tests/Unit/src/AnalyticsExtensionSize.tests.ts b/extensions/applicationinsights-analytics-js/Tests/Unit/src/AnalyticsExtensionSize.tests.ts index d72053af7..f61505caf 100644 --- a/extensions/applicationinsights-analytics-js/Tests/Unit/src/AnalyticsExtensionSize.tests.ts +++ b/extensions/applicationinsights-analytics-js/Tests/Unit/src/AnalyticsExtensionSize.tests.ts @@ -51,7 +51,7 @@ function _checkSize(checkType: string, maxSize: number, size: number, isNightly: } export class AnalyticsExtensionSizeCheck extends AITestClass { - private readonly MAX_DEFLATE_SIZE = 24; + private readonly MAX_DEFLATE_SIZE = 25; private readonly rawFilePath = "../dist/es5/applicationinsights-analytics-js.min.js"; private readonly prodFilePaath = "../browser/es5/applicationinsights-analytics-js.min.js" From f7605dfab3d9f91e97d142d75993a356ac0087ac Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Wed, 16 Apr 2025 14:58:35 -0700 Subject: [PATCH 52/62] add status code 499 --- .../Tests/Unit/src/StatsBeat.tests.ts | 4 ++-- .../src/Sender.ts | 4 ++-- .../test/Unit/src/FileSizeCheckTest.ts | 2 +- .../src/JavaScriptSDK/SenderPostManager.ts | 18 ++++++++++-------- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts b/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts index c1c63cb59..b204ecc86 100644 --- a/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts +++ b/channels/applicationinsights-channel-js/Tests/Unit/src/StatsBeat.tests.ts @@ -153,7 +153,7 @@ export class StatsbeatTests extends AITestClass { }); this.testCaseAsync({ - name: "Statsbeat increments retry count when fetch sender is called once", + name: "Statsbeat increments throttle count when fetch sender is called with status 439", useFakeTimers: true, stepDelay: 100, steps: [ @@ -176,7 +176,7 @@ export class StatsbeatTests extends AITestClass { } ].concat(PollingAssert.createPollingAssert(() => { if (this.statsbeatCountSpy.called && this.fetchStub.called) { - this.assertStatsbeatCall(400, "failure"); + this.assertStatsbeatCall(439, "Throttle_Count"); return true; } return false; diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index ec705e25e..3013dc72b 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -704,7 +704,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { && !_isRetryDisabled) { statsbeat.count(206, payload, endpointHost); } else { - // should count error code here, but we don't have error code ?q1 + statsbeat.count(499, payload, endpointHost); } } } @@ -742,7 +742,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let statsbeat = _getStatsBeat(); if (statsbeat) { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - statsbeat.count(-1, data, endpointHost); // do not have error code here ?q2 + statsbeat.count(499, data, endpointHost); } return _onBeaconRetry(data, onComplete, canSend); } diff --git a/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts b/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts index d2fa9d3ac..68e9830d4 100644 --- a/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts +++ b/shared/1ds-core-js/test/Unit/src/FileSizeCheckTest.ts @@ -51,7 +51,7 @@ function _checkSize(checkType: string, maxSize: number, size: number, isNightly: } export class FileSizeCheckTest extends AITestClass { - private readonly MAX_BUNDLE_SIZE = 69; + private readonly MAX_BUNDLE_SIZE = 70; private readonly MAX_DEFLATE_SIZE = 29; private readonly bundleFilePath = "../bundle/es5/ms.core.min.js"; diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts b/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts index f3fdd2bdc..636936a28 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts @@ -429,12 +429,14 @@ export class SenderPostManager { } - function _handleError(res?: string) { + function _handleError(res?: string, statusCode?: number) { // In case there is an error in the request. Set the status to 0 for 1ds and 400 for appInsights // so that the events can be retried later. - - _doOnComplete(oncomplete, _isOneDs? 0 : 400, {}, _isOneDs? STR_EMPTY: res); - + if (statusCode) { + _doOnComplete(oncomplete, statusCode, {}, _isOneDs? STR_EMPTY: res); + } else { + _doOnComplete(oncomplete, _isOneDs? 0 : 400, {}, _isOneDs? STR_EMPTY: res); + } } function _onFetchComplete(response: Response, payload?: IPayloadData, value?: string) { @@ -468,7 +470,7 @@ export class SenderPostManager { */ if (!_isOneDs && !response.ok) { // this is for appInsights only - _handleError(response.statusText); + _handleError(response.statusText, response.status); resolveFunc && resolveFunc(false); } else { if (_isOneDs && !response.body) { @@ -484,19 +486,19 @@ export class SenderPostManager { } } catch (e) { - _handleError(dumpObj(e)); + _handleError(dumpObj(e), response.status); rejectFunc && rejectFunc(e); } } else { - _handleError(result.reason && result.reason.message); + _handleError(result.reason && result.reason.message, 499); rejectFunc && rejectFunc(result.reason); } } }); } catch (e) { if (!responseHandled) { - _handleError(dumpObj(e)); + _handleError(dumpObj(e), 499); rejectFunc && rejectFunc(e); } } From dd32dc249e4e29cbbae443724227aabcb9e728da Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Wed, 16 Apr 2025 15:43:37 -0700 Subject: [PATCH 53/62] endpointurl update --- .../src/Sender.ts | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index 3013dc72b..da12d2b43 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -288,14 +288,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } } - if (config._sdk && config._sdk.stats === true && _statsBeat && !_statsBeat.isInitialized()) { - let statsBeatConfig = { - ikey: senderConfig.instrumentationKey, - endpoint: urlParseUrl(senderConfig.endpointUrl).hostname, - version: EnvelopeCreator.Version - } as IStatsBeatConfig; - _statsBeat.initialize(core, statsBeatConfig); - } let corsPolicy = senderConfig.corsPolicy; if (corsPolicy){ if (corsPolicy === "same-origin" || corsPolicy === "same-site" || corsPolicy === "cross-origin") { @@ -324,6 +316,15 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { _endpointUrl = _orgEndpointUrl = senderConfig.endpointUrl; } + if (config._sdk && config._sdk.stats === true && _statsBeat && !_statsBeat.isInitialized()) { + let statsBeatConfig = { + ikey: senderConfig.instrumentationKey, + endpoint: _endpointUrl, + version: EnvelopeCreator.Version + } as IStatsBeatConfig; + _statsBeat.initialize(core, statsBeatConfig); + } + // or is not string if (core.activeStatus() === ActiveStatus.PENDING) { // waiting for core promises to be resolved @@ -696,15 +697,15 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; if (xdr && (responseText + "" === "200" || responseText === "")) { _consecutiveErrors = 0; - statsbeat.count(200, payload, endpointHost); + statsbeat.count(200, payload, _endpointUrl); } else { const results = parseResponse(responseText); if (results && results.itemsReceived && results.itemsReceived > results.itemsAccepted && !_isRetryDisabled) { - statsbeat.count(206, payload, endpointHost); + statsbeat.count(206, payload, _endpointUrl); } else { - statsbeat.count(499, payload, endpointHost); + statsbeat.count(499, payload, _endpointUrl); } } } @@ -721,8 +722,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } let statsbeat = _getStatsBeat(); if (statsbeat) { - var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - statsbeat.count(response.status, payload, endpointHost); + statsbeat.count(response.status, payload, _endpointUrl); } return _checkResponsStatus(response.status, payloadArr, response.url, payloadArr.length, response.statusText, resValue || ""); }, @@ -734,15 +734,14 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let statsbeat = _getStatsBeat(); if (statsbeat && request.readyState === 4) { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - statsbeat.count(request.status, payload, endpointHost); + statsbeat.count(request.status, payload, _endpointUrl); } return _xhrReadyStateChange(request, payloadArr, payloadArr.length); }, beaconOnRetry: (data: IPayloadData, onComplete: OnCompleteCallback, canSend: (payload: IPayloadData, oncomplete: OnCompleteCallback, sync?: boolean) => boolean) => { let statsbeat = _getStatsBeat(); if (statsbeat) { - var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - statsbeat.count(499, data, endpointHost); + statsbeat.count(499, data, _endpointUrl); } return _onBeaconRetry(data, onComplete, canSend); } @@ -990,7 +989,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let statsbeat = _getStatsBeat(); if (statsbeat) { var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; - statsbeat.count(status, payloadData, endpointHost); + statsbeat.count(status, payloadData, _endpointUrl); } return _getOnComplete(payload, status, headers, response); } From 90bb3f13b43b78b754f4ab6066f8b09dbe9b6734 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Wed, 16 Apr 2025 16:42:58 -0700 Subject: [PATCH 54/62] change the way of initialize --- .../src/Sender.ts | 35 ++++++++----------- .../IAppInsightsCore.ts | 4 +-- .../JavaScriptSDK.Interfaces/IStatsBeat.ts | 1 + .../src/JavaScriptSDK/AppInsightsCore.ts | 22 +++++++----- .../src/JavaScriptSDK/StatsBeat.ts | 11 ++++-- 5 files changed, 40 insertions(+), 33 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index da12d2b43..ed896be2b 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -2,17 +2,17 @@ import dynamicProto from "@microsoft/dynamicproto-js"; import { BreezeChannelIdentifier, DEFAULT_BREEZE_ENDPOINT, DEFAULT_BREEZE_PATH, Event, Exception, IConfig, IEnvelope, IOfflineListener, ISample, IStorageBuffer, Metric, PageView, PageViewPerformance, ProcessLegacy, RemoteDependencyData, RequestHeaders, SampleRate, Trace, - createOfflineListener, eRequestHeaders, isInternalApplicationInsightsEndpoint, urlParseUrl, utlCanUseSessionStorage, utlSetStoragePrefix + createOfflineListener, eRequestHeaders, isInternalApplicationInsightsEndpoint, utlCanUseSessionStorage, utlSetStoragePrefix } from "@microsoft/applicationinsights-common"; import { ActiveStatus, BaseTelemetryPlugin, IAppInsightsCore, IBackendResponse, IChannelControls, IConfigDefaults, IConfiguration, IDiagnosticLogger, IInternalOfflineSupport, INotificationManager, IPayloadData, IPlugin, IProcessTelemetryContext, - IProcessTelemetryUnloadContext, IStatsBeat, IStatsBeatConfig, IStatsBeatEvent, ITelemetryItem, ITelemetryPluginChain, - ITelemetryUnloadState, IXDomainRequest, IXHROverride, OnCompleteCallback, SendPOSTFunction, SendRequestReason, SenderPostManager, - TransportType, _ISendPostMgrConfig, _ISenderOnComplete, _eInternalMessageId, _throwInternal, _warnToConsole, arrForEach, cfgDfBoolean, - cfgDfValidate, createProcessTelemetryContext, createUniqueNamespace, dateNow, dumpObj, eLoggingSeverity, formatErrorMessageXdr, - formatErrorMessageXhr, getExceptionName, getIEVersion, isArray, isBeaconsSupported, isFetchSupported, isNullOrUndefined, - mergeEvtNamespace, objExtend, onConfigChange, parseResponse, prependTransports, runTargetUnload + IProcessTelemetryUnloadContext, IStatsBeatConfig, IStatsBeatEvent, ITelemetryItem, ITelemetryPluginChain, ITelemetryUnloadState, + IXDomainRequest, IXHROverride, OnCompleteCallback, SendPOSTFunction, SendRequestReason, SenderPostManager, TransportType, + _ISendPostMgrConfig, _ISenderOnComplete, _eInternalMessageId, _throwInternal, _warnToConsole, arrForEach, cfgDfBoolean, cfgDfValidate, + createProcessTelemetryContext, createUniqueNamespace, dateNow, dumpObj, eLoggingSeverity, formatErrorMessageXdr, formatErrorMessageXhr, + getExceptionName, getIEVersion, isArray, isBeaconsSupported, isFetchSupported, isNullOrUndefined, mergeEvtNamespace, objExtend, + onConfigChange, parseResponse, prependTransports, runTargetUnload } from "@microsoft/applicationinsights-core-js"; import { IPromise } from "@nevware21/ts-async"; import { @@ -164,7 +164,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let _offlineListener: IOfflineListener; let _evtNamespace: string | string[]; let _endpointUrl: string; - let _statsBeat: IStatsBeat; let _orgEndpointUrl: string; let _maxBatchSizeInBytes: number; let _beaconSupported: boolean; @@ -273,7 +272,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { // getExtCfg only finds undefined values from core let senderConfig = ctx.getExtCfg(identifier, defaultAppInsightsChannelConfig); let curExtUrl = senderConfig.endpointUrl; - _statsBeat = _getStatsBeat(); // if it is not inital change (_endpointUrl has value) // if current sender endpoint url is not changed directly @@ -316,14 +314,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { _endpointUrl = _orgEndpointUrl = senderConfig.endpointUrl; } - if (config._sdk && config._sdk.stats === true && _statsBeat && !_statsBeat.isInitialized()) { - let statsBeatConfig = { - ikey: senderConfig.instrumentationKey, - endpoint: _endpointUrl, - version: EnvelopeCreator.Version - } as IStatsBeatConfig; - _statsBeat.initialize(core, statsBeatConfig); - } + _getStatsBeat(); // first call will initialize the statsbeat object // or is not string if (core.activeStatus() === ActiveStatus.PENDING) { @@ -662,7 +653,12 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } function _getStatsBeat() { - return _self.core.getStatsBeat(); + let statsBeatConfig = { + ikey: _self._senderConfig.instrumentationKey, + endpoint: _endpointUrl, + version: EnvelopeCreator.Version + } as IStatsBeatConfig; + return _self.core.getStatsBeat(statsBeatConfig); } function _xdrOnLoad (xdr: IXDomainRequest, payload: IInternalStorageItem[]) { @@ -694,7 +690,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { const responseText = _getResponseText(xdr); let statsbeat = _getStatsBeat(); if (statsbeat) { - var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; if (xdr && (responseText + "" === "200" || responseText === "")) { _consecutiveErrors = 0; statsbeat.count(200, payload, _endpointUrl); @@ -733,7 +728,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { } let statsbeat = _getStatsBeat(); if (statsbeat && request.readyState === 4) { - var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; statsbeat.count(request.status, payload, _endpointUrl); } return _xhrReadyStateChange(request, payloadArr, payloadArr.length); @@ -988,7 +982,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { let onComplete = (status: number, headers: {[headerName: string]: string;}, response?: string) => { let statsbeat = _getStatsBeat(); if (statsbeat) { - var endpointHost = urlParseUrl(_self._senderConfig.endpointUrl).hostname; statsbeat.count(status, payloadData, _endpointUrl); } return _getOnComplete(payload, status, headers, response); diff --git a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IAppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IAppInsightsCore.ts index 12dcd085b..80893b388 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IAppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK.Interfaces/IAppInsightsCore.ts @@ -16,7 +16,7 @@ import { INotificationListener } from "./INotificationListener"; import { INotificationManager } from "./INotificationManager"; import { IPerfManagerProvider } from "./IPerfManager"; import { IProcessTelemetryContext } from "./IProcessTelemetryContext"; -import { IStatsBeat } from "./IStatsBeat"; +import { IStatsBeat, IStatsBeatConfig } from "./IStatsBeat"; import { ITelemetryInitializerHandler, TelemetryInitializerFunction } from "./ITelemetryInitializers"; import { ITelemetryItem } from "./ITelemetryItem"; import { IPlugin, ITelemetryPlugin } from "./ITelemetryPlugin"; @@ -125,7 +125,7 @@ export interface IAppInsightsCore im _initInMemoMaxSize = rootCfg.initInMemoMaxSize || maxInitQueueSize; // uncomment this until throttle is implemented - // if (config._sdk.stats === true){ - // _statsBeat = _statsBeat || new Statsbeat(); - // } else { - // _statsBeat = null; - // } + if (config._sdk.stats === true){ + _statsBeat = _statsBeat || new Statsbeat(); + } else { + _statsBeat = null; + } _handleIKeyEndpointPromises(rootCfg); @@ -514,7 +514,13 @@ export class AppInsightsCore im return _perfManager || _cfgPerfManager || getGblPerfMgr(); }; - _self.getStatsBeat = (): IStatsBeat => { + _self.getStatsBeat = (statsBeatConfig?: IStatsBeatConfig): IStatsBeat => { + // create a new statsbeat if not initialize yet or the endpoint is different + // otherwise, return the existing one, or null + if (statsBeatConfig && _statsBeat && _statsBeat.getEndpoint() !== statsBeatConfig.endpoint) { + // _statsBeat = new Statsbeat(); + _statsBeat.initialize(this, statsBeatConfig); + } return _statsBeat; }; @@ -1449,7 +1455,7 @@ export class AppInsightsCore im return null; } - public getStatsBeat(): IStatsBeat { + public getStatsBeat(statsBeatConfig?: IStatsBeatConfig): IStatsBeat { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging return null; } diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts index 26d30d9b1..97ffd8d9c 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/StatsBeat.ts @@ -22,7 +22,6 @@ export class Statsbeat implements IStatsBeat { let _language: string; let _sdkVersion: string; let _os: string; - let _runTimeVersion: string; dynamicProto(Statsbeat, this, (_self, _base) => { _self.initialize = (core: IAppInsightsCore, statsBeatConfig: IStatsBeatConfig) => { _core = core; @@ -58,7 +57,9 @@ export class Statsbeat implements IStatsBeat { _setupTimer(); }; - + _self.getEndpoint = (): string => { + return _networkCounter?_networkCounter.host:null; + } _self.countException = (endpoint: string, exceptionType: string) => { if (!_isEnabled || !_checkEndpoint(endpoint)) { @@ -193,4 +194,10 @@ export class Statsbeat implements IStatsBeat { public countException(endpoint: string, exceptionType: string) { // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging } + + public getEndpoint(): string { + // @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging + return null; + } + } From f2a4e765674b13d7a1ed42593968b17c3a3cfabe Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Wed, 16 Apr 2025 17:11:11 -0700 Subject: [PATCH 55/62] Update AppInsightsCoreSize.Tests.ts --- .../Tests/Unit/src/AppInsightsCoreSize.Tests.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts b/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts index c8da7b41d..e4a746d9b 100644 --- a/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts +++ b/shared/AppInsightsCore/Tests/Unit/src/AppInsightsCoreSize.Tests.ts @@ -53,8 +53,8 @@ function _checkSize(checkType: string, maxSize: number, size: number, isNightly: export class AppInsightsCoreSizeCheck extends AITestClass { private readonly MAX_RAW_SIZE = 67; private readonly MAX_BUNDLE_SIZE = 67; - private readonly MAX_RAW_DEFLATE_SIZE = 28; - private readonly MAX_BUNDLE_DEFLATE_SIZE = 28; + private readonly MAX_RAW_DEFLATE_SIZE = 29; + private readonly MAX_BUNDLE_DEFLATE_SIZE = 29; private readonly rawFilePath = "../dist/es5/applicationinsights-core-js.min.js"; private readonly prodFilePath = "../browser/es5/applicationinsights-core-js.min.js"; From 6161b9eb51755d979e47427c6d665edb349884be Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Wed, 16 Apr 2025 17:13:15 -0700 Subject: [PATCH 56/62] Update AppInsightsCore.ts --- .../src/JavaScriptSDK/AppInsightsCore.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index d94ea961f..9e764d399 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -359,11 +359,11 @@ export class AppInsightsCore im _initInMemoMaxSize = rootCfg.initInMemoMaxSize || maxInitQueueSize; // uncomment this until throttle is implemented - if (config._sdk.stats === true){ - _statsBeat = _statsBeat || new Statsbeat(); - } else { - _statsBeat = null; - } + // if (config._sdk.stats === true){ + // _statsBeat = _statsBeat || new Statsbeat(); + // } else { + // _statsBeat = null; + // } _handleIKeyEndpointPromises(rootCfg); From 1a5a97db7d5e21ff33ee513cf9f711c2ee701e10 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Mon, 21 Apr 2025 21:03:07 -0700 Subject: [PATCH 57/62] re-create --- channels/applicationinsights-channel-js/src/Sender.ts | 2 -- .../src/JavaScriptSDK/AppInsightsCore.ts | 10 ++++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/channels/applicationinsights-channel-js/src/Sender.ts b/channels/applicationinsights-channel-js/src/Sender.ts index ed896be2b..5a06d257c 100644 --- a/channels/applicationinsights-channel-js/src/Sender.ts +++ b/channels/applicationinsights-channel-js/src/Sender.ts @@ -314,8 +314,6 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls { _endpointUrl = _orgEndpointUrl = senderConfig.endpointUrl; } - _getStatsBeat(); // first call will initialize the statsbeat object - // or is not string if (core.activeStatus() === ActiveStatus.PENDING) { // waiting for core promises to be resolved diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts index 9e764d399..261ce8d55 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts @@ -517,10 +517,12 @@ export class AppInsightsCore im _self.getStatsBeat = (statsBeatConfig?: IStatsBeatConfig): IStatsBeat => { // create a new statsbeat if not initialize yet or the endpoint is different // otherwise, return the existing one, or null - if (statsBeatConfig && _statsBeat && _statsBeat.getEndpoint() !== statsBeatConfig.endpoint) { - // _statsBeat = new Statsbeat(); - _statsBeat.initialize(this, statsBeatConfig); - } + + // uncomment this until throttle is implemented + // if (statsBeatConfig && this.config._sdk.stats === true && _statsBeat && _statsBeat.getEndpoint() !== statsBeatConfig.endpoint) { + // _statsBeat = new Statsbeat(); + // _statsBeat.initialize(this, statsBeatConfig); + // } return _statsBeat; }; From 516d6c3c2a3b1956335724925da4773be4efd309 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 22 Apr 2025 01:13:51 -0700 Subject: [PATCH 58/62] Update cfgsynchelper.tests.ts --- .../Tests/Unit/src/cfgsynchelper.tests.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsynchelper.tests.ts b/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsynchelper.tests.ts index f786e5039..5dd82cb55 100644 --- a/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsynchelper.tests.ts +++ b/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsynchelper.tests.ts @@ -101,8 +101,6 @@ export class CfgSyncHelperTests extends AITestClass { extensions:[{isFlushInvoked:false,isTearDownInvoked:false,isResumeInvoked:false,isPauseInvoked:false,identifier:"Sender",priority:1001}], channels:[], extensionConfig:{}, - _sdk: { - stats: false}, enableDebug: false } From b156b56f6596341c5c5f9dc656a9866bab5c6caf Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 22 Apr 2025 01:43:54 -0700 Subject: [PATCH 59/62] Update SenderPostManager.ts --- .../src/JavaScriptSDK/SenderPostManager.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts b/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts index 636936a28..abf481b4e 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts @@ -470,7 +470,11 @@ export class SenderPostManager { */ if (!_isOneDs && !response.ok) { // this is for appInsights only - _handleError(response.statusText, response.status); + if (response.status){ + _handleError(response.statusText, response.status); + } else { + _handleError(response.statusText, 499); + } resolveFunc && resolveFunc(false); } else { if (_isOneDs && !response.body) { @@ -486,7 +490,11 @@ export class SenderPostManager { } } catch (e) { - _handleError(dumpObj(e), response.status); + if (response.status){ + _handleError(dumpObj(e), response.status); + } else { + _handleError(dumpObj(e), 499); + } rejectFunc && rejectFunc(e); } From 3fa831039ff4bfd0e85274e265826596b57cebed Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 22 Apr 2025 02:20:08 -0700 Subject: [PATCH 60/62] Update SenderPostManager.ts --- .../src/JavaScriptSDK/SenderPostManager.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts b/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts index abf481b4e..7a8bd7c93 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts @@ -490,11 +490,12 @@ export class SenderPostManager { } } catch (e) { - if (response.status){ - _handleError(dumpObj(e), response.status); - } else { - _handleError(dumpObj(e), 499); - } + // if (response.status){ + // _handleError(dumpObj(e), response.status); + // } else { + // _handleError(dumpObj(e), 499); + // } + _handleError(dumpObj(e), 499); rejectFunc && rejectFunc(e); } From 73c4a96a864bf1542d9a9328d82b103b5834f350 Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 22 Apr 2025 15:51:12 -0700 Subject: [PATCH 61/62] check statuscode --- .../Tests/Unit/src/cfgsynchelper.tests.ts | 5 ++++- .../src/JavaScriptSDK/SenderPostManager.ts | 13 ++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsynchelper.tests.ts b/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsynchelper.tests.ts index 5dd82cb55..0884aa9a4 100644 --- a/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsynchelper.tests.ts +++ b/extensions/applicationinsights-cfgsync-js/Tests/Unit/src/cfgsynchelper.tests.ts @@ -101,7 +101,10 @@ export class CfgSyncHelperTests extends AITestClass { extensions:[{isFlushInvoked:false,isTearDownInvoked:false,isResumeInvoked:false,isPauseInvoked:false,identifier:"Sender",priority:1001}], channels:[], extensionConfig:{}, - enableDebug: false + _sdk: { + stats: false + }, + enableDebug: false, } let core = new AppInsightsCore(); diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts b/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts index 7a8bd7c93..714c9b50a 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts @@ -433,7 +433,7 @@ export class SenderPostManager { // In case there is an error in the request. Set the status to 0 for 1ds and 400 for appInsights // so that the events can be retried later. if (statusCode) { - _doOnComplete(oncomplete, statusCode, {}, _isOneDs? STR_EMPTY: res); + _doOnComplete(oncomplete, _isOneDs? 0 : statusCode, {}, _isOneDs? STR_EMPTY: res); } else { _doOnComplete(oncomplete, _isOneDs? 0 : 400, {}, _isOneDs? STR_EMPTY: res); } @@ -490,12 +490,11 @@ export class SenderPostManager { } } catch (e) { - // if (response.status){ - // _handleError(dumpObj(e), response.status); - // } else { - // _handleError(dumpObj(e), 499); - // } - _handleError(dumpObj(e), 499); + if (response.status){ + _handleError(dumpObj(e), response.status); + } else { + _handleError(dumpObj(e), 499); + } rejectFunc && rejectFunc(e); } From 318d41f54ab51a12e9b313d5800f06736322e59a Mon Sep 17 00:00:00 2001 From: siyuniu-ms Date: Tue, 22 Apr 2025 17:09:02 -0700 Subject: [PATCH 62/62] update response check --- shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts b/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts index 714c9b50a..40d1d5be9 100644 --- a/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts +++ b/shared/AppInsightsCore/src/JavaScriptSDK/SenderPostManager.ts @@ -490,7 +490,7 @@ export class SenderPostManager { } } catch (e) { - if (response.status){ + if (response && response.status){ _handleError(dumpObj(e), response.status); } else { _handleError(dumpObj(e), 499);