Skip to content

Commit

Permalink
[Main] Add ability to disable the pollInternalLogs via config and cha…
Browse files Browse the repository at this point in the history
…nge to stop using setInterval #2055
  • Loading branch information
MSNev committed Apr 20, 2023
1 parent 053a8a0 commit e7b7226
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 53 deletions.
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 @@ -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);
}

Check notice

Code scanning / CodeQL

Semicolon insertion Note

Avoid automated semicolon insertion (90% of all statements in
the enclosing function
have an explicit semicolon).

_internalLogPoller && _internalLogPoller.cancel();
_internalLogPoller = scheduleInterval(() => {
_flushInternalLogs();
}, interval) as any;
}
function _startLogPoller(alwaysStart?: boolean): ITimerHandler {
if ((!_internalLogPoller || !_internalLogPoller.enabled) && !_forceStopInternalLogPoller) {

Check warning

Code scanning / CodeQL

Useless conditional Warning

This negation always evaluates to true.
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 = false;
_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

0 comments on commit e7b7226

Please sign in to comment.