Skip to content

Commit

Permalink
Beta Part 1: Part of Mega Dynamic Load/Unload support
Browse files Browse the repository at this point in the history
- Refactor TelemetryPluginChain ready to start supporting load/unload
- Move TelemetryInitializer to BaseCore
- add getPlugin (will be used for remove)
  • Loading branch information
MSNev committed Feb 19, 2022
1 parent 9c2aefa commit 769b7a6
Show file tree
Hide file tree
Showing 24 changed files with 2,436 additions and 1,780 deletions.
2 changes: 1 addition & 1 deletion AISKU/Tests/Unit/src/AISKUSize.Tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { AITestClass, Assert } from "@microsoft/ai-test-framework";
import * as pako from "pako";

export class AISKUSizeCheck extends AITestClass {
private readonly MAX_DEFLATE_SIZE = 40;
private readonly MAX_DEFLATE_SIZE = 41;
private readonly rawFilePath = "../dist/applicationinsights-web.min.js";
private readonly prodFilePath = "../browser/ai.2.min.js";

Expand Down
2,296 changes: 1,206 additions & 1,090 deletions common/config/rush/npm-shrinkwrap.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ export class ApplicationInsightsCoreTests extends AITestClass {

// TODO: test stopPollingInternalLogs
this.testCase({
name: "DiagnosticLogger: stop Polling InternalLogs",
name: "DiagnosticLogger: stop Polling InternalLogs flushes logs when not empty",
useFakeTimers: true,
test: () => {
// Setup
Expand All @@ -375,10 +375,14 @@ export class ApplicationInsightsCoreTests extends AITestClass {

// Act
appInsightsCore.stopPollingInternalLogs();
this.clock.tick(1);

// Assert postcondition
Assert.equal(2, appInsightsCore.logger.queue.length, "Queue is not empty");
// We now flush the internal logs when stop Polling internal logs is called
Assert.equal(0, appInsightsCore.logger.queue.length, "Queue is empty");

queue.push(new _InternalLogMessage(2, "Hello3"));
this.clock.tick(60000);

Assert.equal(1, appInsightsCore.logger.queue.length, "Queue is not empty");
}
});

Expand Down Expand Up @@ -408,7 +412,8 @@ export class ApplicationInsightsCoreTests extends AITestClass {
appInsightsCore.logger.throwInternal(LoggingSeverity.CRITICAL, count, "Test Error");
--count;
}
// this.clock.tick(1000);

// this.clock.tick(1000);
// Assert postcondition
Assert.equal(26, appInsightsCore.logger.queue.length, "Queue is not empty");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ import { IDiagnosticLogger } from "./IDiagnosticLogger";
import { IProcessTelemetryContext } from "./IProcessTelemetryContext";
import { IPerfManagerProvider } from "./IPerfManager";
import { ICookieMgr } from "./ICookieMgr";
import { ITelemetryInitializerHandler, TelemetryInitializerFunction } from "./ITelemetryInitializers";

"use strict";
export interface ILoadedPlugin<T extends IPlugin> {
plugin: T;
}

export interface IAppInsightsCore extends IPerfManagerProvider {

Expand Down Expand Up @@ -72,6 +75,13 @@ export interface IAppInsightsCore extends IPerfManagerProvider {
*/
removeNotificationListener?(listener: INotificationListener): void;

/**
* Add a telemetry processor to decorate or drop telemetry events.
* @param telemetryInitializer - The Telemetry Initializer function
* @returns - A ITelemetryInitializerHandler to enable the initializer to be removed
*/
addTelemetryInitializer(telemetryInitializer: TelemetryInitializerFunction): ITelemetryInitializerHandler | void;

pollInternalLogs?(eventName?: string): number;

stopPollingInternalLogs?(): void;
Expand All @@ -80,4 +90,10 @@ export interface IAppInsightsCore extends IPerfManagerProvider {
* Return a new instance of the IProcessTelemetryContext for processing events
*/
getProcessTelContext() : IProcessTelemetryContext;

/**
* Find and return the (first) plugin with the specified identifier if present
* @param pluginIdentifier
*/
getPlugin<T extends IPlugin = IPlugin>(pluginIdentifier: string): ILoadedPlugin<T>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,9 @@ export interface IInstrumentCallDetails {
* The error (exception) which occurred while executing the original method
*/
err?: Error;

/**
* The Event object from (window.event) at the start of the original call
*/
evt?: Event;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@ import { IAppInsightsCore } from "./IAppInsightsCore";
import { IDiagnosticLogger } from "./IDiagnosticLogger";
import { IConfiguration } from "./IConfiguration";
import { ITelemetryItem } from "./ITelemetryItem";
import { IPlugin } from "./ITelemetryPlugin";
import { IPlugin, ITelemetryPlugin } from "./ITelemetryPlugin";
import { ITelemetryPluginChain } from "./ITelemetryPluginChain";

export const enum GetExtCfgMergeType {
None = 0,
MergeDefaultOnly = 1,
MergeDefaultFromRootOrDefault = 2,
}

/**
* The current context for the current call to processTelemetry(), used to support sharing the same plugin instance
* between multiple AppInsights instances
Expand All @@ -27,12 +33,12 @@ export interface IProcessTelemetryContext {
/**
* Gets the current core config instance
*/
getCfg: ()=> IConfiguration;
getCfg: () => IConfiguration;

/**
* Gets the named extension config
*/
getExtCfg: <T>(identifier: string, defaultValue?:T|any) => T;
getExtCfg: <T>(identifier: string, defaultValue?: T | any, mergeDefault?: GetExtCfgMergeType) => T;

/**
* Gets the named config from either the named identifier extension or core config if neither exist then the
Expand All @@ -41,7 +47,7 @@ export interface IProcessTelemetryContext {
* @param field The config field name
* @param defaultValue The default value to return if no defined config exists
*/
getConfig: (identifier: string, field: string, defaultValue?: number | string | boolean) => number | string | boolean;
getConfig: (identifier: string, field: string, defaultValue?: number | string | boolean | string[] | RegExp[] | Function) => number | string | boolean | string[] | RegExp[] | Function;

/**
* Helper to allow plugins to check and possibly shortcut executing code only
Expand All @@ -57,14 +63,21 @@ export interface IProcessTelemetryContext {
/**
* Helper to set the next plugin proxy
*/
setNext: (nextCtx:ITelemetryPluginChain) => void;
setNext: (nextCtx: ITelemetryPluginChain) => void;

/**
* Call back for telemetry processing before it it is sent
* @param env - This is the current event being reported
*/
processNext: (env: ITelemetryItem) => void;

/**
* Synchronously iterate over the context chain running the callback for each plugin, once
* every plugin has been executed via the callback, any associated onComplete will be called.
* @param callback - The function call for each plugin in the context chain
*/
iterate: <T extends ITelemetryPlugin = ITelemetryPlugin>(callback: (plugin: T) => void) => void;

/**
* Create a new context using the core and config from the current instance
* @param plugins - The execution order to process the plugins, if null or not supplied
Expand All @@ -73,4 +86,9 @@ export interface IProcessTelemetryContext {
* order then the next plugin will be NOT set.
*/
createNew: (plugins?:IPlugin[]|ITelemetryPluginChain, startAt?:IPlugin) => IProcessTelemetryContext;

/**
* Set the function to call when the current chain has executed all processNext or unloadNext items.
*/
onComplete: (onComplete: () => void) => void;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { ITelemetryItem } from "./ITelemetryItem";

export declare type TelemetryInitializerFunction = <T extends ITelemetryItem>(item: T) => boolean | void;

export interface ITelemetryInitializerHandler {
remove(): void;
}

export interface ITelemetryInitializerContainer {
/**
* Add a telemetry processor to decorate or drop telemetry events.
* @param telemetryInitializer - The Telemetry Initializer function
* @returns - A ITelemetryInitializerHandler to enable the initializer to be removed
*/
addTelemetryInitializer(telemetryInitializer: TelemetryInitializerFunction): ITelemetryInitializerHandler | void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export interface IPlugin {
* @param pluginChain - [Optional] specifies the current plugin chain which identifies the
* set of plugins and the order they should be executed for the current request.
*/
initialize: (config: IConfiguration, core: IAppInsightsCore, extensions: IPlugin[], pluginChain?:ITelemetryPluginChain) => void;
initialize: (config: IConfiguration, core: IAppInsightsCore, extensions: IPlugin[], pluginChain?: ITelemetryPluginChain) => void;

/**
* Returns a value that indicates whether the plugin has already been previously initialized.
Expand Down
103 changes: 2 additions & 101 deletions shared/AppInsightsCore/src/JavaScriptSDK/AppInsightsCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,20 @@ import { BaseCore } from "./BaseCore";
import { IConfiguration } from "../JavaScriptSDK.Interfaces/IConfiguration";
import { IPlugin } from "../JavaScriptSDK.Interfaces/ITelemetryPlugin";
import { ITelemetryItem } from "../JavaScriptSDK.Interfaces/ITelemetryItem";
import { INotificationListener } from "../JavaScriptSDK.Interfaces/INotificationListener";
import { EventsDiscardedReason } from "../JavaScriptSDK.Enums/EventsDiscardedReason";
import { NotificationManager } from "./NotificationManager";
import { doPerf } from "./PerfManager";
import { INotificationManager } from "../JavaScriptSDK.Interfaces/INotificationManager";
import { IDiagnosticLogger } from "../JavaScriptSDK.Interfaces/IDiagnosticLogger";
import { _InternalLogMessage, DiagnosticLogger } from "./DiagnosticLogger";
import { DiagnosticLogger } from "./DiagnosticLogger";
import dynamicProto from "@microsoft/dynamicproto-js";
import { arrForEach, isNullOrUndefined, toISOString, throwError } from "./HelperFuncs";
import { isNullOrUndefined, throwError } from "./HelperFuncs";

"use strict";

export class AppInsightsCore extends BaseCore implements IAppInsightsCore {
constructor() {
super();
/**
* Internal log poller
*/
let _internalLogPoller: number = 0;

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

Expand All @@ -46,67 +41,6 @@ export class AppInsightsCore extends BaseCore implements IAppInsightsCore {
}, () => ({ item: telemetryItem }), !((telemetryItem as any).sync));
};

/**
* Adds a notification listener. The SDK calls methods on the listener when an appropriate notification is raised.
* The added plugins must raise notifications. If the plugins do not implement the notifications, then no methods will be
* called.
* @param {INotificationListener} listener - An INotificationListener object.
*/
_self.addNotificationListener = (listener: INotificationListener): void => {
let manager = _self.getNotifyMgr();
if (manager) {
manager.addNotificationListener(listener);
}
};

/**
* Removes all instances of the listener.
* @param {INotificationListener} listener - INotificationListener to remove.
*/
_self.removeNotificationListener = (listener: INotificationListener): void => {
let manager = _self.getNotifyMgr();
if (manager) {
manager.removeNotificationListener(listener);
}
}

/**
* Periodically check logger.queue for log messages to be flushed
*/
_self.pollInternalLogs = (eventName?: string): number => {
let interval = _self.config.diagnosticLogInterval;
if (!interval || !(interval > 0)) {
interval = 10000;
}
if(_internalLogPoller) {
_self.stopPollingInternalLogs();
}
_internalLogPoller = setInterval(() => {
const queue: _InternalLogMessage[] = _self.logger ? _self.logger.queue : [];
arrForEach(queue, (logMessage: _InternalLogMessage) => {
const item: ITelemetryItem = {
name: eventName ? eventName : "InternalMessageId: " + logMessage.messageId,
iKey: _self.config.instrumentationKey,
time: toISOString(new Date()),
baseType: _InternalLogMessage.dataType,
baseData: { message: logMessage.message }
};
_self.track(item);
});
queue.length = 0;
}, interval) as any;
return _internalLogPoller;
}

/**
* Stop polling log messages from logger.queue
*/
_self.stopPollingInternalLogs = (): void => {
if(!_internalLogPoller) return;
clearInterval(_internalLogPoller);
_internalLogPoller = 0;
}

function _validateTelemetryItem(telemetryItem: ITelemetryItem) {
if (isNullOrUndefined(telemetryItem.name)) {
_notifyInvalidEvent(telemetryItem);
Expand All @@ -130,37 +64,4 @@ export class AppInsightsCore extends BaseCore implements IAppInsightsCore {
public track(telemetryItem: ITelemetryItem) {
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
}

/**
* Adds a notification listener. The SDK calls methods on the listener when an appropriate notification is raised.
* The added plugins must raise notifications. If the plugins do not implement the notifications, then no methods will be
* called.
* @param {INotificationListener} listener - An INotificationListener object.
*/
public addNotificationListener(listener: INotificationListener): void {
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
}

/**
* Removes all instances of the listener.
* @param {INotificationListener} listener - INotificationListener to remove.
*/
public removeNotificationListener(listener: INotificationListener): void {
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
}

/**
* Periodically check logger.queue for
*/
public pollInternalLogs(eventName?: string): number {
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
return 0;
}

/**
* Periodically check logger.queue for
*/
public stopPollingInternalLogs(): void {
// @DynamicProtoStub -- DO NOT add any code as this will be removed during packaging
}
}
Loading

0 comments on commit 769b7a6

Please sign in to comment.