[Main][Task]27939476: Initialization with iKey and endpoint to be promises (#2340)

* add init with promise

* update

* udpate

* udpate

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update
This commit is contained in:
Karlie-777 2024-06-25 17:23:34 -07:00 коммит произвёл GitHub
Родитель 40b150a3c8
Коммит db5e084edd
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
24 изменённых файлов: 1678 добавлений и 173 удалений

Просмотреть файл

@ -8,6 +8,7 @@
"eBatchDiscardedReason",
"FeatureOptInMode",
"CdnFeatureMode",
"eActiveStatus",
"eLoggingSeverity",
"_eInternalMessageId",
"SendRequestReason",

Просмотреть файл

@ -5,10 +5,10 @@ import { Snippet } from "../../../src/Snippet";
import { utlRemoveSessionStorage } from "@microsoft/applicationinsights-common";
export class AISKUSizeCheck extends AITestClass {
private readonly MAX_RAW_SIZE = 141;
private readonly MAX_BUNDLE_SIZE = 141;
private readonly MAX_RAW_DEFLATE_SIZE = 57;
private readonly MAX_BUNDLE_DEFLATE_SIZE = 57;
private readonly MAX_RAW_SIZE = 143;
private readonly MAX_BUNDLE_SIZE = 143;
private readonly MAX_RAW_DEFLATE_SIZE = 58;
private readonly MAX_BUNDLE_DEFLATE_SIZE = 58;
private readonly rawFilePath = "../dist/es5/applicationinsights-web.min.js";
// Automatically updated by version scripts
private readonly currentVer = "3.2.2";

Просмотреть файл

@ -3,8 +3,9 @@ import { SinonSpy } from 'sinon';
import { ApplicationInsights } from '../../../src/applicationinsights-web'
import { Sender } from '@microsoft/applicationinsights-channel-js';
import { IDependencyTelemetry, ContextTagKeys, Event, Trace, Exception, Metric, PageView, PageViewPerformance, RemoteDependencyData, DistributedTracingModes, RequestHeaders, IAutoExceptionTelemetry, BreezeChannelIdentifier, IConfig } from '@microsoft/applicationinsights-common';
import { ITelemetryItem, getGlobal, newId, dumpObj, BaseTelemetryPlugin, IProcessTelemetryContext, __getRegisteredEvents, arrForEach, IConfiguration, FeatureOptInMode } from "@microsoft/applicationinsights-core-js";
import { ITelemetryItem, getGlobal, newId, dumpObj, BaseTelemetryPlugin, IProcessTelemetryContext, __getRegisteredEvents, arrForEach, IConfiguration, ActiveStatus, FeatureOptInMode } from "@microsoft/applicationinsights-core-js";
import { TelemetryContext } from '@microsoft/applicationinsights-properties-js';
import { createAsyncResolvedPromise } from '@nevware21/ts-async';
import { CONFIG_ENDPOINT_URL } from '../../../src/InternalConstants';
import { OfflineChannel } from '@microsoft/applicationinsights-offlinechannel-js';
@ -47,6 +48,7 @@ export class ApplicationInsightsTests extends AITestClass {
private _appId: string;
private _ctx: any;
constructor(testName?: string) {
super(testName || "ApplicationInsightsTests");
}
@ -250,6 +252,217 @@ export class ApplicationInsightsTests extends AITestClass {
}
});
this.testCaseAsync({
name: "Init: init with cs promise, change with cs string",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
// unload previous one first
let oriInst = this._ai;
if (oriInst && oriInst.unload) {
// force unload
oriInst.unload(false);
}
if (oriInst && oriInst["dependencies"]) {
oriInst["dependencies"].teardown();
}
this._config = this._getTestConfig(this._sessionPrefix);
let csPromise = createAsyncResolvedPromise("InstrumentationKey=testIkey;ingestionendpoint=testUrl");
this._config.connectionString = csPromise;
this._config.initTimeOut= 80000;
let init = new ApplicationInsights({
config: this._config
});
init.loadAppInsights();
this._ai = init;
let config = this._ai.config;
let core = this._ai.core;
let status = core.activeStatus && core.activeStatus();
Assert.equal(status, ActiveStatus.PENDING, "status should be set to pending");
config.connectionString = "InstrumentationKey=testIkey1;ingestionendpoint=testUrl1";
this.clock.tick(1);
status = core.activeStatus && core.activeStatus();
// promise is not resolved, no new changes applied
Assert.equal(status, ActiveStatus.PENDING, "status should be set to pending test1");
}].concat(PollingAssert.createPollingAssert(() => {
let core = this._ai.core
let activeStatus = core.activeStatus && core.activeStatus();
if (activeStatus === ActiveStatus.ACTIVE) {
Assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set");
Assert.equal("testUrl/v2/track", core.config.endpointUrl ,"endpoint shoule be set");
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCaseAsync({
name: "Init: init with cs promise and offline channel",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
// unload previous one first
let oriInst = this._ai;
if (oriInst && oriInst.unload) {
// force unload
oriInst.unload(false);
}
if (oriInst && oriInst["dependencies"]) {
oriInst["dependencies"].teardown();
}
this._config = this._getTestConfig(this._sessionPrefix);
let csPromise = createAsyncResolvedPromise("InstrumentationKey=testIkey;ingestionendpoint=testUrl");
this._config.connectionString = csPromise;
let offlineChannel = new OfflineChannel();
this._config.channels = [[offlineChannel]];
this._config.initTimeOut= 80000;
let init = new ApplicationInsights({
config: this._config
});
init.loadAppInsights();
this._ai = init;
let config = this._ai.config;
let core = this._ai.core;
let status = core.activeStatus && core.activeStatus();
Assert.equal(status, ActiveStatus.PENDING, "status should be set to pending");
config.connectionString = "InstrumentationKey=testIkey1;ingestionendpoint=testUrl1"
this.clock.tick(1);
status = core.activeStatus && core.activeStatus();
Assert.equal(status, ActiveStatus.PENDING, "status should be set to pending test1");
}].concat(PollingAssert.createPollingAssert(() => {
let core = this._ai.core
let activeStatus = core.activeStatus && core.activeStatus();
if (activeStatus === ActiveStatus.ACTIVE) {
Assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set");
Assert.equal("testUrl/v2/track", core.config.endpointUrl ,"endpoint shoule be set");
let sendChannel = this._ai.getPlugin(BreezeChannelIdentifier);
let offlineChannelPlugin = this._ai.getPlugin("OfflineChannel").plugin;
Assert.equal(sendChannel.plugin.isInitialized(), true, "sender is initialized");
Assert.equal(offlineChannelPlugin.isInitialized(), true, "offline channel is initialized");
let urlConfig = offlineChannelPlugin["_getDbgPlgTargets"]()[0];
Assert.ok(urlConfig, "offline url config is initialized");
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCaseAsync({
name: "Init: init with cs string, change with cs promise",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
let config = this._ai.config;
let expectedIkey = ApplicationInsightsTests._instrumentationKey;
let expectedConnectionString = ApplicationInsightsTests._connectionString;
let expectedEndpointUrl = "https://dc.services.visualstudio.com/v2/track";
Assert.ok(config, "ApplicationInsights config exists");
Assert.equal(expectedConnectionString, config.connectionString, "connection string is set");
Assert.equal(expectedIkey, config.instrumentationKey, "ikey is set");
Assert.equal(expectedEndpointUrl, config.endpointUrl, "endpoint url is set from connection string");
let core = this._ai.core;
let status = core.activeStatus && core.activeStatus();
Assert.equal(status, ActiveStatus.ACTIVE, "status should be set to active");
let csPromise = createAsyncResolvedPromise("InstrumentationKey=testIkey;ingestionendpoint=testUrl");
config.connectionString = csPromise;
config.initTimeOut = 80000;
this.clock.tick(1);
status = core.activeStatus && core.activeStatus();
Assert.equal(status, ActiveStatus.PENDING, "status should be set to pending");
}].concat(PollingAssert.createPollingAssert(() => {
let core = this._ai.core
let activeStatus = core.activeStatus && core.activeStatus();
if (activeStatus === ActiveStatus.ACTIVE) {
Assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set");
Assert.equal("testUrl/v2/track", core.config.endpointUrl ,"endpoint shoule be set");
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCaseAsync({
name: "Init: init with cs null, ikey promise, endpoint promise",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
// unload previous one first
let oriInst = this._ai;
if (oriInst && oriInst.unload) {
// force unload
oriInst.unload(false);
}
if (oriInst && oriInst["dependencies"]) {
oriInst["dependencies"].teardown();
}
this._config = this._getTestConfig(this._sessionPrefix);
let ikeyPromise = createAsyncResolvedPromise("testIkey");
let endpointPromise = createAsyncResolvedPromise("testUrl");
//let csPromise = createAsyncResolvedPromise("InstrumentationKey=testIkey;ingestionendpoint=testUrl");
//this._config.connectionString = csPromise;
this._config.connectionString = null;
this._config.instrumentationKey = ikeyPromise;
this._config.endpointUrl = endpointPromise;
this._config.initTimeOut= 80000;
let init = new ApplicationInsights({
config: this._config
});
init.loadAppInsights();
this._ai = init;
let config = this._ai.config;
let core = this._ai.core;
let status = core.activeStatus && core.activeStatus();
Assert.equal(status, ActiveStatus.PENDING, "status should be set to pending");
Assert.equal(config.connectionString,null, "connection string shoule be null");
}].concat(PollingAssert.createPollingAssert(() => {
let core = this._ai.core
let activeStatus = core.activeStatus && core.activeStatus();
if (activeStatus === ActiveStatus.ACTIVE) {
Assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set");
Assert.equal("testUrl", core.config.endpointUrl ,"endpoint shoule be set");
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCase({
name: "CfgSync DynamicConfigTests: Prod CDN is Fetched and feature is turned on/off as expected",
useFakeTimers: true,
@ -295,7 +508,7 @@ export class ApplicationInsightsTests extends AITestClass {
});
this.testCase({
name: "CfgSync DynamicConfigTests: Offline Support can be added and initialized with endpoint url",
name: "Init Promise: Offline Support can be added and initialized with endpoint url",
useFakeTimers: true,
test: () => {
this.clock.tick(1);
@ -327,13 +540,13 @@ export class ApplicationInsightsTests extends AITestClass {
if (ai && ai["dependencies"]) {
ai["dependencies"].teardown();
}
offlineChannel.teardown();
//offlineChannel.teardown();
}
});
this.testCase({
name: "CfgSync DynamicConfigTests: Offline Support can be added and initialized with channels",
name: "Init Promise: Offline Support can be added and initialized with channels",
useFakeTimers: true,
test: () => {
this.clock.tick(1);
@ -365,7 +578,6 @@ export class ApplicationInsightsTests extends AITestClass {
if (ai && ai["dependencies"]) {
ai["dependencies"].teardown();
}
offlineChannel.teardown();
}
});
@ -377,7 +589,7 @@ export class ApplicationInsightsTests extends AITestClass {
this.clock.tick(1);
let offlineChannel = new OfflineChannel();
let config = {
instrumentationKey: "testIKey",
connectionString: "InstrumentationKey=testIKey",
extensionConfig:{
["AppInsightsCfgSyncPlugin"]: {
cfgUrl: ""
@ -395,13 +607,14 @@ export class ApplicationInsightsTests extends AITestClass {
Assert.equal(sendChannel.plugin.isInitialized(), true, "sender is initialized");
Assert.equal(offlineChannelPlugin.isInitialized(), true, "offline channel is initialized");
let urlConfig = offlineChannelPlugin["_getDbgPlgTargets"]()[0];
this.clock.tick(1);
Assert.ok(urlConfig, "offline url config is initialized");
ai.unload(false);
if (ai && ai["dependencies"]) {
ai["dependencies"].teardown();
}
offlineChannel.teardown();
}
});

Просмотреть файл

@ -7,8 +7,8 @@ import { AnalyticsPlugin, ApplicationInsights } from "@microsoft/applicationinsi
import { CfgSyncPlugin, ICfgSyncConfig, ICfgSyncMode } from "@microsoft/applicationinsights-cfgsync-js";
import { Sender } from "@microsoft/applicationinsights-channel-js";
import {
AnalyticsPluginIdentifier, DEFAULT_BREEZE_PATH, IAutoExceptionTelemetry, IConfig, IDependencyTelemetry, IEventTelemetry,
IExceptionTelemetry, IMetricTelemetry, IPageViewPerformanceTelemetry, IPageViewTelemetry, IRequestHeaders,
AnalyticsPluginIdentifier, ConnectionString, DEFAULT_BREEZE_PATH, IAutoExceptionTelemetry, IConfig, IDependencyTelemetry,
IEventTelemetry, IExceptionTelemetry, IMetricTelemetry, IPageViewPerformanceTelemetry, IPageViewTelemetry, IRequestHeaders,
ITelemetryContext as Common_ITelemetryContext, IThrottleInterval, IThrottleLimit, IThrottleMgrConfig, ITraceTelemetry,
PropertiesPluginIdentifier, ThrottleMgr, parseConnectionString
} from "@microsoft/applicationinsights-common";
@ -26,8 +26,8 @@ import {
IDependencyListenerHandler
} from "@microsoft/applicationinsights-dependencies-js";
import { PropertiesPlugin } from "@microsoft/applicationinsights-properties-js";
import { IPromise, createPromise } from "@nevware21/ts-async";
import { arrForEach, arrIndexOf, objDefine, objForEachKey, strIndexOf, throwUnsupported } from "@nevware21/ts-utils";
import { IPromise, createAsyncPromise, createPromise, doAwaitResponse } from "@nevware21/ts-async";
import { arrForEach, arrIndexOf, isPromiseLike, objDefine, objForEachKey, strIndexOf, throwUnsupported } from "@nevware21/ts-utils";
import { IApplicationInsights } from "./IApplicationInsights";
import {
CONFIG_ENDPOINT_URL, STR_ADD_TELEMETRY_INITIALIZER, STR_CLEAR_AUTHENTICATED_USER_CONTEXT, STR_EVT_NAMESPACE, STR_GET_COOKIE_MGR,
@ -200,8 +200,65 @@ export class AppInsightsSku implements IApplicationInsights {
// Will get recalled if any referenced values are changed
_addUnloadHook(onConfigChange(cfgHandler, () => {
if (_config.connectionString) {
const cs = parseConnectionString(_config.connectionString);
let configCs = _config.connectionString;
function _parseCs() {
return createAsyncPromise<ConnectionString>((resolve, reject) => {
doAwaitResponse(configCs, (res) => {
let curCs = res && res.value;
let parsedCs = null;
if (!res.rejected && curCs) {
// replace cs with resolved values in case of circular promises
_config.connectionString = curCs;
parsedCs = parseConnectionString(curCs);
}
// if can't resolve cs promise, null will be returned
resolve(parsedCs);
});
});
}
if (isPromiseLike(configCs)) {
let ikeyPromise = createAsyncPromise<string>((resolve, reject) => {
_parseCs().then((cs) => {
let ikey = _config.instrumentationKey;
ikey = cs && cs.instrumentationkey || ikey;
resolve(ikey);
}).catch((e) => {
// parseCs will always resolve(unless timeout)
// return null in case any error happens
resolve(null);
});
});
let url: IPromise<string> | string = _config.userOverrideEndpointUrl;
if (isNullOrUndefined(url)) {
url = createAsyncPromise<string>((resolve, reject) => {
_parseCs().then((cs) => {
let url = _config.endpointUrl;
let ingest = cs && cs.ingestionendpoint;
url = ingest? ingest + DEFAULT_BREEZE_PATH : url;
resolve(url);
}).catch((e) => {
// parseCs will always resolve(unless timeout)
// return null in case any error happens
resolve(null);
});
});
}
_config.instrumentationKey = ikeyPromise;
_config.endpointUrl = url;
}
if (isString(configCs)) {
// confirm if promiselike function present
// handle cs promise here
// add cases to oneNote
const cs = parseConnectionString(configCs);
const ingest = cs.ingestionendpoint;
_config.endpointUrl = _config.userOverrideEndpointUrl ? _config.userOverrideEndpointUrl : ingest + DEFAULT_BREEZE_PATH; // add /v2/track
_config.instrumentationKey = cs.instrumentationkey || _config.instrumentationKey;

Просмотреть файл

@ -2,10 +2,10 @@ import { AITestClass, Assert } from "@microsoft/ai-test-framework";
import * as pako from "pako";
export class AISKULightSizeCheck extends AITestClass {
private readonly MAX_RAW_SIZE = 88;
private readonly MAX_BUNDLE_SIZE = 88;
private readonly MAX_RAW_DEFLATE_SIZE = 36;
private readonly MAX_BUNDLE_DEFLATE_SIZE = 36;
private readonly MAX_RAW_SIZE = 89;
private readonly MAX_BUNDLE_SIZE = 89;
private readonly MAX_RAW_DEFLATE_SIZE = 37;
private readonly MAX_BUNDLE_DEFLATE_SIZE = 37;
private readonly rawFilePath = "../dist/es5/applicationinsights-web-basic.min.js";
private readonly currentVer = "3.2.2";
private readonly prodFilePath = `../browser/es5/aib.${this.currentVer[0]}.min.js`;

Просмотреть файл

@ -8,8 +8,8 @@ import {
AppInsightsCore, IConfigDefaults, IConfiguration, IDynamicConfigHandler, ILoadedPlugin, IPlugin, ITelemetryItem, ITelemetryPlugin,
ITelemetryUnloadState, IUnloadHook, UnloadHandler, WatcherFunction, cfgDfValidate, createDynamicConfig, onConfigChange, proxyFunctions
} from "@microsoft/applicationinsights-core-js";
import { IPromise } from "@nevware21/ts-async";
import { isNullOrUndefined, objDefine, throwError } from "@nevware21/ts-utils";
import { IPromise, createAsyncPromise, doAwaitResponse } from "@nevware21/ts-async";
import { isNullOrUndefined, isPromiseLike, isString, objDefine, throwError } from "@nevware21/ts-utils";
const defaultConfigValues: IConfigDefaults<IConfiguration> = {
diagnosticLogInterval: cfgDfValidate(_chkDiagLevel, 10000)
@ -73,8 +73,45 @@ export class ApplicationInsights {
_config = cfgHandler.cfg;
core.addUnloadHook(onConfigChange(cfgHandler, () => {
if (_config.connectionString) {
const cs = parseConnectionString(_config.connectionString);
let configCs = _config.connectionString;
if (isPromiseLike(configCs)) {
let ikeyPromise = createAsyncPromise<string>((resolve, reject) => {
doAwaitResponse(configCs, (res) => {
let curCs = res.value;
let ikey = _config.instrumentationKey;
if (!res.rejected && curCs) {
// replace cs with resolved values in case of circular promises
_config.connectionString = curCs;
let resolvedCs = parseConnectionString(curCs);
ikey = resolvedCs.instrumentationkey || ikey;
}
resolve(ikey);
});
});
let urlPromise = createAsyncPromise<string>((resolve, reject) => {
doAwaitResponse(configCs, (res) => {
let curCs = res.value;
let url = _config.endpointUrl;
if (!res.rejected && curCs) {
let resolvedCs = parseConnectionString(curCs);
let ingest = resolvedCs.ingestionendpoint;
url = ingest? ingest + DEFAULT_BREEZE_PATH : url;
}
resolve(url);
});
});
_config.instrumentationKey = ikeyPromise;
_config.endpointUrl = _config.userOverrideEndpointUrl || urlPromise;
}
if (isString(configCs)) {
const cs = parseConnectionString(configCs);
const ingest = cs.ingestionendpoint;
_config.endpointUrl = _config.userOverrideEndpointUrl ? _config.userOverrideEndpointUrl : (ingest + DEFAULT_BREEZE_PATH); // only add /v2/track when from connectionstring
_config.instrumentationKey = cs.instrumentationkey || _config.instrumentationKey;

Просмотреть файл

@ -1,11 +1,12 @@
import { AITestClass } from "@microsoft/ai-test-framework";
import { AITestClass, PollingAssert } from "@microsoft/ai-test-framework";
import { Sender } from "../../../src/Sender";
import { IOfflineListener, createOfflineListener, utlGetSessionStorageKeys, utlRemoveSessionStorage } from "@microsoft/applicationinsights-common";
import { EnvelopeCreator } from '../../../src/EnvelopeCreator';
import { Exception, CtxTagKeys, isBeaconApiSupported, DEFAULT_BREEZE_ENDPOINT, DEFAULT_BREEZE_PATH, utlCanUseSessionStorage, utlGetSessionStorage, utlSetSessionStorage } from "@microsoft/applicationinsights-common";
import { ITelemetryItem, AppInsightsCore, ITelemetryPlugin, DiagnosticLogger, NotificationManager, SendRequestReason, _eInternalMessageId, safeGetLogger, isString, isArray, arrForEach, isBeaconsSupported, IXHROverride, IPayloadData,TransportType, getWindow } from "@microsoft/applicationinsights-core-js";
import { ITelemetryItem, AppInsightsCore, ITelemetryPlugin, DiagnosticLogger, NotificationManager, SendRequestReason, _eInternalMessageId, safeGetLogger, isString, isArray, arrForEach, isBeaconsSupported, IXHROverride, IPayloadData,TransportType, getWindow, ActiveStatus } from "@microsoft/applicationinsights-core-js";
import { ArraySendBuffer, SessionStorageSendBuffer } from "../../../src/SendBuffer";
import { IInternalStorageItem, ISenderConfig } from "../../../src/Interfaces";
import { createAsyncResolvedPromise } from "@nevware21/ts-async";
@ -163,6 +164,40 @@ export class SenderTests extends AITestClass {
}
});
this.testCaseAsync({
name: "Channel Init: init with promise",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
let core = new AppInsightsCore();
let ikeyPromise = createAsyncResolvedPromise("testIkey");
let urlPromise = createAsyncResolvedPromise("testUrl");
let coreConfig = {
instrumentationKey: ikeyPromise,
endpointUrl: urlPromise,
initTimeOut: 80000,
extensionConfig: {}
}
core.initialize(coreConfig, [this._sender]);
let status = core.activeStatus && core.activeStatus();
QUnit.assert.equal(status, ActiveStatus.PENDING, "status should be set to pending");
}].concat(PollingAssert.createPollingAssert(() => {
let core = this._sender.core;
let activeStatus = core.activeStatus && core.activeStatus();
if (activeStatus === ActiveStatus.ACTIVE) {
QUnit.assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set");
QUnit.assert.equal("testUrl", core.config.endpointUrl ,"endpoint shoule be set");
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCase({
name: "Channel Config: Sender override can be handled correctly",
useFakeTimers: true,

Просмотреть файл

@ -5,13 +5,14 @@ import {
createOfflineListener, eRequestHeaders, isInternalApplicationInsightsEndpoint, utlCanUseSessionStorage, utlSetStoragePrefix
} from "@microsoft/applicationinsights-common";
import {
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
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
} from "@microsoft/applicationinsights-core-js";
import { IPromise } from "@nevware21/ts-async";
import { ITimerHandler, isNumber, isString, isTruthy, objDeepFreeze, objDefine, scheduleTimeout } from "@nevware21/ts-utils";
@ -242,7 +243,8 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls {
if (_self.isInitialized()) {
_throwInternal(_self.diagLog(), eLoggingSeverity.CRITICAL, _eInternalMessageId.SenderNotInitialized, "Sender is already initialized");
}
_base.initialize(config, core, extensions, pluginChain);
let identifier = _self.identifier;
_serializer = new Serializer(core.logger);
@ -270,6 +272,19 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls {
}
});
// or is not string
if (core.activeStatus() === ActiveStatus.PENDING) {
// waiting for core promises to be resolved
// NOTE: if active status is set to pending, stop sending, clear timer here
_self.pause();
} else if (core.activeStatus() === ActiveStatus.ACTIVE) {
// core status changed from pending to other status
_self.resume();
}
// Only update the endpoint if the original config !== the current config
// This is so any redirect endpointUrl is not overwritten
if (_orgEndpointUrl !== senderConfig.endpointUrl) {
@ -348,7 +363,7 @@ export class Sender extends BaseTelemetryPlugin implements IChannelControls {
}
_customHeaders = senderConfig.customHeaders;
if (!isInternalApplicationInsightsEndpoint(_endpointUrl) && _customHeaders && _customHeaders.length > 0) {
if (isString(_endpointUrl) && !isInternalApplicationInsightsEndpoint(_endpointUrl) && _customHeaders && _customHeaders.length > 0) {
arrForEach(_customHeaders, customHeader => {
this.addHeader(customHeader.header, customHeader.value);
});

Просмотреть файл

@ -13,7 +13,7 @@ import {
eLoggingSeverity, mergeEvtNamespace, onConfigChange, runTargetUnload
} from "@microsoft/applicationinsights-core-js";
import { IPromise, ITaskScheduler, createAsyncPromise, createTaskScheduler } from "@nevware21/ts-async";
import { ITimerHandler, isFunction, objDeepFreeze, scheduleTimeout } from "@nevware21/ts-utils";
import { ITimerHandler, isFunction, isString, objDeepFreeze, scheduleTimeout } from "@nevware21/ts-utils";
import {
EVT_DISCARD_STR, EVT_SENT_STR, EVT_STORE_STR, batchDropNotification, callNotification, isGreaterThanZero
} from "./Helpers/Utils";
@ -401,12 +401,12 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr
_storeNotification(sentItems);
}
};
if (payloadData) {
if (payloadData && _urlCfg && _urlCfg.batchHandler) {
let promise = _urlCfg.batchHandler.storeBatch(payloadData, callback, unload);
_queueStorageEvent("storeBatch", promise);
}
if (!_inMemoBatch.count()) {
if (_inMemoBatch && !_inMemoBatch.count()) {
_inMemoFlushTimer && _inMemoFlushTimer.cancel();
}
@ -448,8 +448,11 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr
}
}
let promise = _urlCfg.batchHandler.sendNextBatch(callback, false, _senderInst);
_queueStorageEvent("sendNextBatch", promise);
if (_urlCfg && _urlCfg.batchHandler) {
let promise = _urlCfg.batchHandler.sendNextBatch(callback, false, _senderInst);
_queueStorageEvent("sendNextBatch", promise);
}
}
} else {
@ -570,6 +573,14 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr
function _createUrlConfig(coreConfig: IConfiguration & IConfig, core: IAppInsightsCore, extensions: IPlugin[], pluginChain?: ITelemetryPluginChain) {
_self._addHook(onConfigChange(coreConfig, (details) => {
if (!isString(coreConfig.instrumentationKey) || !isString(coreConfig.endpointUrl)) {
// if ikey or endpointUrl is promise, delay initialization
_self.pause();
return;
}
if (_paused) {
_self.resume();
}
let storageConfig: IOfflineChannelConfiguration = null;
let theConfig = details.cfg;
@ -614,7 +625,7 @@ export class OfflineChannel extends BaseTelemetryPlugin implements IChannelContr
handler.initialize(providerContext);
urlConfig = {
iKey: coreConfig.instrumentationKey,
iKey: coreConfig.instrumentationKey as string,
url: curUrl,
minPersistenceCacheLevel: storageConfig.minPersistenceLevel,
coreRootCtx: coreRootCtx,

Просмотреть файл

@ -5,7 +5,7 @@ import dynamicProto from "@microsoft/dynamicproto-js";
import { EventPersistence } from "@microsoft/applicationinsights-common";
import {
INotificationManager, IProcessTelemetryContext, IUnloadHookContainer, eBatchDiscardedReason, eLoggingSeverity, isNotNullOrUndefined,
isNumber, newGuid, onConfigChange
isNumber, isString, newGuid, onConfigChange
} from "@microsoft/applicationinsights-core-js";
import { IPromise, createAsyncAllPromise, createAsyncPromise, doAwait, doAwaitResponse } from "@nevware21/ts-async";
import { batchDropNotification, getEndpointDomain, getTimeFromId, getTimeId } from "../Helpers/Utils";
@ -280,7 +280,12 @@ export class IndexedDbProvider implements IOfflineProvider {
}
let coreConfig = providerContext.itemCtx.getCfg();
let itemCtx = providerContext.itemCtx;
_iKey = itemCtx.getCfg().instrumentationKey || coreConfig.instrumentationKey;
let ikey = itemCtx.getCfg().instrumentationKey || coreConfig.instrumentationKey;
if (!isString(ikey)) {
//_iKey = ikey
return;
}
_iKey = ikey;
let storageConfig: IOfflineChannelConfiguration = providerContext.storageConfig;
_storageId = _this.id || providerContext.id || newGuid();

192
common/config/rush/npm-shrinkwrap.json сгенерированный
Просмотреть файл

@ -1573,16 +1573,16 @@
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.1.tgz",
"integrity": "sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==",
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.14.1.tgz",
"integrity": "sha512-aAJd6bIf2vvQRjUG3ZkNXkmBpN+J7Wd0mfQiiVCJMu9Z5GcZZdcc0j8XwN/BM97Fl7e3SkTXODSk4VehUv7CGw==",
"peer": true,
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "7.13.1",
"@typescript-eslint/type-utils": "7.13.1",
"@typescript-eslint/utils": "7.13.1",
"@typescript-eslint/visitor-keys": "7.13.1",
"@typescript-eslint/scope-manager": "7.14.1",
"@typescript-eslint/type-utils": "7.14.1",
"@typescript-eslint/utils": "7.14.1",
"@typescript-eslint/visitor-keys": "7.14.1",
"graphemer": "^1.4.0",
"ignore": "^5.3.1",
"natural-compare": "^1.4.0",
@ -1606,15 +1606,15 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.1.tgz",
"integrity": "sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==",
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.14.1.tgz",
"integrity": "sha512-8lKUOebNLcR0D7RvlcloOacTOWzOqemWEWkKSVpMZVF/XVcwjPR+3MD08QzbW9TCGJ+DwIc6zUSGZ9vd8cO1IA==",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "7.13.1",
"@typescript-eslint/types": "7.13.1",
"@typescript-eslint/typescript-estree": "7.13.1",
"@typescript-eslint/visitor-keys": "7.13.1",
"@typescript-eslint/scope-manager": "7.14.1",
"@typescript-eslint/types": "7.14.1",
"@typescript-eslint/typescript-estree": "7.14.1",
"@typescript-eslint/visitor-keys": "7.14.1",
"debug": "^4.3.4"
},
"engines": {
@ -1634,13 +1634,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz",
"integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==",
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz",
"integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==",
"peer": true,
"dependencies": {
"@typescript-eslint/types": "7.13.1",
"@typescript-eslint/visitor-keys": "7.13.1"
"@typescript-eslint/types": "7.14.1",
"@typescript-eslint/visitor-keys": "7.14.1"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@ -1651,13 +1651,13 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.1.tgz",
"integrity": "sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==",
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.14.1.tgz",
"integrity": "sha512-/MzmgNd3nnbDbOi3LfasXWWe292+iuo+umJ0bCCMCPc1jLO/z2BQmWUUUXvXLbrQey/JgzdF/OV+I5bzEGwJkQ==",
"peer": true,
"dependencies": {
"@typescript-eslint/typescript-estree": "7.13.1",
"@typescript-eslint/utils": "7.13.1",
"@typescript-eslint/typescript-estree": "7.14.1",
"@typescript-eslint/utils": "7.14.1",
"debug": "^4.3.4",
"ts-api-utils": "^1.3.0"
},
@ -1678,9 +1678,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz",
"integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==",
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz",
"integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==",
"peer": true,
"engines": {
"node": "^18.18.0 || >=20.0.0"
@ -1691,13 +1691,13 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz",
"integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==",
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz",
"integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==",
"peer": true,
"dependencies": {
"@typescript-eslint/types": "7.13.1",
"@typescript-eslint/visitor-keys": "7.13.1",
"@typescript-eslint/types": "7.14.1",
"@typescript-eslint/visitor-keys": "7.14.1",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -1755,15 +1755,15 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz",
"integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==",
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz",
"integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"@typescript-eslint/scope-manager": "7.13.1",
"@typescript-eslint/types": "7.13.1",
"@typescript-eslint/typescript-estree": "7.13.1"
"@typescript-eslint/scope-manager": "7.14.1",
"@typescript-eslint/types": "7.14.1",
"@typescript-eslint/typescript-estree": "7.14.1"
},
"engines": {
"node": "^18.18.0 || >=20.0.0"
@ -1777,12 +1777,12 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz",
"integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==",
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz",
"integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==",
"peer": true,
"dependencies": {
"@typescript-eslint/types": "7.13.1",
"@typescript-eslint/types": "7.14.1",
"eslint-visitor-keys": "^3.4.3"
},
"engines": {
@ -2641,9 +2641,9 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
},
"node_modules/electron-to-chromium": {
"version": "1.4.807",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.807.tgz",
"integrity": "sha512-kSmJl2ZwhNf/bcIuCH/imtNOKlpkLDn2jqT5FJ+/0CXjhnFaOa9cOe9gHKKy71eM49izwuQjZhKk+lWQ1JxB7A=="
"version": "1.4.811",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.811.tgz",
"integrity": "sha512-CDyzcJ5XW78SHzsIOdn27z8J4ist8eaFLhdto2hSMSJQgsiwvbv2fbizcKUICryw1Wii1TI/FEkvzvJsR3awrA=="
},
"node_modules/encodeurl": {
"version": "1.0.2",
@ -4142,9 +4142,9 @@
"peer": true
},
"node_modules/jsonc-parser": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz",
"integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA=="
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz",
"integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="
},
"node_modules/jsonfile": {
"version": "4.0.0",
@ -7681,16 +7681,16 @@
}
},
"@typescript-eslint/eslint-plugin": {
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.1.tgz",
"integrity": "sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==",
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.14.1.tgz",
"integrity": "sha512-aAJd6bIf2vvQRjUG3ZkNXkmBpN+J7Wd0mfQiiVCJMu9Z5GcZZdcc0j8XwN/BM97Fl7e3SkTXODSk4VehUv7CGw==",
"peer": true,
"requires": {
"@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "7.13.1",
"@typescript-eslint/type-utils": "7.13.1",
"@typescript-eslint/utils": "7.13.1",
"@typescript-eslint/visitor-keys": "7.13.1",
"@typescript-eslint/scope-manager": "7.14.1",
"@typescript-eslint/type-utils": "7.14.1",
"@typescript-eslint/utils": "7.14.1",
"@typescript-eslint/visitor-keys": "7.14.1",
"graphemer": "^1.4.0",
"ignore": "^5.3.1",
"natural-compare": "^1.4.0",
@ -7698,54 +7698,54 @@
}
},
"@typescript-eslint/parser": {
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.1.tgz",
"integrity": "sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==",
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.14.1.tgz",
"integrity": "sha512-8lKUOebNLcR0D7RvlcloOacTOWzOqemWEWkKSVpMZVF/XVcwjPR+3MD08QzbW9TCGJ+DwIc6zUSGZ9vd8cO1IA==",
"peer": true,
"requires": {
"@typescript-eslint/scope-manager": "7.13.1",
"@typescript-eslint/types": "7.13.1",
"@typescript-eslint/typescript-estree": "7.13.1",
"@typescript-eslint/visitor-keys": "7.13.1",
"@typescript-eslint/scope-manager": "7.14.1",
"@typescript-eslint/types": "7.14.1",
"@typescript-eslint/typescript-estree": "7.14.1",
"@typescript-eslint/visitor-keys": "7.14.1",
"debug": "^4.3.4"
}
},
"@typescript-eslint/scope-manager": {
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz",
"integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==",
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.14.1.tgz",
"integrity": "sha512-gPrFSsoYcsffYXTOZ+hT7fyJr95rdVe4kGVX1ps/dJ+DfmlnjFN/GcMxXcVkeHDKqsq6uAcVaQaIi3cFffmAbA==",
"peer": true,
"requires": {
"@typescript-eslint/types": "7.13.1",
"@typescript-eslint/visitor-keys": "7.13.1"
"@typescript-eslint/types": "7.14.1",
"@typescript-eslint/visitor-keys": "7.14.1"
}
},
"@typescript-eslint/type-utils": {
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.1.tgz",
"integrity": "sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==",
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.14.1.tgz",
"integrity": "sha512-/MzmgNd3nnbDbOi3LfasXWWe292+iuo+umJ0bCCMCPc1jLO/z2BQmWUUUXvXLbrQey/JgzdF/OV+I5bzEGwJkQ==",
"peer": true,
"requires": {
"@typescript-eslint/typescript-estree": "7.13.1",
"@typescript-eslint/utils": "7.13.1",
"@typescript-eslint/typescript-estree": "7.14.1",
"@typescript-eslint/utils": "7.14.1",
"debug": "^4.3.4",
"ts-api-utils": "^1.3.0"
}
},
"@typescript-eslint/types": {
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz",
"integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==",
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.14.1.tgz",
"integrity": "sha512-mL7zNEOQybo5R3AavY+Am7KLv8BorIv7HCYS5rKoNZKQD9tsfGUpO4KdAn3sSUvTiS4PQkr2+K0KJbxj8H9NDg==",
"peer": true
},
"@typescript-eslint/typescript-estree": {
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz",
"integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==",
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.14.1.tgz",
"integrity": "sha512-k5d0VuxViE2ulIO6FbxxSZaxqDVUyMbXcidC8rHvii0I56XZPv8cq+EhMns+d/EVIL41sMXqRbK3D10Oza1bbA==",
"peer": true,
"requires": {
"@typescript-eslint/types": "7.13.1",
"@typescript-eslint/visitor-keys": "7.13.1",
"@typescript-eslint/types": "7.14.1",
"@typescript-eslint/visitor-keys": "7.14.1",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -7781,24 +7781,24 @@
}
},
"@typescript-eslint/utils": {
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz",
"integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==",
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz",
"integrity": "sha512-CMmVVELns3nak3cpJhZosDkm63n+DwBlDX8g0k4QUa9BMnF+lH2lr3d130M1Zt1xxmB3LLk3NV7KQCq86ZBBhQ==",
"peer": true,
"requires": {
"@eslint-community/eslint-utils": "^4.4.0",
"@typescript-eslint/scope-manager": "7.13.1",
"@typescript-eslint/types": "7.13.1",
"@typescript-eslint/typescript-estree": "7.13.1"
"@typescript-eslint/scope-manager": "7.14.1",
"@typescript-eslint/types": "7.14.1",
"@typescript-eslint/typescript-estree": "7.14.1"
}
},
"@typescript-eslint/visitor-keys": {
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz",
"integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==",
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.14.1.tgz",
"integrity": "sha512-Crb+F75U1JAEtBeQGxSKwI60hZmmzaqA3z9sYsVm8X7W5cwLEm5bRe0/uXS6+MR/y8CVpKSR/ontIAIEPFcEkA==",
"peer": true,
"requires": {
"@typescript-eslint/types": "7.13.1",
"@typescript-eslint/types": "7.14.1",
"eslint-visitor-keys": "^3.4.3"
}
},
@ -8403,9 +8403,9 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
},
"electron-to-chromium": {
"version": "1.4.807",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.807.tgz",
"integrity": "sha512-kSmJl2ZwhNf/bcIuCH/imtNOKlpkLDn2jqT5FJ+/0CXjhnFaOa9cOe9gHKKy71eM49izwuQjZhKk+lWQ1JxB7A=="
"version": "1.4.811",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.811.tgz",
"integrity": "sha512-CDyzcJ5XW78SHzsIOdn27z8J4ist8eaFLhdto2hSMSJQgsiwvbv2fbizcKUICryw1Wii1TI/FEkvzvJsR3awrA=="
},
"encodeurl": {
"version": "1.0.2",
@ -9533,9 +9533,9 @@
"peer": true
},
"jsonc-parser": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz",
"integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA=="
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz",
"integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="
},
"jsonfile": {
"version": "4.0.0",

Просмотреть файл

@ -1,11 +1,12 @@
import { SinonStub } from "sinon";
import { Assert, AITestClass, PollingAssert } from "@microsoft/ai-test-framework";
import { createSyncPromise } from "@nevware21/ts-async";
import { createAsyncResolvedPromise, createSyncPromise } from "@nevware21/ts-async";
import { AjaxMonitor } from "../../../src/ajax";
import { DisabledPropertyName, IConfig, DistributedTracingModes, RequestHeaders, IDependencyTelemetry, IRequestContext, formatTraceParent, createTraceParent, PropertiesPluginIdentifier } from "@microsoft/applicationinsights-common";
import {
AppInsightsCore, IConfiguration, ITelemetryItem, ITelemetryPlugin, IChannelControls, _eInternalMessageId,
getPerformance, getGlobalInst, getGlobal, generateW3CId, arrForEach
getPerformance, getGlobalInst, getGlobal, generateW3CId, arrForEach,
ActiveStatus
} from "@microsoft/applicationinsights-core-js";
import { IDependencyListenerDetails } from "../../../src/DependencyListener";
import { FakeXMLHttpRequest } from "@microsoft/ai-test-framework";
@ -208,6 +209,59 @@ export class AjaxTests extends AITestClass {
}
});
this.testCaseAsync({
name: "Dependencies Configuration: init with cs promise ikey promise and default enableAjaxPerfTracking",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
this._ajax = new AjaxMonitor();
let csPromise = createAsyncResolvedPromise("testIkey");
let appInsightsCore = new AppInsightsCore();
let coreConfig = {
instrumentationKey: csPromise,
initTimeOut: 80000
};
appInsightsCore.initialize(coreConfig, [this._ajax, new TestChannelPlugin()]);
let trackStub = this.sandbox.stub(appInsightsCore, "track");
let throwSpy = this.sandbox.spy(appInsightsCore.logger, "throwInternal");
Assert.equal(false, trackStub.called, "Track should not be called");
Assert.equal(false, throwSpy.called, "We should not have thrown an internal error");
this._context.core = appInsightsCore;
this._context.trackStub = trackStub;
this._context.throwSpy = throwSpy;
let xhr = new XMLHttpRequest();
xhr.open("GET", "http://microsoft.com");
xhr.setRequestHeader("Content-type", "application/json");
xhr.send();
// Emulate response
(<any>xhr).respond(200, {"Content-Type": "application/json; charset=utf-8", "Access-Control-Allow-Origin": "*"}, "");
Assert.ok((<any>xhr)[AJAX_DATA_CONTAINER], "should have xhr hooks");
}].concat(PollingAssert.createPollingAssert(() => {
let core = this._context.core
let activeStatus = core.activeStatus && core.activeStatus();
let trackStub = this._context.trackStub;
let throwSpy = this._context.throwSpy;
if (activeStatus === ActiveStatus.ACTIVE) {
Assert.equal("testIkey", core.config.instrumentationKey, "ikey should be set");
Assert.equal(1, trackStub.callCount, "Track should be called once");
Assert.equal(false, throwSpy.called, "We should not have thrown an internal error test1");
let data = trackStub.args[0][0].baseData;
Assert.equal(data.type, "Ajax", "request type should be ajax");
Assert.ok(data.properties, "properties should be added");
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCase({
name: "Dependencies Configuration: Make sure we don't fail for invalid arguments",
test: () => {

Просмотреть файл

@ -597,12 +597,14 @@ export class AjaxMonitor extends BaseTelemetryPlugin implements IDependenciesPlu
_isUsingW3CHeaders = _distributedTracingMode === eDistributedTracingModes.AI_AND_W3C || _distributedTracingMode === eDistributedTracingModes.W3C;
if (_enableAjaxPerfTracking) {
let iKey = config.instrumentationKey || "unkwn";
let iKey = (config.instrumentationKey as string) || "unkwn";
// TODO: handle ikey promise
if (iKey.length > 5) {
_markPrefix = AJAX_MONITOR_PREFIX + strSubstring(iKey, iKey.length - 5) + ".";
} else {
_markPrefix = AJAX_MONITOR_PREFIX + iKey + ".";
}
}
_disableAjaxTracking = !!_extensionConfig.disableAjaxTracking;

Просмотреть файл

@ -2,8 +2,8 @@ import { AITestClass } from "@microsoft/ai-test-framework";
import * as pako from 'pako';
export class FileSizeCheckTest extends AITestClass {
private readonly MAX_BUNDLE_SIZE = 66;
private readonly MAX_DEFLATE_SIZE = 28;
private readonly MAX_BUNDLE_SIZE = 68;
private readonly MAX_DEFLATE_SIZE = 29;
private readonly bundleFilePath = "../bundle/es5/ms.core.min.js";
public testInitialize() {

Просмотреть файл

@ -7,6 +7,7 @@ export {
} from "./Util";
export { ThrottleMgr } from "./ThrottleMgr";
export { parseConnectionString, ConnectionStringParser } from "./ConnectionStringParser";
export { ConnectionString } from "./Interfaces/ConnectionString";
export { FieldType } from "./Enums";
export { IRequestHeaders, RequestHeaders, eRequestHeaders } from "./RequestResponseHeaders";
export { DisabledPropertyName, ProcessLegacy, SampleRate, HttpMethod, DEFAULT_BREEZE_ENDPOINT, DEFAULT_BREEZE_PATH, strNotSpecified } from "./Constants";

Просмотреть файл

@ -2,8 +2,8 @@ import { Assert, AITestClass } from "@microsoft/ai-test-framework";
import * as pako from "pako";
export class AppInsightsCoreSizeCheck extends AITestClass {
private readonly MAX_RAW_SIZE = 64;
private readonly MAX_BUNDLE_SIZE = 64;
private readonly MAX_RAW_SIZE = 65;
private readonly MAX_BUNDLE_SIZE = 65;
private readonly MAX_RAW_DEFLATE_SIZE = 27;
private readonly MAX_BUNDLE_DEFLATE_SIZE = 27;
private readonly rawFilePath = "../dist/es5/applicationinsights-core-js.min.js";

Просмотреть файл

@ -1,21 +1,27 @@
import { Assert, AITestClass } from "@microsoft/ai-test-framework";
import { IConfiguration, ITelemetryPlugin, ITelemetryItem, IPlugin, IAppInsightsCore, normalizeJsName, random32, mwcRandomSeed, newId, randomValue, mwcRandom32, isNullOrUndefined, SenderPostManager, OnCompleteCallback, IPayloadData, _ISenderOnComplete, TransportType, _ISendPostMgrConfig, dumpObj } from "../../../src/applicationinsights-core-js"
import { Assert, AITestClass, PollingAssert } from "@microsoft/ai-test-framework";
import { IConfiguration, ITelemetryPlugin, ITelemetryItem, IPlugin, IAppInsightsCore, normalizeJsName, random32, mwcRandomSeed, newId, randomValue, mwcRandom32, isNullOrUndefined, SenderPostManager, OnCompleteCallback, IPayloadData, _ISenderOnComplete, TransportType, _ISendPostMgrConfig, dumpObj, onConfigChange, createProcessTelemetryContext } from "../../../src/applicationinsights-core-js"
import { AppInsightsCore } from "../../../src/JavaScriptSDK/AppInsightsCore";
import { IChannelControls } from "../../../src/JavaScriptSDK.Interfaces/IChannelControls";
import { _eInternalMessageId, LoggingSeverity } from "../../../src/JavaScriptSDK.Enums/LoggingEnums";
import { _InternalLogMessage, DiagnosticLogger } from "../../../src/JavaScriptSDK/DiagnosticLogger";
import { ActiveStatus } from "../../../src/JavaScriptSDK.Enums/InitActiveStatusEnum";
import { createAsyncPromise, createAsyncRejectedPromise, createAsyncResolvedPromise, createTimeoutPromise, doAwaitResponse } from "@nevware21/ts-async";
const AIInternalMessagePrefix = "AITR_";
const MaxInt32 = 0xFFFFFFFF;
export class ApplicationInsightsCoreTests extends AITestClass {
private ctx: any;
public testInitialize() {
super.testInitialize();
this.ctx = {};
}
public testCleanup() {
super.testCleanup();
this.ctx = {};
}
public registerTests() {
@ -848,6 +854,814 @@ export class ApplicationInsightsCoreTests extends AITestClass {
}
});
// init with ikey: null
this.testCase({
name: "ApplicationInsightsCore Init: init with ikey null, will throw error message",
useFakeTimers: true,
test: () => {
let trackPlugin = new TrackPlugin();
let channelPlugin = new ChannelPlugin();
channelPlugin.priority = 1001;
let core = new AppInsightsCore();
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
let activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.NONE, "default should be inactive status");
let config = {
instrumentationKey: undefined,
endpointUrl: "testUrl"
} as IConfiguration;
let errorisCalled = false;
try {
core.initialize(
config,
[trackPlugin, channelPlugin]);
} catch (e) {
errorisCalled = true;
Assert.ok(JSON.stringify(e.message).indexOf("Please provide instrumentation key") > -1, "should send provide ikey error message");
}
Assert.ok(errorisCalled, "ikey error should be called");
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
Assert.equal(core.config.instrumentationKey, null, "channel testIkey should be null");
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should not be changed");
activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.INACTIVE, "default should be inactive status test1");
core.track({name: "test1"});
Assert.ok(core.eventCnt() == 0, "Event should not be queued");
let isInit = core.isInitialized();
Assert.ok(!isInit, "core is not initialized");
// Test re-init with valid ikey
config.instrumentationKey = "testIkey";
core.initialize(
config,
[trackPlugin, channelPlugin]);
Assert.ok(channelSpy.calledOnce, "channel should be called once");
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should be set");
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should not be changed");
activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status again");
isInit = core.isInitialized();
Assert.ok(isInit, "core is initialized");
}
});
// init with ikey: string, endpoint null
this.testCase({
name: "ApplicationInsightsCore Init: init with ikey string, endpoint null",
useFakeTimers: true,
test: () => {
let trackPlugin = new TrackPlugin();
let channelPlugin = new ChannelPlugin();
channelPlugin.priority = 1001;
let core = new AppInsightsCore();
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
let activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.NONE, "default should be inactive status");
let config = {
instrumentationKey: "testIkey",
endpointUrl: undefined
} as IConfiguration;
let errorisCalled = false;
try {
core.initialize(
config,
[trackPlugin, channelPlugin]);
} catch (e) {
errorisCalled = true;
}
Assert.ok(!errorisCalled, "ikey error should not be called");
Assert.ok(channelSpy.calledOnce, "channel should be called once");
Assert.ok(core.eventCnt() == 0, "Event should not be queued");
let evt = channelSpy.args[0][0];
Assert.equal(evt.iKey, "testIkey", "event ikey should be null");
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed");
Assert.equal(core.config.endpointUrl, null, "channel endpoint should not be changed");
activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status test");
}
});
// init with ikey: string, endpointUrl: string
this.testCase({
name: "ApplicationInsightsCore Init: init with ikey string, endpoint url string, dynamic changes with string",
useFakeTimers: true,
test: () => {
let trackPlugin = new TrackPlugin();
let channelPlugin = new ChannelPlugin();
channelPlugin.priority = 1001;
let core = new AppInsightsCore();
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
let activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.NONE, "default should be pending status");
let config = {
instrumentationKey: "testIkey",
endpointUrl: "testUrl"
} as IConfiguration;
core.initialize(
config,
[trackPlugin, channelPlugin]);
Assert.ok(channelSpy.calledOnce, "channel should be called once");
Assert.ok(core.eventCnt() == 0, "Event should not be queued");
let evt = channelSpy.args[0][0];
Assert.equal(evt.iKey, "testIkey", "event ikey should be set");
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should be set");
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be set");
activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status");
core.config.instrumentationKey = "testIkey1";
core.config.endpointUrl = "testUrl1";
this.clock.tick(1);
core.track({name: "test1"});
Assert.equal(channelSpy.callCount, 2, "channel should be called twice");
Assert.ok(core.eventCnt() == 0, "Event should not be queued test1");
evt = channelSpy.args[1][0];
Assert.equal(evt.name, "test1", "event name should be set");
Assert.equal(evt.iKey, "testIkey1", "event ikey should be set test1");
activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status test1");
// change the ikey to null again, inactive
core.config.instrumentationKey = undefined;
this.clock.tick(1);
activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.INACTIVE, "default should be inactive status test1");
}
});
this.testCaseAsync({
name: "ApplicationInsightsCore Init: init with ikey resolved promise, endpoint url resolved promise",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
let trackPlugin = new TrackPlugin();
let channelPlugin = new ChannelPlugin();
channelPlugin.priority = 1001;
let core = new AppInsightsCore();
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
this.ctx.core = core;
this.ctx.channelSpy = channelSpy;
let ikeyPromise = createAsyncResolvedPromise("testIkey");
let urlPromise = createAsyncResolvedPromise("testUrl");
let config = {
instrumentationKey: ikeyPromise,
endpointUrl: urlPromise,
initTimeOut: 80000
} as IConfiguration;
core.initialize(
config,
[trackPlugin, channelPlugin]);
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
Assert.ok(core.eventCnt() == 1, "Event should be queued");
let activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
}].concat(PollingAssert.createPollingAssert(() => {
let core = this.ctx.core;
let activeStatus = core.activeStatus();
let channelSpy = this.ctx.channelSpy
if (activeStatus === ActiveStatus.ACTIVE) {
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed");
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed");
Assert.ok(channelSpy.calledOnce, "channel should be called once");
Assert.ok(core.eventCnt() == 0, "Event should be released");
let evt = channelSpy.args[0][0];
Assert.equal(evt.iKey, "testIkey", "event ikey should be set");
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCaseAsync({
name: "ApplicationInsightsCore Init: init with ikey resolved promise, endpoint url rejected promise",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
let trackPlugin = new TrackPlugin();
let channelPlugin = new ChannelPlugin();
channelPlugin.priority = 1001;
let core = new AppInsightsCore();
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
this.ctx.core = core;
this.ctx.channelSpy = channelSpy;
let ikeyPromise = createAsyncResolvedPromise("testIkey");
let urlPromise = createAsyncRejectedPromise(new Error("endpoint error"));
let config = {
instrumentationKey: ikeyPromise,
endpointUrl: urlPromise,
initTimeOut: 80000
} as IConfiguration;
core.initialize(
config,
[trackPlugin, channelPlugin]);
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
Assert.ok(core.eventCnt() == 1, "Event should be queued");
let activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
}].concat(PollingAssert.createPollingAssert(() => {
let core = this.ctx.core;
let activeStatus = core.activeStatus();
let channelSpy = this.ctx.channelSpy
if (activeStatus === ActiveStatus.ACTIVE) {
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed");
Assert.equal(core.config.endpointUrl, null, "channel endpoint should not be changed");
Assert.ok(channelSpy.calledOnce, "channel should be called once");
Assert.ok(core.eventCnt() == 0, "Event should be released");
let evt = channelSpy.args[0][0];
Assert.equal(evt.iKey, "testIkey", "event ikey should be set");
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCaseAsync({
name: "ApplicationInsightsCore Init: init with ikey rejected promise, endpoint url rejected promise",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
let trackPlugin = new TrackPlugin();
let channelPlugin = new ChannelPlugin();
channelPlugin.priority = 1001;
let core = new AppInsightsCore();
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
this.ctx.core = core;
this.ctx.channelSpy = channelSpy;
let ikeyPromise = createAsyncRejectedPromise(new Error("ikey error"));
let urlPromise = createAsyncRejectedPromise(new Error("endpoint error"));
this.ctx.ikeyPromise = ikeyPromise;
this.ctx.urlPromise = urlPromise;
let config = {
instrumentationKey: ikeyPromise,
endpointUrl: urlPromise,
initTimeOut: 80000
} as IConfiguration;
core.initialize(
config,
[trackPlugin, channelPlugin]);
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
Assert.ok(core.eventCnt() == 1, "Event should be queued");
let activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
}].concat(PollingAssert.createPollingAssert(() => {
let core = this.ctx.core;
let activeStatus = core.activeStatus();
let channelSpy = this.ctx.channelSpy
let ikeyPromise = this.ctx.ikeyPromise;
let urlPromise = this.ctx.urlPromise;
if (activeStatus === ActiveStatus.INACTIVE) {
Assert.deepEqual(core.config.instrumentationKey, ikeyPromise, "channel testIkey should not be changed");
Assert.deepEqual(core.config.endpointUrl, urlPromise, "channel endpoint should not be changed");
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
Assert.ok(core.eventCnt() == 0, "Event should be released");
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCaseAsync({
name: "ApplicationInsightsCore Init: init with ikey promise chain, endpoint url promise chain",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
let trackPlugin = new TrackPlugin();
let channelPlugin = new ChannelPlugin();
channelPlugin.priority = 1001;
let core = new AppInsightsCore();
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
this.ctx.core = core;
this.ctx.channelSpy = channelSpy;
let csPromise = createAsyncResolvedPromise("instrumentationKey=testIkey;endpoint=testUrl");
let ikeyPromise = createAsyncPromise((resolve, reject) => {
doAwaitResponse(csPromise, (res) => {
if (!res.rejected) {
resolve("testIkey");
return;
}
reject(new Error("ikey error"));
})
});
let urlPromise = createAsyncPromise((resolve, reject) => {
doAwaitResponse(csPromise, (res) => {
if (!res.rejected) {
resolve("testUrl");
return;
}
reject(new Error("url error"));
})
});
let config = {
instrumentationKey: ikeyPromise,
endpointUrl: urlPromise,
initTimeOut: 80000
} as IConfiguration;
core.initialize(
config,
[trackPlugin, channelPlugin]);
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
Assert.ok(core.eventCnt() == 1, "Event should be queued");
let activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
}].concat(PollingAssert.createPollingAssert(() => {
let core = this.ctx.core;
let activeStatus = core.activeStatus();
let channelSpy = this.ctx.channelSpy
if (activeStatus === ActiveStatus.ACTIVE) {
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed");
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed");
Assert.ok(channelSpy.calledOnce, "channel should be called once");
Assert.ok(core.eventCnt() == 0, "Event should be released");
let evt = channelSpy.args[0][0];
Assert.equal(evt.iKey, "testIkey", "event ikey should be set");
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCaseAsync({
name: "ApplicationInsightsCore Init: init with ikey mutiple layer promise chain, endpoint url mutiple layer promise chain",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
let trackPlugin = new TrackPlugin();
let channelPlugin = new ChannelPlugin();
channelPlugin.priority = 1001;
let core = new AppInsightsCore();
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
this.ctx.core = core;
this.ctx.channelSpy = channelSpy;
let csPromise = createAsyncResolvedPromise("instrumentationKey=testIkey;endpoint=testUrl");
let ikeyPromise = createAsyncPromise((resolve, reject) => {
doAwaitResponse(csPromise, (res) => {
if (!res.rejected) {
resolve(createAsyncResolvedPromise("testIkey"));
return;
}
reject(createAsyncRejectedPromise(new Error("ikey error")));
return;
})
});
let urlPromise = createAsyncPromise((resolve, reject) => {
doAwaitResponse(csPromise, (res) => {
if (!res.rejected) {
resolve(createAsyncResolvedPromise("testUrl"));
return;
}
reject(createAsyncRejectedPromise(new Error("url error")));
return;
})
});
let config = {
instrumentationKey: ikeyPromise,
endpointUrl: urlPromise,
initTimeOut: 80000
} as IConfiguration;
core.initialize(
config,
[trackPlugin, channelPlugin]);
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
Assert.ok(core.eventCnt() == 1, "Event should be queued");
let activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
}].concat(PollingAssert.createPollingAssert(() => {
let core = this.ctx.core;
let activeStatus = core.activeStatus();
let channelSpy = this.ctx.channelSpy
if (activeStatus === ActiveStatus.ACTIVE) {
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed");
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed");
Assert.ok(channelSpy.calledOnce, "channel should be called once");
Assert.ok(core.eventCnt() == 0, "Event should be released");
let evt = channelSpy.args[0][0];
Assert.equal(evt.iKey, "testIkey", "event ikey should be set");
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCaseAsync({
name: "ApplicationInsightsCore Init: init with ikey string, endpoint url string, dynamic changed with resolved promises",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
let trackPlugin = new TrackPlugin();
let channelPlugin = new ChannelPlugin();
channelPlugin.priority = 1001;
let core = new AppInsightsCore();
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
let config = {
instrumentationKey: "testIkey",
endpointUrl: "testUrl",
initTimeOut: 80000
} as IConfiguration;
core.initialize(
config,
[trackPlugin, channelPlugin]);
this.ctx.core = core;
this.ctx.channelSpy = channelSpy;
Assert.ok(channelSpy.calledOnce, "channel should not be called once");
Assert.ok(core.eventCnt() == 0, "Event should not be queued");
let activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status");
Assert.ok(channelSpy.calledOnce, "channel should be called once");
Assert.ok(core.eventCnt() == 0, "Event should be released");
let evt = channelSpy.args[0][0];
Assert.equal(evt.iKey, "testIkey", "event ikey should be set");
activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.ACTIVE, "default should be active status");
let ikeyPromise = createAsyncResolvedPromise("testIkey1");
let urlPromise = createAsyncResolvedPromise("testUrl1");
core.config.instrumentationKey = ikeyPromise;
core.config.endpointUrl = urlPromise;
this.clock.tick(1);
activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
}].concat(PollingAssert.createPollingAssert(() => {
let core = this.ctx.core;
let activeStatus = core.activeStatus();
let channelSpy = this.ctx.channelSpy
if (activeStatus === ActiveStatus.ACTIVE) {
Assert.equal(core.config.instrumentationKey, "testIkey1", "channel testIkey should not be changed");
Assert.equal(core.config.endpointUrl, "testUrl1", "channel endpoint should be changed");
core.track({name: "test2"});
Assert.ok(core.eventCnt() == 0, "Event should not be queued test1");
let evt = channelSpy.args[1][0];
Assert.equal(evt.name, "test2", "event name should be set test2");
Assert.equal(evt.iKey, "testIkey1", "event ikey should be set test1");
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCaseAsync({
name: "ApplicationInsightsCore Init: init with ikey resolved promise, endpoint url resolved promise, dynamic change with promise",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
let trackPlugin = new TrackPlugin();
let channelPlugin = new ChannelPlugin();
channelPlugin.priority = 1001;
let core = new AppInsightsCore();
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
this.ctx.core = core;
this.ctx.channelSpy = channelSpy;
let ikeyPromise = createAsyncResolvedPromise("testIkey");
let urlPromise = createAsyncResolvedPromise("testUrl");
let config = {
instrumentationKey: ikeyPromise,
endpointUrl: urlPromise,
initTimeOut: 80000
} as IConfiguration;
core.initialize(
config,
[trackPlugin, channelPlugin]);
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
Assert.ok(core.eventCnt() == 1, "Event should be queued");
let activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
}].concat(PollingAssert.createPollingAssert(() => {
let core = this.ctx.core;
let activeStatus = core.activeStatus();
let channelSpy = this.ctx.channelSpy;
if (activeStatus === ActiveStatus.ACTIVE) {
Assert.equal(activeStatus, ActiveStatus.ACTIVE, "active status should be set to active");
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed");
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed");
Assert.ok(channelSpy.calledOnce, "channel should be called once");
Assert.ok(core.eventCnt() == 0, "Event should be released");
let evt = channelSpy.args[0][0];
Assert.equal(evt.iKey, "testIkey", "event ikey should be set");
let ikeyPromise = createAsyncResolvedPromise("testIkey1");
let urlPromise = createAsyncResolvedPromise("testUrl1");
core.config.instrumentationKey = ikeyPromise;
core.config.endpointUrl = urlPromise;
this.ctx.secondCall = true;
//Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending test1");
return true;
}
return false;
}, "Wait for promise first response" + new Date().toISOString(), 60, 1000) as any).concat(PollingAssert.createPollingAssert(() => {
let core = this.ctx.core;
let activeStatus = core.activeStatus();
let channelSpy = this.ctx.channelSpy;
if (this.ctx.secondCall && activeStatus === ActiveStatus.ACTIVE) {
Assert.equal(activeStatus, ActiveStatus.ACTIVE, "active status should be set to active test1");
Assert.equal(core.config.instrumentationKey, "testIkey1", "channel testIkey should not be changed test1");
Assert.equal(core.config.endpointUrl, "testUrl1", "channel endpoint should be changed test1");
Assert.ok(core.eventCnt() == 0, "Event should be released");
core.track({name: "test1"});
let evt = channelSpy.args[1][0];
Assert.equal(evt.name, "test1", "event name should be set test2");
Assert.equal(evt.iKey, "testIkey1", "event ikey should be set test1");
return true;
}
return false;
}, "Wait for promise second response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCaseAsync({
name: "ApplicationInsightsCore Init: init with ikey promise, endpoint url promise, dynamic changed with strings",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
let trackPlugin = new TrackPlugin();
let channelPlugin = new ChannelPlugin();
channelPlugin.priority = 1001;
let core = new AppInsightsCore();
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
let ikeyPromise = createAsyncResolvedPromise("testIkey");
let urlPromise = createAsyncResolvedPromise("testUrl");
let unresolveIkeyPromise = createAsyncPromise((resolve, reject) => {
//do nothing,
}) // init with it, it should be pending
let newIkeyPromise = createAsyncPromise((resolve, reject) => {
resolve("ikey")
}) // init with it, pending, no changes or string
// resolve first one, active
let config = {
instrumentationKey: ikeyPromise,
endpointUrl: urlPromise,
initTimeOut: 80000
} as IConfiguration;
core.initialize(
config,
[trackPlugin, channelPlugin]);
this.ctx.core = core;
this.ctx.channelSpy = channelSpy;
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
Assert.ok(core.eventCnt() == 1, "Event should be queued");
let activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.PENDING, "default should be pending status");
// status is pending, following changes should not be applied
core.config.instrumentationKey = "testIkey1";
core.config.endpointUrl = "testUrl1";
}].concat(PollingAssert.createPollingAssert(() => {
let core = this.ctx.core;
let activeStatus = core.activeStatus();
let channelSpy = this.ctx.channelSpy
if (activeStatus === ActiveStatus.ACTIVE) {
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed");
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed");
Assert.ok(core.eventCnt() == 0, "Event should not be queued test1");
let evt1 = channelSpy.args[0][0];
Assert.equal(evt1.iKey, "testIkey", "event ikey should be set test1");
this.clock.tick(1);
core.track({name: "test2"});
let evt2 = channelSpy.args[1][0];
Assert.equal(evt2.name, "test2", "event name should be set test2");
Assert.equal(evt2.iKey, "testIkey", "event ikey should be set test1");
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCaseAsync({
name: "ApplicationInsightsCore Init: init with ikey promise, endpoint url promise, dynamic changed with strings while waiting promises",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
let trackPlugin = new TrackPlugin();
let channelPlugin = new ChannelPlugin();
channelPlugin.priority = 1001;
let core = new AppInsightsCore();
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
let urlPromise = createAsyncResolvedPromise("testUrl");
let resolveFunc;
let ikeyPromise = createAsyncPromise((resolve, reject) => {
resolveFunc = resolve;
//do nothing, mock unresolve
});
let config = {
instrumentationKey: ikeyPromise,
endpointUrl: urlPromise,
initTimeOut: 80000
} as IConfiguration;
core.initialize(
config,
[trackPlugin, channelPlugin]);
this.ctx.core = core;
this.ctx.channelSpy = channelSpy;
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
Assert.ok(core.eventCnt() == 1, "Event should be queued");
let activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.PENDING, "default should be pending status");
// status is pending, following changes should not be applied
core.config.instrumentationKey = "testIkey1";
this.clock.tick(1);
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
Assert.ok(core.eventCnt() == 1, "Event should be queued");
activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.PENDING, "default should be pending status");
resolveFunc("testIkey");
}].concat(PollingAssert.createPollingAssert(() => {
let core = this.ctx.core;
let activeStatus = core.activeStatus();
let channelSpy = this.ctx.channelSpy
if (activeStatus === ActiveStatus.ACTIVE) {
Assert.equal(core.config.instrumentationKey, "testIkey", "channel testIkey should not be changed");
Assert.equal(core.config.endpointUrl, "testUrl", "channel endpoint should be changed");
Assert.ok(core.eventCnt() == 0, "Event should not be queued test1");
let evt1 = channelSpy.args[0][0];
Assert.equal(evt1.iKey, "testIkey", "event ikey should be set test1");
this.clock.tick(1);
core.track({name: "test2"});
let evt2 = channelSpy.args[1][0];
Assert.equal(evt2.name, "test2", "event name should be set test2");
Assert.equal(evt2.iKey, "testIkey", "event ikey should be set test1");
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCaseAsync({
name: "ApplicationInsightsCore Init: init with ikey and endpoint timeout promises",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
let trackPlugin = new TrackPlugin();
let channelPlugin = new ChannelPlugin();
channelPlugin.priority = 1001;
let core = new AppInsightsCore();
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
this.ctx.core = core;
this.ctx.channelSpy = channelSpy;
let ikeyPromise = createTimeoutPromise(60, true,"testIkey");
let urlPromise = createTimeoutPromise(60, true, "testUrl");
let config = {
instrumentationKey: ikeyPromise,
endpointUrl: urlPromise,
initTimeOut: 1
} as IConfiguration;
core.initialize(
config,
[trackPlugin, channelPlugin]);
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
Assert.ok(core.eventCnt() == 1, "Event should be queued");
let activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
}].concat(PollingAssert.createPollingAssert(() => {
let core = this.ctx.core;
let activeStatus = core.activeStatus();
let channelSpy = this.ctx.channelSpy;
if (activeStatus === ActiveStatus.INACTIVE) {
Assert.ok(!channelSpy.calledOnce, "channel should not be called once");
Assert.ok(core.eventCnt() == 0, "Event should be released");
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCaseAsync({
name: "ApplicationInsightsCore Init: init with ikey timeout promises and endpoint promises",
stepDelay: 100,
useFakeTimers: true,
steps: [() => {
let channelPlugin = new ChannelPlugin();
channelPlugin.priority = 1001;
let core = new AppInsightsCore();
let channelSpy = this.sandbox.stub(channelPlugin, "processTelemetry");
let ikeyPromise = createTimeoutPromise(20, true, "testIkey1");
let urlPromise = createTimeoutPromise(1, true, "testUrl1");
let config = {
instrumentationKey: ikeyPromise,
endpointUrl: urlPromise,
initTimeOut: 6
} as IConfiguration;
core.initialize(
config,
[channelPlugin]);
this.ctx.core = core;
this.ctx.channelSpy = channelSpy;
let activeStatus = core.activeStatus();
Assert.equal(activeStatus, ActiveStatus.PENDING, "active status should be set to pending");
Assert.ok(!channelSpy.calledOnce, "channel should not be called");
core.track({name: "testEvent"});
}].concat(PollingAssert.createPollingAssert(() => {
let core = this.ctx.core;
let activeStatus = core.activeStatus();
let channelSpy = this.ctx.channelSpy
if (activeStatus === ActiveStatus.INACTIVE) {
Assert.ok(core.eventCnt() == 0, "Event should be released");
Assert.ok(!channelSpy.called, "channel should not be called");
return true;
}
return false;
}, "Wait for promise response" + new Date().toISOString(), 60, 1000) as any)
});
this.testCase({
name: 'newId tests length',
@ -1186,9 +2000,11 @@ class ChannelPlugin implements IChannelControls {
}
public initialize = (config: IConfiguration) => {
}
public _processTelemetry(env: ITelemetryItem) {
console.log(JSON.stringify(env))
}
}
@ -1295,7 +2111,6 @@ class TestOfflineChannelPlugin implements IChannelControls {
this.events.push(env);
// Just calling processTelemetry as this is the original design of the Plugins (as opposed to the newer processNext())
this._nextPlugin?.processTelemetry(env);
}
}

Просмотреть файл

@ -0,0 +1,30 @@
import { createEnumStyle } from "./EnumHelperFuncs";
export const enum eActiveStatus {
// None
NONE = 0,
/**
* inactive status means there might be rejected ikey/endpoint promises or ikey/endpoint resolved is not valid
*/
INACTIVE = 1,
/**
* active mean ikey/endpoint promises is resolved and initializing with ikey/endpoint is successful
*/
ACTIVE = 2,
/**
* Waiting for promises to be resolved
* NOTE: if status is set to be pending, incoming changes will be dropped until pending status is removed
*/
PENDING = 3,
}
export const ActiveStatus = createEnumStyle<typeof eActiveStatus>({
NONE: eActiveStatus.NONE,
PENDING: eActiveStatus.PENDING,
INACTIVE: eActiveStatus.INACTIVE,
ACTIVE: eActiveStatus.ACTIVE
});
export type ActiveStatus = number | eActiveStatus;

Просмотреть файл

@ -126,7 +126,8 @@ export const enum _eInternalMessageId {
DynamicConfigException = 108,
DefaultThrottleMsgKey = 109,
CdnDeprecation = 110,
SdkLdrUpdate = 111
SdkLdrUpdate = 111,
InitPromiseException = 112
}
export type _InternalMessageId = number | _eInternalMessageId;

Просмотреть файл

@ -4,6 +4,7 @@
import { IPromise } from "@nevware21/ts-async";
import { ITimerHandler } from "@nevware21/ts-utils";
import { WatcherFunction } from "../Config/IDynamicWatcher";
import { eActiveStatus } from "../JavaScriptSDK.Enums/InitActiveStatusEnum";
import { SendRequestReason } from "../JavaScriptSDK.Enums/SendRequestReason";
import { UnloadHandler } from "../JavaScriptSDK/UnloadHandlerContainer";
import { IChannelControls } from "./IChannelControls";
@ -225,4 +226,22 @@ export interface IAppInsightsCore<CfgType extends IConfiguration = IConfiguratio
* Function used to identify the get w parameter used to identify status bit to some channels
*/
getWParam: () => number;
/**
* Watches and tracks status of initialization process
* @returns ActiveStatus
* @since 3.3.0
* If returned status is active, it means initialization process is completed.
* If returned status is pending, it means the initialization process is waiting for promieses to be resolved.
* If returned status is inactive, it means ikey is invalid or can 't get ikey or enpoint url from promsises.
*/
activeStatus?: () => eActiveStatus | number;
/**
* Set Active Status to pending, which will block the incoming changes until internal promises are resolved
* @internal Internal use
* @since 3.3.0
*/
_setPendingStatus?: () => void;
}

Просмотреть файл

@ -1,5 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import { IPromise } from "@nevware21/ts-async";
import { IAppInsightsCore } from "./IAppInsightsCore";
import { IChannelControls } from "./IChannelControls";
import { ICookieMgrConfig } from "./ICookieMgr";
@ -17,12 +18,12 @@ export interface IConfiguration {
/**
* Instrumentation key of resource. Either this or connectionString must be specified.
*/
instrumentationKey?: string;
instrumentationKey?: string| IPromise<string>;
/**
* Connection string of resource. Either this or instrumentationKey must be specified.
*/
connectionString?: string;
connectionString?: string | IPromise<string> ;
/**
* Set the timer interval (in ms) for internal logging queue, this is the
@ -72,7 +73,7 @@ export interface IConfiguration {
/**
* Endpoint where telemetry data is sent
*/
endpointUrl?: string;
endpointUrl?: string | IPromise<string>;
/**
* Extension configs loaded in SDK
@ -190,4 +191,21 @@ export interface IConfiguration {
* @defaultValue undefined
*/
featureOptIn?: IFeatureOptIn;
/**
* If your connection string, instrumentation key and endpoint url are promises,
* this config is to manually set timeout for those promises.
* Default: 50000ms
* @since 3.3.0
*/
initTimeOut?: number;
/**
* If your connection string, instrumentation key and endpoint url are promises,
* this config is to manually set in memory proxy track calls count limit before promises finished.
* Default: 100
* @since 3.3.0
*/
initInMemoMaxSize?: number;
}

Просмотреть файл

@ -3,16 +3,17 @@
"use strict";
import dynamicProto from "@microsoft/dynamicproto-js";
import { IPromise, createPromise } from "@nevware21/ts-async";
import { IPromise, createAllSettledPromise, createPromise, doAwaitResponse } from "@nevware21/ts-async";
import {
ITimerHandler, arrAppend, arrForEach, arrIndexOf, createTimeout, deepExtend, hasDocument, isFunction, isNullOrUndefined, isPlainObject,
objDeepFreeze, objDefine, objForEachKey, objFreeze, objHasOwn, scheduleTimeout, throwError
isPromiseLike, objDeepFreeze, objDefine, objForEachKey, objFreeze, objHasOwn, scheduleTimeout, throwError
} from "@nevware21/ts-utils";
import { createDynamicConfig, onConfigChange } from "../Config/DynamicConfig";
import { IConfigDefaults } from "../Config/IConfigDefaults";
import { IDynamicConfigHandler, _IInternalDynamicConfigHandler } from "../Config/IDynamicConfigHandler";
import { IWatchDetails, WatcherFunction } from "../Config/IDynamicWatcher";
import { eEventsDiscardedReason } from "../JavaScriptSDK.Enums/EventsDiscardedReason";
import { ActiveStatus, eActiveStatus } from "../JavaScriptSDK.Enums/InitActiveStatusEnum";
import { _eInternalMessageId, eLoggingSeverity } from "../JavaScriptSDK.Enums/LoggingEnums";
import { SendRequestReason } from "../JavaScriptSDK.Enums/SendRequestReason";
import { TelemetryUnloadReason } from "../JavaScriptSDK.Enums/TelemetryUnloadReason";
@ -41,7 +42,7 @@ import { createCookieMgr } from "./CookieMgr";
import { createUniqueNamespace } from "./DataCacheHelper";
import { getDebugListener } from "./DbgExtensionUtils";
import { DiagnosticLogger, _InternalLogMessage, _throwInternal, _warnToConsole } from "./DiagnosticLogger";
import { getSetValue, proxyFunctionAs, proxyFunctions, toISOString } from "./HelperFuncs";
import { getSetValue, isNotNullOrUndefined, proxyFunctionAs, proxyFunctions, toISOString } from "./HelperFuncs";
import {
STR_CHANNELS, STR_CREATE_PERF_MGR, STR_DISABLED, STR_EMPTY, STR_EXTENSIONS, STR_EXTENSION_CONFIG, UNDEFINED_VALUE
} from "./InternalConstants";
@ -59,6 +60,8 @@ const strValidationError = "Plugins must provide initialize method";
const strNotificationManager = "_notificationManager";
const strSdkUnloadingError = "SDK is still unloading...";
const strSdkNotInitialized = "SDK is not initialized";
const maxInitQueueSize = 100;
const maxInitTimeout = 50000;
// const strPluginUnloadFailed = "Failed to unload plugin";
/**
@ -292,6 +295,11 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
let _extensions: IPlugin[];
let _pluginVersionStringArr: string[];
let _pluginVersionString: string;
let _activeStatus: eActiveStatus; // to indicate if ikey or endpoint url promised is resolved or not
let _endpoint: string;
let _initInMemoMaxSize: number; // max event count limit during wait for init promises to be resolved
let _isStatusSet: boolean; // track if active status is set in case of init timeout and init promises setting the status twice
let _initTimer: ITimerHandler;
/**
* Internal log poller
@ -307,11 +315,20 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
// Special internal method to allow the unit tests and DebugPlugin to hook embedded objects
_self["_getDbgPlgTargets"] = () => {
return [_extensions];
return [_extensions, _eventQueue];
};
_self.isInitialized = () => _isInitialized;
// since version 3.3.0
_self.activeStatus = () => _activeStatus;
// since version 3.3.0
// internal
_self._setPendingStatus = () => {
_activeStatus = eActiveStatus.PENDING;
};
// Creating the self.initialize = ()
_self.initialize = (config: CfgType, extensions: IPlugin[], logger?: IDiagnosticLogger, notificationManager?: INotificationManager): void => {
if (_isUnloading) {
@ -330,8 +347,122 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
// This will be "re-run" if the referenced config properties are changed
_addUnloadHook(_configHandler.watch((details) => {
_instrumentationKey = details.cfg.instrumentationKey;
let rootCfg = details.cfg;
let isPending = _activeStatus === eActiveStatus.PENDING;
if (isPending){
// means waiting for previous promises to be resolved, won't apply new changes
return;
}
_initInMemoMaxSize = rootCfg.initInMemoMaxSize || maxInitQueueSize;
// 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
if (isNullOrUndefined(ikey)) {
_instrumentationKey = null;
// if new ikey is null, set status to be inactive, all new events will be saved in memory or dropped
_activeStatus = ActiveStatus.INACTIVE;
let msg = "Please provide instrumentation key";
if (!_isInitialized) {
// only throw error during initialization
throwError(msg);
} else {
_throwInternal(_logger, eLoggingSeverity.CRITICAL, _eInternalMessageId.InvalidInstrumentationKey, msg);
_releaseQueues();
}
return;
}
let promises: IPromise<string>[] = [];
if (isPromiseLike(ikey)) {
promises.push(ikey);
_instrumentationKey = null; // reset current local ikey variable (otherwise it will always be the previous ikeys if timeout is called before promise cb)
} else {
// string
_instrumentationKey = ikey;
}
if (isPromiseLike(endpointUrl)) {
promises.push(endpointUrl);
_endpoint = null; // reset current local endpoint variable (otherwise it will always be the previous urls if timeout is called before promise cb)
} else {
// string or null
_endpoint = endpointUrl;
}
// at least have one promise
if (promises.length) {
// reset to false for new dynamic changes
_isStatusSet = false;
_activeStatus = eActiveStatus.PENDING;
let initTimeout = isNotNullOrUndefined(rootCfg.initTimeOut)? rootCfg.initTimeOut : maxInitTimeout; // rootCfg.initTimeOut could be 0
let allPromises = createAllSettledPromise<string>(promises);
_initTimer = scheduleTimeout(() => {
// set _isStatusSet to true
// set active status
// release queues
_initTimer = null;
if (!_isStatusSet) {
_setStatus();
}
}, initTimeout);
doAwaitResponse(allPromises, (response) => {
try {
if (_isStatusSet) {
// promises take too long to resolve, ignore them
// active status should be set by timeout already
return;
}
if (!response.rejected) {
let values = response.value;
if (values && values.length) {
// ikey
let ikeyRes = values[0];
_instrumentationKey = ikeyRes && ikeyRes.value;
// endpoint
if (values.length > 1) {
let endpointRes = values[1];
_endpoint = endpointRes && endpointRes.value;
}
}
if (_instrumentationKey) {
// if ikey is null, no need to trigger extra dynamic changes for extensions
config.instrumentationKey = _instrumentationKey; // set config.instrumentationKey for extensions to consume
config.endpointUrl = _endpoint; // set config.endpointUrl for extensions to consume
}
}
// set _isStatusSet to true
// set active status
// release queues
_setStatus();
} catch (e) {
if (!_isStatusSet){
_setStatus();
}
}
});
} else {
// means no promises
_setStatus();
}
//_instrumentationKey = details.cfg.instrumentationKey;
// Mark the extensionConfig and all first level keys as referenced
// This is so that calls to getExtCfg() will always return the same object
// Even when a user may "re-assign" the plugin properties (or it's unloaded/reloaded)
@ -339,10 +470,8 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
objForEachKey(extCfg, (key) => {
details.ref(extCfg, key);
});
if (isNullOrUndefined(_instrumentationKey)) {
throwError("Please provide instrumentation key");
}
}));
_notificationManager = notificationManager;
@ -377,9 +506,10 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
_cfgListeners = null;
_isInitialized = true;
_self.releaseQueue();
_self.pollInternalLogs();
if (_activeStatus === ActiveStatus.ACTIVE) {
_releaseQueues();
}
};
_self.getChannels = (): IChannelControls[] => {
@ -416,12 +546,16 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
// Common Schema 4.0
telemetryItem.ver = telemetryItem.ver || "4.0";
if (!_isUnloading && _self.isInitialized()) {
if (!_isUnloading && _self.isInitialized() && _activeStatus === ActiveStatus.ACTIVE) {
// Process the telemetry plugin chain
_createTelCtx().processNext(telemetryItem);
} else {
} else if (_activeStatus !== ActiveStatus.INACTIVE){
// Queue events until all extensions are initialized
_eventQueue.push(telemetryItem);
if (_eventQueue.length <= _initInMemoMaxSize) {
// set limit, if full, stop adding new events
_eventQueue.push(telemetryItem);
}
}
}, () => ({ item: telemetryItem }), !((telemetryItem as any).sync));
};
@ -490,10 +624,18 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
if (_isInitialized && _eventQueue.length > 0) {
let eventQueue = _eventQueue;
_eventQueue = [];
if (_activeStatus === eActiveStatus.ACTIVE) {
arrForEach(eventQueue, (event: ITelemetryItem) => {
event.iKey = event.iKey || _instrumentationKey;
_createTelCtx().processNext(event);
});
arrForEach(eventQueue, (event: ITelemetryItem) => {
_createTelCtx().processNext(event);
});
} else {
// new one for msg ikey
_throwInternal(_logger, eLoggingSeverity.WARNING, _eInternalMessageId.FailedToSendQueuedTelemetry, "core init status is not active");
}
}
};
@ -505,6 +647,25 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
return _startLogPoller(true);
};
function _setStatus() {
_isStatusSet = true;
if (isNullOrUndefined(_instrumentationKey)) {
_activeStatus = ActiveStatus.INACTIVE;
_throwInternal(_logger, eLoggingSeverity.CRITICAL, _eInternalMessageId.InitPromiseException, "ikey can't be resolved from promises");
} else {
_activeStatus = ActiveStatus.ACTIVE;
}
_releaseQueues();
}
function _releaseQueues() {
if (_isInitialized) {
_self.releaseQueue();
_self.pollInternalLogs();
}
}
function _startLogPoller(alwaysStart?: boolean): ITimerHandler {
if ((!_internalLogPoller || !_internalLogPoller.enabled) && !_forceStopInternalLogPoller) {
let shouldStart = alwaysStart || (_logger && _logger.queue.length > 0);
@ -872,6 +1033,11 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
_forceStopInternalLogPoller = false;
_internalLogPoller = null;
_internalLogPollerListening = false;
_activeStatus = eActiveStatus.NONE; // default is None
_endpoint = null;
_initInMemoMaxSize = null;
_isStatusSet = false;
_initTimer = null;
}
function _createTelCtx(): IProcessTelemetryContext {
@ -1403,6 +1569,30 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
return null;
}
/**
* Watches and tracks status of initialization process
* @returns ActiveStatus
* @since 3.3.0
* If returned status is active, it means initialization process is completed.
* If returned status is pending, it means the initialization process is waiting for promieses to be resolved.
* If returned status is inactive, it means ikey is invalid or can 't get ikey or enpoint url from promsises.
*/
public activeStatus(): eActiveStatus | number {
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
return null;
}
/**
* Set Active Status to pending, which will block the incoming changes until internal promises are resolved
* @internal Internal use
* @since 3.3.0
*/
public _setPendingStatus(): void {
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
return null;
}
protected releaseQueue() {
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
}

Просмотреть файл

@ -18,6 +18,7 @@ export { eEventsDiscardedReason, EventsDiscardedReason, eBatchDiscardedReason, B
export { SendRequestReason, TransportType } from "./JavaScriptSDK.Enums/SendRequestReason";
export { TelemetryUpdateReason } from "./JavaScriptSDK.Enums/TelemetryUpdateReason";
export { TelemetryUnloadReason } from "./JavaScriptSDK.Enums/TelemetryUnloadReason";
export { eActiveStatus, ActiveStatus } from "./JavaScriptSDK.Enums/InitActiveStatusEnum"
export { throwAggregationError } from "./JavaScriptSDK/AggregationError";
export { AppInsightsCore } from "./JavaScriptSDK/AppInsightsCore";
export { BaseTelemetryPlugin } from "./JavaScriptSDK/BaseTelemetryPlugin";

Просмотреть файл

@ -56,7 +56,7 @@ declare var cfg:ISnippetConfig;
function _parseConnectionString() {
let fields:Fields = {};
let connectionString = aiConfig.connectionString;
if (connectionString) {
if (typeof connectionString === "string" && connectionString) {
let kvPairs = connectionString.split(";");
for (let lp = 0; lp < kvPairs.length; lp++) {
let kvParts = kvPairs[lp].split("=");