Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Main] Add ability to disable the pollInternalLogs via config and change to stop using setInterval #2055 #2057

Merged
merged 1 commit into from
Apr 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions AISKU/Tests/Unit/src/applicationinsights.e2e.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,8 @@ export class ApplicationInsightsTests extends AITestClass {
this.testCaseAsync({
name: "TelemetryContext: auto collection of ajax requests",
stepDelay: 1,
useFakeServer: true,
fakeServerAutoRespond: true,
steps: [
() => {
const xhr = new XMLHttpRequest();
Expand All @@ -708,6 +710,8 @@ export class ApplicationInsightsTests extends AITestClass {
this.testCaseAsync({
name: "DependenciesPlugin: auto collection of outgoing fetch requests " + (this.isFetchPolyfill ? " using polyfill " : ""),
stepDelay: 5000,
useFakeFetch: true,
fakeFetchAutoRespond: true,
steps: [
() => {
fetch('https://httpbin.org/status/200', { method: 'GET', headers: { 'header': 'value'} });
Expand All @@ -721,8 +725,7 @@ export class ApplicationInsightsTests extends AITestClass {
fetch('https://httpbin.org/status/200');
Assert.ok(true, "fetch monitoring is instrumented");
}
]
.concat(this.asserts(3, false, false))
].concat(this.asserts(3, false, false))
.concat(() => {
let args = [];
this.trackSpy.args.forEach(call => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
IAppInsightsCore, IDiagnosticLogger, IProcessTelemetryUnloadContext, ITelemetryUnloadState, _eInternalMessageId, _throwInternal,
arrForEach, dumpObj, eLoggingSeverity, getDocument, getExceptionName, getLocation, isNullOrUndefined
} from "@microsoft/applicationinsights-core-js";
import { isWebWorker } from "@nevware21/ts-utils";
import { ITimerHandler, isWebWorker, scheduleTimeout } from "@nevware21/ts-utils";
import { PageViewPerformanceManager } from "./PageViewPerformanceManager";

/**
Expand All @@ -32,7 +32,7 @@ export class PageViewManager {
pageViewPerformanceManager: PageViewPerformanceManager) {

dynamicProto(PageViewManager, this, (_self) => {
let intervalHandle: any = null;
let queueTimer: ITimerHandler = null;
let itemQueue: Array<() => boolean> = [];
let pageViewPerformanceSent: boolean = false;
let _logger: IDiagnosticLogger;
Expand All @@ -47,11 +47,10 @@ export class PageViewManager {
}
}

function _addQueue(cb:() => boolean) {
itemQueue.push(cb);

if (!intervalHandle) {
intervalHandle = setInterval((() => {
function _startTimer() {
if (!queueTimer) {
queueTimer = scheduleTimeout((() => {
queueTimer = null;
let allItems = itemQueue.slice(0);
let doFlush = false;
itemQueue = [];
Expand All @@ -64,9 +63,8 @@ export class PageViewManager {
}
});

if (itemQueue.length === 0) {
clearInterval(intervalHandle);
intervalHandle = null;
if (itemQueue.length > 0) {
_startTimer();
}

if (doFlush) {
Expand All @@ -77,6 +75,12 @@ export class PageViewManager {
}
}

function _addQueue(cb:() => boolean) {
itemQueue.push(cb);

_startTimer();
}

_self.trackPageView = (pageView: IPageViewTelemetry, customProperties?: { [key: string]: any }) => {
let name = pageView.name;
if (isNullOrUndefined(name) || typeof name !== "string") {
Expand Down Expand Up @@ -211,9 +215,9 @@ export class PageViewManager {
};

_self.teardown = (unloadCtx?: IProcessTelemetryUnloadContext, unloadState?: ITelemetryUnloadState) => {
if (intervalHandle) {
clearInterval(intervalHandle);
intervalHandle = null;
if (queueTimer) {
clearInterval(queueTimer);
queueTimer = null;

let allItems = itemQueue.slice(0);
let doFlush = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { IInternal } from "@microsoft/applicationinsights-common";
import { IUnloadHookContainer, onConfigChange } from "@microsoft/applicationinsights-core-js";
import { IPropertiesConfig } from "../Interfaces/IPropertiesConfig";

const Version = "2.8.5";
const Version = "#version#";

export class Internal implements IInternal {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ export interface IConfiguration {
connectionString?: string;

/**
* Polling interval (in ms) for internal logging queue
* Set the timer interval (in ms) for internal logging queue, this is the
* amount of time to wait after logger.queue messages are detected to be sent.
* Note: since 3.0.1 and 2.8.13 the diagnostic logger timer is a normal timeout timer
* and not an interval timer. So this now represents the timer "delay" and not
* the frequency at which the events are sent.
*/
diagnosticLogInterval?: number;

Expand Down
100 changes: 61 additions & 39 deletions shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

import dynamicProto from "@microsoft/dynamicproto-js";
import {
ITimerHandler, arrAppend, arrForEach, arrIndexOf, deepExtend, hasDocument, isFunction, isNullOrUndefined, isPlainObject, objDeepFreeze,
objDefine, objForEachKey, objFreeze, objHasOwn, scheduleInterval, scheduleTimeout, throwError
ITimerHandler, arrAppend, arrForEach, arrIndexOf, createTimeout, deepExtend, hasDocument, isFunction, isNullOrUndefined, isPlainObject,
objDeepFreeze, objDefine, objForEachKey, objFreeze, objHasOwn, scheduleTimeout, throwError
} from "@nevware21/ts-utils";
import { createDynamicConfig, onConfigChange } from "../Config/DynamicConfig";
import { IConfigDefaults } from "../Config/IConfigDefaults";
Expand Down Expand Up @@ -261,6 +261,7 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
*/
let _internalLogPoller: ITimerHandler;
let _internalLogPollerListening: boolean;
let _forceStopInternalLogPoller: boolean;

dynamicProto(AppInsightsCore, this, (_self) => {

Expand Down Expand Up @@ -470,47 +471,56 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
}
};

/**
* Periodically check logger.queue for log messages to be flushed
*/
_self.pollInternalLogs = (eventName?: string): ITimerHandler => {
_internalLogsEventName = eventName || null;
_forceStopInternalLogPoller = false;
_internalLogPoller && _internalLogPoller.cancel();

function _startLogPoller(config: CfgType) {
let interval: number = config.diagnosticLogInterval;
if (!interval || !(interval > 0)) {
interval = 10000;
}
return _startLogPoller(true);
};

_internalLogPoller && _internalLogPoller.cancel();
_internalLogPoller = scheduleInterval(() => {
_flushInternalLogs();
}, interval) as any;
}
function _startLogPoller(alwaysStart?: boolean): ITimerHandler {
if ((!_internalLogPoller || !_internalLogPoller.enabled) && !_forceStopInternalLogPoller) {
Fixed Show fixed Hide fixed
let shouldStart = alwaysStart || (_self.logger && _self.logger.queue.length > 0);
if (shouldStart) {
if (!_internalLogPollerListening) {
_internalLogPollerListening = true;

// listen for any configuration changes so that changes to the
// interval will cause the timer to be re-initialized
_addUnloadHook(_configHandler.watch((details) => {
let interval: number = details.cfg.diagnosticLogInterval;
if (!interval || !(interval > 0)) {
interval = 10000;
}

if (!_internalLogPollerListening) {
_internalLogPollerListening = true;
// listen to the configuration
_addUnloadHook(_configHandler.watch((details) => {
_startLogPoller(details.cfg);
}));
} else {
// We are being called again, so make sure the poller is running
_startLogPoller(_configHandler.cfg);
let isRunning = false;
if (_internalLogPoller) {
// It was already created so remember it's running and cancel
isRunning = _internalLogPoller.enabled;
_internalLogPoller.cancel();
}

// Create / reconfigure
_internalLogPoller = createTimeout(_flushInternalLogs, interval) as any;
_internalLogPoller.unref();

// Restart if previously running
_internalLogPoller.enabled = isRunning;
}));
}

_internalLogPoller.enabled = true;
}
}

return _internalLogPoller;
}

/**
* Stop polling log messages from logger.queue
*/
_self.stopPollingInternalLogs = (): void => {
if (_internalLogPoller) {
_internalLogPoller.cancel();
_internalLogPoller = null;
_flushInternalLogs();
}
_forceStopInternalLogPoller = true;
_internalLogPoller && _internalLogPoller.cancel();
_flushInternalLogs();
}

// Add addTelemetryInitializer
Expand Down Expand Up @@ -556,6 +566,8 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
processUnloadCtx.processNext(unloadState);
}

_flushInternalLogs();

if (!_flushChannels(isAsync, _doUnload, SendRequestReason.SdkUnload, cbTimeout)) {
_doUnload(false);
}
Expand Down Expand Up @@ -800,10 +812,14 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
_cfgListeners = [];
_pluginVersionString = null;
_pluginVersionStringArr = null;
_forceStopInternalLogPoller = false;
}

function _createTelCtx(): IProcessTelemetryContext {
return createProcessTelemetryContext(_getPluginChain(), _configHandler.cfg, _self);
let theCtx = createProcessTelemetryContext(_getPluginChain(), _configHandler.cfg, _self);
theCtx.onComplete(_startLogPoller);

return theCtx;
}

// Initialize or Re-initialize the plugins
Expand Down Expand Up @@ -968,6 +984,7 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
}

removeComplete && removeComplete(removed);
_startLogPoller();
});

unloadCtx.processNext(unloadState);
Expand All @@ -977,8 +994,10 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
}

function _flushInternalLogs() {
let queue: _InternalLogMessage[] = _self.logger ? _self.logger.queue : [];
if (queue) {
if (_self.logger && _self.logger.queue) {
let queue: _InternalLogMessage[] = _self.logger.queue.slice(0);
_self.logger.queue.length = 0;

arrForEach(queue, (logMessage: _InternalLogMessage) => {
const item: ITelemetryItem = {
name: _internalLogsEventName ? _internalLogsEventName : "InternalMessageId: " + logMessage.messageId,
Expand All @@ -989,8 +1008,6 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
};
_self.track(item);
});

queue.length = 0;
}
}

Expand Down Expand Up @@ -1088,6 +1105,7 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im

function _doUpdate(updateState: ITelemetryUpdateState): void {
let updateCtx = createProcessTelemetryUpdateContext(_getPluginChain(), _self);
updateCtx.onComplete(_startLogPoller);

if (!_self._updateHook || _self._updateHook(updateCtx, updateState) !== true) {
updateCtx.processNext(updateState);
Expand All @@ -1099,6 +1117,7 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
if (logger) {
// there should always be a logger
_throwInternal(logger, eLoggingSeverity.WARNING, _eInternalMessageId.PluginException, message);
_startLogPoller();
} else {
throwError(message);
}
Expand Down Expand Up @@ -1189,15 +1208,18 @@ export class AppInsightsCore<CfgType extends IConfiguration = IConfiguration> im
}

/**
* Periodically check logger.queue for
* Enable the timer that checks the logger.queue for log messages to be flushed.
* Note: Since 3.0.1 and 2.8.13 this is no longer an interval timer but is a normal
* timer that is only started when this function is called and then subsequently
* only _if_ there are any logger.queue messages to be sent.
*/
public pollInternalLogs(eventName?: string): ITimerHandler {
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
return null;
}

/**
* Periodically check logger.queue for
* Stop the timer that log messages from logger.queue when available
*/
public stopPollingInternalLogs(): void {
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
Expand Down