@microsoft/applicationinsights-core-js 2.7.4-nightly.2202-09 → 2.8.0-beta.2202-07

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/browser/applicationinsights-core-js.integrity.json +9 -9
  2. package/browser/applicationinsights-core-js.js +860 -457
  3. package/browser/applicationinsights-core-js.js.map +1 -1
  4. package/browser/applicationinsights-core-js.min.js +2 -2
  5. package/browser/applicationinsights-core-js.min.js.map +1 -1
  6. package/dist/applicationinsights-core-js.api.json +1193 -267
  7. package/dist/applicationinsights-core-js.api.md +54 -14
  8. package/dist/applicationinsights-core-js.d.ts +133 -45
  9. package/dist/applicationinsights-core-js.js +860 -457
  10. package/dist/applicationinsights-core-js.js.map +1 -1
  11. package/dist/applicationinsights-core-js.min.js +2 -2
  12. package/dist/applicationinsights-core-js.min.js.map +1 -1
  13. package/dist/applicationinsights-core-js.rollup.d.ts +133 -45
  14. package/dist-esm/JavaScriptSDK/AppInsightsCore.js +3 -69
  15. package/dist-esm/JavaScriptSDK/AppInsightsCore.js.map +1 -1
  16. package/dist-esm/JavaScriptSDK/BaseCore.js +237 -82
  17. package/dist-esm/JavaScriptSDK/BaseCore.js.map +1 -1
  18. package/dist-esm/JavaScriptSDK/BaseTelemetryPlugin.js +45 -19
  19. package/dist-esm/JavaScriptSDK/BaseTelemetryPlugin.js.map +1 -1
  20. package/dist-esm/JavaScriptSDK/ChannelController.js +155 -87
  21. package/dist-esm/JavaScriptSDK/ChannelController.js.map +1 -1
  22. package/dist-esm/JavaScriptSDK/Constants.js +1 -1
  23. package/dist-esm/JavaScriptSDK/CookieMgr.js +1 -1
  24. package/dist-esm/JavaScriptSDK/CoreUtils.js +2 -27
  25. package/dist-esm/JavaScriptSDK/CoreUtils.js.map +1 -1
  26. package/dist-esm/JavaScriptSDK/DbgExtensionUtils.js +1 -1
  27. package/dist-esm/JavaScriptSDK/DiagnosticLogger.js +1 -1
  28. package/dist-esm/JavaScriptSDK/EnvUtils.js +6 -6
  29. package/dist-esm/JavaScriptSDK/EnvUtils.js.map +1 -1
  30. package/dist-esm/JavaScriptSDK/HelperFuncs.js +51 -11
  31. package/dist-esm/JavaScriptSDK/HelperFuncs.js.map +1 -1
  32. package/dist-esm/JavaScriptSDK/InstrumentHooks.js +3 -1
  33. package/dist-esm/JavaScriptSDK/InstrumentHooks.js.map +1 -1
  34. package/dist-esm/JavaScriptSDK/NotificationManager.js +34 -36
  35. package/dist-esm/JavaScriptSDK/NotificationManager.js.map +1 -1
  36. package/dist-esm/JavaScriptSDK/PerfManager.js +1 -1
  37. package/dist-esm/JavaScriptSDK/ProcessTelemetryContext.js +289 -119
  38. package/dist-esm/JavaScriptSDK/ProcessTelemetryContext.js.map +1 -1
  39. package/dist-esm/JavaScriptSDK/RandomHelper.js +29 -4
  40. package/dist-esm/JavaScriptSDK/RandomHelper.js.map +1 -1
  41. package/dist-esm/JavaScriptSDK/TelemetryHelpers.js +2 -2
  42. package/dist-esm/JavaScriptSDK/TelemetryHelpers.js.map +1 -1
  43. package/dist-esm/JavaScriptSDK/TelemetryInitializerPlugin.js +82 -0
  44. package/dist-esm/JavaScriptSDK/TelemetryInitializerPlugin.js.map +1 -0
  45. package/dist-esm/JavaScriptSDK.Enums/EventsDiscardedReason.js +1 -1
  46. package/dist-esm/JavaScriptSDK.Enums/LoggingEnums.js +1 -1
  47. package/dist-esm/JavaScriptSDK.Enums/SendRequestReason.js +1 -1
  48. package/dist-esm/JavaScriptSDK.Interfaces/IAppInsightsCore.js +1 -2
  49. package/dist-esm/JavaScriptSDK.Interfaces/IAppInsightsCore.js.map +1 -1
  50. package/dist-esm/JavaScriptSDK.Interfaces/IChannelControls.js +1 -1
  51. package/dist-esm/JavaScriptSDK.Interfaces/IConfiguration.js +1 -1
  52. package/dist-esm/JavaScriptSDK.Interfaces/ICookieMgr.js +1 -1
  53. package/dist-esm/JavaScriptSDK.Interfaces/IDbgExtension.js +1 -1
  54. package/dist-esm/JavaScriptSDK.Interfaces/IDiagnosticLogger.js +1 -1
  55. package/dist-esm/JavaScriptSDK.Interfaces/IInstrumentHooks.js +1 -1
  56. package/dist-esm/JavaScriptSDK.Interfaces/INotificationListener.js +1 -1
  57. package/dist-esm/JavaScriptSDK.Interfaces/INotificationManager.js +1 -1
  58. package/dist-esm/JavaScriptSDK.Interfaces/IPerfEvent.js +1 -1
  59. package/dist-esm/JavaScriptSDK.Interfaces/IPerfManager.js +1 -1
  60. package/dist-esm/JavaScriptSDK.Interfaces/IProcessTelemetryContext.js +1 -1
  61. package/dist-esm/JavaScriptSDK.Interfaces/ITelemetryInitializers.js +6 -0
  62. package/dist-esm/JavaScriptSDK.Interfaces/ITelemetryInitializers.js.map +1 -0
  63. package/dist-esm/JavaScriptSDK.Interfaces/ITelemetryItem.js +1 -1
  64. package/dist-esm/JavaScriptSDK.Interfaces/ITelemetryPlugin.js +1 -1
  65. package/dist-esm/JavaScriptSDK.Interfaces/ITelemetryPluginChain.js +1 -1
  66. package/dist-esm/applicationinsights-core-js.js +4 -4
  67. package/dist-esm/applicationinsights-core-js.js.map +1 -1
  68. package/package.json +2 -2
  69. package/src/JavaScriptSDK/AppInsightsCore.ts +2 -101
  70. package/src/JavaScriptSDK/BaseCore.ts +330 -100
  71. package/src/JavaScriptSDK/BaseTelemetryPlugin.ts +69 -32
  72. package/src/JavaScriptSDK/ChannelController.ts +175 -103
  73. package/src/JavaScriptSDK/CoreUtils.ts +1 -28
  74. package/src/JavaScriptSDK/EnvUtils.ts +5 -5
  75. package/src/JavaScriptSDK/HelperFuncs.ts +57 -14
  76. package/src/JavaScriptSDK/InstrumentHooks.ts +3 -1
  77. package/src/JavaScriptSDK/NotificationManager.ts +32 -31
  78. package/src/JavaScriptSDK/PerfManager.ts +1 -1
  79. package/src/JavaScriptSDK/ProcessTelemetryContext.ts +350 -133
  80. package/src/JavaScriptSDK/RandomHelper.ts +34 -3
  81. package/src/JavaScriptSDK/TelemetryHelpers.ts +4 -6
  82. package/src/JavaScriptSDK/TelemetryInitializerPlugin.ts +119 -0
  83. package/src/JavaScriptSDK.Interfaces/IAppInsightsCore.ts +17 -1
  84. package/src/JavaScriptSDK.Interfaces/IChannelControls.ts +7 -3
  85. package/src/JavaScriptSDK.Interfaces/IInstrumentHooks.ts +5 -0
  86. package/src/JavaScriptSDK.Interfaces/IProcessTelemetryContext.ts +23 -5
  87. package/src/JavaScriptSDK.Interfaces/ITelemetryInitializers.ts +16 -0
  88. package/src/JavaScriptSDK.Interfaces/ITelemetryPlugin.ts +1 -1
  89. package/types/JavaScriptSDK/AppInsightsCore.d.ts +0 -21
  90. package/types/JavaScriptSDK/BaseCore.d.ts +30 -1
  91. package/types/JavaScriptSDK/BaseTelemetryPlugin.d.ts +13 -11
  92. package/types/JavaScriptSDK/ChannelController.d.ts +12 -17
  93. package/types/JavaScriptSDK/CoreUtils.d.ts +0 -6
  94. package/types/JavaScriptSDK/HelperFuncs.d.ts +14 -5
  95. package/types/JavaScriptSDK/ProcessTelemetryContext.d.ts +49 -3
  96. package/types/JavaScriptSDK/RandomHelper.d.ts +6 -0
  97. package/types/JavaScriptSDK/TelemetryHelpers.d.ts +3 -3
  98. package/types/JavaScriptSDK/TelemetryInitializerPlugin.d.ts +23 -0
  99. package/types/JavaScriptSDK.Interfaces/IAppInsightsCore.d.ts +15 -0
  100. package/types/JavaScriptSDK.Interfaces/IChannelControls.d.ts +7 -3
  101. package/types/JavaScriptSDK.Interfaces/IInstrumentHooks.d.ts +4 -0
  102. package/types/JavaScriptSDK.Interfaces/IProcessTelemetryContext.d.ts +18 -3
  103. package/types/JavaScriptSDK.Interfaces/ITelemetryInitializers.d.ts +13 -0
  104. package/types/applicationinsights-core-js.d.ts +5 -4
  105. package/dist-esm/JavaScriptSDK/TelemetryPluginChain.js +0 -76
  106. package/dist-esm/JavaScriptSDK/TelemetryPluginChain.js.map +0 -1
  107. package/src/JavaScriptSDK/TelemetryPluginChain.ts +0 -120
  108. package/types/JavaScriptSDK/TelemetryPluginChain.d.ts +0 -32
@@ -3,90 +3,365 @@
3
3
  "use strict";
4
4
 
5
5
  import { IAppInsightsCore } from "../JavaScriptSDK.Interfaces/IAppInsightsCore";
6
- import { IDiagnosticLogger } from "../JavaScriptSDK.Interfaces/IDiagnosticLogger";
7
6
  import { IConfiguration } from "../JavaScriptSDK.Interfaces/IConfiguration";
8
7
  import { ITelemetryItem } from "../JavaScriptSDK.Interfaces/ITelemetryItem";
9
8
  import { IPlugin, ITelemetryPlugin } from "../JavaScriptSDK.Interfaces/ITelemetryPlugin";
10
- import { IProcessTelemetryContext } from "../JavaScriptSDK.Interfaces/IProcessTelemetryContext";
9
+ import { GetExtCfgMergeType, IProcessTelemetryContext } from "../JavaScriptSDK.Interfaces/IProcessTelemetryContext";
11
10
  import { ITelemetryPluginChain } from "../JavaScriptSDK.Interfaces/ITelemetryPluginChain";
12
11
  import { safeGetLogger } from "./DiagnosticLogger";
13
- import { TelemetryPluginChain } from "./TelemetryPluginChain";
14
- import { arrForEach, isFunction, isNullOrUndefined, isUndefined } from "./HelperFuncs";
12
+ import { arrForEach, isArray, isFunction, isNullOrUndefined, isObject, objExtend, objForEachKey, objFreeze, objKeys, proxyFunctions } from "./HelperFuncs";
13
+ import { doPerf } from "./PerfManager";
14
+ import { LoggingSeverity, _InternalMessageId } from "../JavaScriptSDK.Enums/LoggingEnums";
15
+ import { dumpObj } from "./EnvUtils";
16
+ import { IDiagnosticLogger } from "../JavaScriptSDK.Interfaces/IDiagnosticLogger";
17
+
18
+ const strTelemetryPluginChain = "TelemetryPluginChain";
19
+ const strHasRunFlags = "_hasRun";
20
+ const strGetTelCtx = "_getTelCtx";
21
+
22
+ let _chainId = 0;
23
+
24
+ interface IInternalTelemetryPluginChain extends ITelemetryPluginChain {
25
+ _id: string;
26
+ _setNext: (nextPlugin: IInternalTelemetryPluginChain) => void;
27
+ }
28
+
29
+ function _getNextProxyStart(proxy: ITelemetryPluginChain, config: IConfiguration, core:IAppInsightsCore, startAt: IPlugin): ITelemetryPluginChain {
30
+ while (proxy) {
31
+ if (proxy.getPlugin() === startAt) {
32
+ return proxy;
33
+ }
34
+
35
+ proxy = proxy.getNext();
36
+ }
37
+
38
+ // This wasn't found in the existing chain so create an isolated one with just this plugin
39
+ return createTelemetryProxyChain([startAt], config, core);
40
+ }
15
41
 
16
42
  /**
17
- * Creates the instance execution chain for the plugins
43
+ * Creates a new Telemetry Item context with the current config, core and plugin execution chain
44
+ * @param plugins - The plugin instances that will be executed
45
+ * @param config - The current config
46
+ * @param core - The current core instance
18
47
  */
19
- function _createProxyChain(plugins:IPlugin[], itemCtx:IProcessTelemetryContext) {
20
- let proxies:ITelemetryPluginChain[] = [];
21
-
22
- if (plugins && plugins.length > 0) {
23
- // Create the proxies and wire up the next plugin chain
24
- let lastProxy:TelemetryPluginChain = null;
25
- for (let idx = 0; idx < plugins.length; idx++) {
26
- let thePlugin = plugins[idx] as ITelemetryPlugin;
27
- if (thePlugin && isFunction(thePlugin.processTelemetry)) {
28
- // Only add plugins that are processors
29
- let newProxy = new TelemetryPluginChain(thePlugin, itemCtx);
30
- proxies.push(newProxy);
31
- if (lastProxy) {
32
- // Set this new proxy as the next for the previous one
33
- lastProxy.setNext(newProxy);
48
+ export function createProcessTelemetryContext(telemetryChain: ITelemetryPluginChain, config: IConfiguration, core:IAppInsightsCore, startAt?: IPlugin): IProcessTelemetryContext {
49
+ let _nextProxy: ITelemetryPluginChain = null; // Null == No next plugin
50
+ let _onComplete: () => void = null;
51
+
52
+ // There is no next element (null === last element) vs not defined (undefined)
53
+ // We have a proxy chain object
54
+ if (startAt) {
55
+ // We have a special case where we want to start execution from this specific plugin
56
+ _nextProxy = _getNextProxyStart(telemetryChain, config, core, startAt);
57
+ } else {
58
+ // Reuse the existing telemetry plugin chain (normal execution case)
59
+ _nextProxy = telemetryChain;
60
+ }
61
+
62
+ let context: IProcessTelemetryContext = {
63
+ core: () => {
64
+ return core;
65
+ },
66
+ diagLog: () => {
67
+ return safeGetLogger(core, config);
68
+ },
69
+ getCfg: () => {
70
+ return config;
71
+ },
72
+ getExtCfg: _getExtCfg,
73
+ getConfig: _getConfig,
74
+ hasNext: () => {
75
+ return _nextProxy != null;
76
+ },
77
+ getNext: () => {
78
+ return _nextProxy;
79
+ },
80
+ setNext: (nextPlugin:ITelemetryPluginChain) => {
81
+ _nextProxy = nextPlugin;
82
+ },
83
+ processNext: (env: ITelemetryItem) => {
84
+ _processChain((nextPlugin) => {
85
+ // Run the next plugin which will call "processNext()"
86
+ nextPlugin.processTelemetry(env, context);
87
+ });
88
+ },
89
+ iterate: _iterateChain,
90
+ createNew: (plugins: IPlugin[] | ITelemetryPluginChain = null, startAt?: IPlugin) => {
91
+ if (isArray(plugins)) {
92
+ plugins = createTelemetryProxyChain(plugins, config, core, startAt);
93
+ }
94
+
95
+ return createProcessTelemetryContext(plugins || _nextProxy, config, core, startAt);
96
+ },
97
+ onComplete: (onComplete: () => void) => {
98
+ _onComplete = onComplete;
99
+ }
100
+ };
101
+
102
+ function _getExtCfg<T>(identifier: string, defaultValue: T|any = {}, mergeDefault: GetExtCfgMergeType = GetExtCfgMergeType.None) {
103
+ let theConfig: T;
104
+ if (config) {
105
+ let extConfig = config.extensionConfig;
106
+ if (extConfig && identifier) {
107
+ theConfig = extConfig[identifier];
108
+ }
109
+ }
110
+
111
+ if (!theConfig) {
112
+ // Just use the defaults
113
+ theConfig = defaultValue as T;
114
+ } else if (isObject(defaultValue)) {
115
+ if (mergeDefault !== GetExtCfgMergeType.None) {
116
+ // Merge the defaults and configured values
117
+ let newConfig = objExtend(true, defaultValue, theConfig);
118
+
119
+ if (config && mergeDefault === GetExtCfgMergeType.MergeDefaultFromRootOrDefault) {
120
+ // Enumerate over the defaultValues and if not already populate attempt to
121
+ // find a value from the root config
122
+ objForEachKey(defaultValue, (field) => {
123
+ // for each unspecified field, set the default value
124
+ if (isNullOrUndefined(newConfig[field])) {
125
+ let cfgValue = config[field];
126
+ if (!isNullOrUndefined(cfgValue)) {
127
+ newConfig[field] = cfgValue;
128
+ }
129
+ }
130
+ });
34
131
  }
35
-
36
- lastProxy = newProxy;
37
132
  }
38
133
  }
134
+
135
+ return theConfig;
39
136
  }
40
137
 
41
- return proxies.length > 0 ? proxies[0] : null;
42
- }
138
+ function _getConfig(identifier:string, field: string, defaultValue: number | string | boolean | string[] | RegExp[] | Function = false) {
139
+ let theValue;
140
+ let extConfig = _getExtCfg(identifier, null);
141
+ if (extConfig && !isNullOrUndefined(extConfig[field])) {
142
+ theValue = extConfig[field];
143
+ } else if (config && !isNullOrUndefined(config[field])) {
144
+ theValue = config[field];
145
+ }
43
146
 
44
- function _copyProxyChain(proxy:ITelemetryPluginChain, itemCtx:IProcessTelemetryContext, startAt:IPlugin) {
45
- let plugins:IPlugin[] = [];
46
- let add = startAt ? false : true;
147
+ return !isNullOrUndefined(theValue) ? theValue : defaultValue;
148
+ }
47
149
 
48
- if (proxy) {
49
- while (proxy) {
50
- let thePlugin = proxy.getPlugin();
51
- if (add || thePlugin === startAt) {
52
- add = true;
53
- plugins.push(thePlugin);
150
+ function _processChain(cb: (nextPlugin: ITelemetryPluginChain) => void) {
151
+ let nextPlugin = _nextProxy;
152
+
153
+ if (nextPlugin) {
154
+ // Automatically move to the next plugin
155
+ _nextProxy = nextPlugin.getNext();
156
+ cb(nextPlugin);
157
+ } else {
158
+ if (_onComplete) {
159
+ _onComplete();
160
+ _onComplete = null;
54
161
  }
55
- proxy = proxy.getNext();
56
162
  }
57
163
  }
58
164
 
59
- if (!add) {
60
- plugins.push(startAt);
165
+ function _iterateChain<T extends ITelemetryPlugin = ITelemetryPlugin>(cb: (plugin: T) => void) {
166
+ while(_nextProxy) {
167
+ _processChain((nextPlugin: ITelemetryPluginChain) => {
168
+ let plugin = nextPlugin.getPlugin();
169
+ if (plugin) {
170
+ // callback with the current on
171
+ cb(plugin as T);
172
+ }
173
+ });
174
+ }
61
175
  }
62
-
63
- return _createProxyChain(plugins, itemCtx);
176
+
177
+ return context;
64
178
  }
65
179
 
66
- function _copyPluginChain(srcPlugins:IPlugin[], itemCtx:IProcessTelemetryContext, startAt:IPlugin) {
67
- let plugins:IPlugin[] = srcPlugins;
68
- let add = false;
69
- if (startAt && srcPlugins) {
70
- plugins = [];
71
-
72
- arrForEach(srcPlugins, thePlugin => {
73
- if (add || thePlugin === startAt) {
180
+ /**
181
+ * Creates an execution chain from the array of plugins
182
+ * @param plugins - The array of plugins that will be executed in this order
183
+ * @param defItemCtx - The default execution context to use when no telemetry context is passed to processTelemetry(), this
184
+ * should be for legacy plugins only. Currently, only used for passing the current core instance and to provide better error
185
+ * reporting (hasRun) when errors occur.
186
+ */
187
+ export function createTelemetryProxyChain(plugins: IPlugin[], config: IConfiguration, core: IAppInsightsCore, startAt?: IPlugin): ITelemetryPluginChain {
188
+ let firstProxy: ITelemetryPluginChain = null;
189
+ let add = startAt ? false : true;
190
+
191
+ if (isArray(plugins) && plugins.length > 0) {
192
+ // Create the proxies and wire up the next plugin chain
193
+ let lastProxy: IInternalTelemetryPluginChain = null;
194
+ arrForEach(plugins, (thePlugin: ITelemetryPlugin) => {
195
+ if (!add && startAt === thePlugin) {
74
196
  add = true;
75
- plugins.push(thePlugin);
197
+ }
198
+
199
+ if (add && thePlugin && isFunction(thePlugin.processTelemetry)) {
200
+ // Only add plugins that are processors
201
+ let newProxy = createTelemetryPluginProxy(thePlugin, config, core);
202
+ if (!firstProxy) {
203
+ firstProxy = newProxy;
204
+ }
205
+
206
+ if (lastProxy) {
207
+ // Set this new proxy as the next for the previous one
208
+ lastProxy._setNext(newProxy as IInternalTelemetryPluginChain);
209
+ }
210
+
211
+ lastProxy = newProxy as IInternalTelemetryPluginChain;
76
212
  }
77
213
  });
78
214
  }
79
215
 
80
- if (startAt && !add) {
81
- if (!plugins) {
82
- plugins = [];
216
+ if (startAt && !firstProxy) {
217
+ // Special case where the "startAt" was not in the original list of plugins
218
+ return createTelemetryProxyChain([startAt], config, core);
219
+ }
220
+
221
+ return firstProxy;
222
+ }
223
+
224
+ /**
225
+ * Create the processing telemetry proxy instance, the proxy is used to abstract the current plugin to allow monitoring and
226
+ * execution plugins while passing around the dynamic execution state (IProcessTelemetryContext), the proxy instance no longer
227
+ * contains any execution state and can be reused between requests (this was not the case for 2.7.2 and earlier with the
228
+ * TelemetryPluginChain class).
229
+ * @param plugin - The plugin instance to proxy
230
+ * @param config - The default execution context to use when no telemetry context is passed to processTelemetry(), this
231
+ * should be for legacy plugins only. Currently, only used for passing the current core instance and to provide better error
232
+ * reporting (hasRun) when errors occur.
233
+ * @returns
234
+ */
235
+ export function createTelemetryPluginProxy(plugin: ITelemetryPlugin, config: IConfiguration, core: IAppInsightsCore): ITelemetryPluginChain {
236
+ let nextProxy: IInternalTelemetryPluginChain = null;
237
+ let hasProcessTelemetry = isFunction(plugin.processTelemetry);
238
+ let hasSetNext = isFunction(plugin.setNextPlugin);
239
+ let chainId: string;
240
+ if (plugin) {
241
+ chainId = plugin.identifier + "-" + plugin.priority + "-" + _chainId++;
242
+ } else {
243
+ chainId = "Unknown-0-" + _chainId++;
244
+ }
245
+ let proxyChain: IInternalTelemetryPluginChain = {
246
+ getPlugin: () => {
247
+ return plugin;
248
+ },
249
+ getNext: () => {
250
+ return nextProxy;
251
+ },
252
+ processTelemetry: _processTelemetry,
253
+ _id: chainId,
254
+ _setNext: (nextPlugin: IInternalTelemetryPluginChain) => {
255
+ nextProxy = nextPlugin;
83
256
  }
84
- plugins.push(startAt);
257
+ };
258
+
259
+ function _processChain(
260
+ itemCtx: IProcessTelemetryContext,
261
+ processPluginFn: (itemCtx: IProcessTelemetryContext) => boolean,
262
+ processProxyFn: (itemCtx: IProcessTelemetryContext) => void,
263
+ name: string,
264
+ details: () => any,
265
+ isAsync: boolean) {
266
+
267
+ // Make sure we have a context
268
+ if (!itemCtx) {
269
+ // Looks like a plugin didn't pass the (optional) context, so create a new one
270
+ if (plugin && isFunction(plugin[strGetTelCtx])) {
271
+ // This plugin extends from the BaseTelemetryPlugin so lets use it
272
+ itemCtx = plugin[strGetTelCtx]();
273
+ }
274
+
275
+ if (!itemCtx) {
276
+ // Create a temporary one
277
+ itemCtx = createProcessTelemetryContext(proxyChain, config, core);
278
+ }
279
+ }
280
+
281
+ let identifier = plugin ? plugin.identifier : strTelemetryPluginChain;
282
+ let hasRunContext = itemCtx[strHasRunFlags];
283
+ if (!hasRunContext) {
284
+ // Assign and populate
285
+ hasRunContext = itemCtx[strHasRunFlags] = {};
286
+ }
287
+
288
+ doPerf(itemCtx.core(), () => identifier + ":" + name, () => {
289
+ // Mark this component as having run
290
+ hasRunContext[chainId] = true;
291
+ let hasRun = false;
292
+
293
+ // Ensure that we keep the context in sync
294
+ itemCtx.setNext(nextProxy);
295
+
296
+ if (plugin) {
297
+ try {
298
+ // Set a flag on the next plugin so we know if it was attempted to be executed
299
+ let nextId = nextProxy ? nextProxy._id : "";
300
+ if (nextId) {
301
+ hasRunContext[nextId] = false;
302
+ }
303
+
304
+ hasRun = processPluginFn(itemCtx);
305
+ } catch (error) {
306
+ let hasNextRun = nextProxy ? hasRunContext[nextProxy._id] : true;
307
+ if (hasNextRun) {
308
+ // The next plugin after us has already run so set this one as complete
309
+ hasRun = true;
310
+ }
311
+
312
+ if (!nextProxy || !hasNextRun) {
313
+
314
+ // Either we have no next plugin or the current one did not attempt to call the next plugin
315
+ // Which means the current one is the root of the failure so log/report this failure
316
+ itemCtx.diagLog().throwInternal(
317
+ LoggingSeverity.CRITICAL,
318
+ _InternalMessageId.PluginException,
319
+ "Plugin [" + plugin.identifier + "] failed during " + name + " - " + dumpObj(error) + ", run flags: " + dumpObj(hasRunContext));
320
+ }
321
+ }
322
+ }
323
+
324
+ if (nextProxy && !hasRun) {
325
+ // The underlying plugin is not defined, but we still want the next plugin to be executed.
326
+ // So rather than leave the pipeline dead in the water we call the next plugin
327
+ processProxyFn(itemCtx);
328
+ }
329
+ }, details, isAsync);
85
330
  }
86
-
87
- return _createProxyChain(plugins, itemCtx);
331
+
332
+ function _processTelemetry(env: ITelemetryItem, itemCtx: IProcessTelemetryContext) {
333
+ _processChain(itemCtx, (itemCtx: IProcessTelemetryContext) => {
334
+ if (!hasProcessTelemetry) {
335
+ return false;
336
+ }
337
+
338
+ // Ensure that we keep the context in sync (for processNext()), just in case a plugin
339
+ // doesn't calls processTelemetry() instead of itemContext.processNext() or some
340
+ // other form of error occurred
341
+ if (hasSetNext) {
342
+ // Backward compatibility setting the next plugin on the instance
343
+ plugin.setNextPlugin(nextProxy);
344
+ }
345
+
346
+ plugin.processTelemetry(env, itemCtx);
347
+
348
+ return true;
349
+ },
350
+ (itemCtx: IProcessTelemetryContext) => {
351
+ // The underlying plugin is either not defined or does not have a processTelemetry implementation
352
+ // so we still want the next plugin to be executed.
353
+ nextProxy.processTelemetry(env, itemCtx);
354
+ },
355
+ "processTelemetry", () => ({ item: env }), !((env as any).sync));
356
+ }
357
+
358
+ return objFreeze(proxyChain);
88
359
  }
89
360
 
361
+ /**
362
+ * This class will be removed!
363
+ * @deprecated use createProcessTelemetryContext() instead
364
+ */
90
365
  export class ProcessTelemetryContext implements IProcessTelemetryContext {
91
366
  /**
92
367
  * Gets the current core config instance
@@ -132,97 +407,39 @@ export class ProcessTelemetryContext implements IProcessTelemetryContext {
132
407
  */
133
408
  public processNext: (env: ITelemetryItem) => void;
134
409
 
410
+ /**
411
+ * Synchronously iterate over the context chain running the callback for each plugin, once
412
+ * every plugin has been executed via the callback, any associated onComplete will be called.
413
+ * @param callback - The function call for each plugin in the context chain
414
+ */
415
+ public iterate: <T extends ITelemetryPlugin = ITelemetryPlugin>(callback: (plugin: T) => void) => void;
416
+
417
+ /**
135
418
  /**
136
419
  * Create a new context using the core and config from the current instance
420
+ * @param plugins - The execution order to process the plugins, if null or not supplied
421
+ * then the current execution order will be copied.
422
+ * @param startAt - The plugin to start processing from, if missing from the execution
423
+ * order then the next plugin will be NOT set.
137
424
  */
138
425
  public createNew: (plugins?:IPlugin[]|ITelemetryPluginChain, startAt?:IPlugin) => IProcessTelemetryContext;
139
-
426
+
427
+ /**
428
+ * Set the function to call when the current chain has executed all processNext or unloadNext items.
429
+ */
430
+ public onComplete: (onComplete: () => void) => void;
431
+
140
432
  /**
141
433
  * Creates a new Telemetry Item context with the current config, core and plugin execution chain
142
434
  * @param plugins - The plugin instances that will be executed
143
435
  * @param config - The current config
144
436
  * @param core - The current core instance
145
437
  */
146
- constructor(plugins:IPlugin[]|ITelemetryPluginChain, config: IConfiguration, core:IAppInsightsCore, startAt?:IPlugin) {
438
+ constructor(pluginChain: ITelemetryPluginChain, config: IConfiguration, core:IAppInsightsCore, startAt?:IPlugin) {
147
439
  let _self = this;
148
- let _nextProxy: ITelemetryPluginChain = null; // Null == No next plugin
149
-
150
- // There is no next element (null) vs not defined (undefined)
151
- if (startAt !== null) {
152
- if (plugins && isFunction((plugins as ITelemetryPluginChain).getPlugin)) {
153
- // We have a proxy chain object
154
- _nextProxy = _copyProxyChain(plugins as ITelemetryPluginChain, _self, startAt||(plugins as ITelemetryPluginChain).getPlugin());
155
- } else {
156
- // We just have an array
157
- if (startAt) {
158
- _nextProxy = _copyPluginChain(plugins as IPlugin[], _self, startAt);
159
- } else if (isUndefined(startAt)) {
160
- // Undefined means copy the existing chain
161
- _nextProxy = _createProxyChain(plugins as IPlugin[], _self)
162
- }
163
- }
164
- }
165
-
166
- _self.core = () => {
167
- return core;
168
- };
169
-
170
- _self.diagLog = () => {
171
- return safeGetLogger(core, config);
172
- };
173
-
174
- _self.getCfg = () => {
175
- return config;
176
- };
177
-
178
- _self.getExtCfg = <T>(identifier:string, defaultValue:T|any = {}) => {
179
- let theConfig:T;
180
- if (config) {
181
- let extConfig = config.extensionConfig;
182
- if (extConfig && identifier) {
183
- theConfig = extConfig[identifier];
184
- }
185
- }
186
-
187
- return (theConfig ? theConfig : defaultValue) as T;
188
- };
189
-
190
- _self.getConfig = (identifier:string, field: string, defaultValue: number | string | boolean = false) => {
191
- let theValue;
192
- let extConfig = _self.getExtCfg(identifier, null);
193
- if (extConfig && !isNullOrUndefined(extConfig[field])) {
194
- theValue = extConfig[field];
195
- } else if (config && !isNullOrUndefined(config[field])) {
196
- theValue = config[field];
197
- }
198
-
199
- return !isNullOrUndefined(theValue) ? theValue : defaultValue;
200
- };
201
440
 
202
- _self.hasNext = () => {
203
- return _nextProxy != null;
204
- };
205
-
206
- _self.getNext = () => {
207
- return _nextProxy;
208
- }
209
-
210
- _self.setNext = (nextPlugin:ITelemetryPluginChain) => {
211
- _nextProxy = nextPlugin;
212
- };
213
-
214
- _self.processNext = (env: ITelemetryItem) => {
215
- let nextPlugin = _nextProxy;
216
-
217
- if (nextPlugin) {
218
- // Automatically move to the next plugin
219
- _nextProxy = nextPlugin.getNext();
220
- nextPlugin.processTelemetry(env, _self);
221
- }
222
- };
223
-
224
- _self.createNew = (plugins:IPlugin[]|ITelemetryPluginChain = null, startAt?:IPlugin) => {
225
- return new ProcessTelemetryContext(plugins||_nextProxy, config, core, startAt);
226
- }
441
+ let context = createProcessTelemetryContext(pluginChain, config, core, startAt);
442
+ // Proxy all functions of the context to this object
443
+ proxyFunctions(_self, context, objKeys(context) as any);
227
444
  }
228
445
  }
@@ -52,12 +52,14 @@ export function randomValue(maxValue: number) {
52
52
  * @param signed - True to return a signed 32-bit number (-0x80000000..0x7FFFFFFF) otherwise an unsigned one (0x000000..0xFFFFFFFF)
53
53
  */
54
54
  export function random32(signed?: boolean) {
55
- let value;
55
+ let value = 0;
56
56
  let c = getCrypto() || getMsCrypto();
57
57
  if (c && c.getRandomValues) {
58
58
  // Make sure the number is converted into the specified range (-0x80000000..0x7FFFFFFF)
59
59
  value = c.getRandomValues(new Uint32Array(1))[0] & MaxUInt32;
60
- } else if (isIE()) {
60
+ }
61
+
62
+ if (value === 0 && isIE()) {
61
63
  // For IE 6, 7, 8 (especially on XP) Math.random is not very random
62
64
  if (!_mwcSeeded) {
63
65
  // Set the seed for the Mwc algorithm
@@ -67,7 +69,9 @@ export function random32(signed?: boolean) {
67
69
  // Don't use Math.random for IE
68
70
  // Make sure the number is converted into the specified range (-0x80000000..0x7FFFFFFF)
69
71
  value = mwcRandom32() & MaxUInt32;
70
- } else {
72
+ }
73
+
74
+ if (value === 0) {
71
75
  // Make sure the number is converted into the specified range (-0x80000000..0x7FFFFFFF)
72
76
  value = Math.floor((UInt32Mask * Math.random()) | 0);
73
77
  }
@@ -112,3 +116,30 @@ export function mwcRandom32(signed?: boolean) {
112
116
  return value;
113
117
  }
114
118
 
119
+ /**
120
+ * Generate random base64 id string.
121
+ * The default length is 22 which is 132-bits so almost the same as a GUID but as base64 (the previous default was 5)
122
+ * @param maxLength - Optional value to specify the length of the id to be generated, defaults to 22
123
+ */
124
+ export function newId(maxLength = 22): string {
125
+ const base64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
126
+
127
+ // Start with an initial random number, consuming the value in reverse byte order
128
+ let number = random32() >>> 0; // Make sure it's a +ve number
129
+ let chars = 0;
130
+ let result = "";
131
+ while (result.length < maxLength) {
132
+ chars ++;
133
+ result += base64chars.charAt(number & 0x3F);
134
+ number >>>= 6; // Zero fill with right shift
135
+ if (chars === 5) {
136
+ // 5 base64 characters === 30 bits so we don't have enough bits for another base64 char
137
+ // So add on another 30 bits and make sure it's +ve
138
+ number = (((random32() << 2) & 0xFFFFFFFF) | (number & 0x03)) >>> 0;
139
+ chars = 0; // We need to reset the number every 5 chars (30 bits)
140
+ }
141
+ }
142
+
143
+ return result;
144
+ }
145
+
@@ -3,9 +3,7 @@
3
3
  "use strict";
4
4
 
5
5
  import { IPlugin, ITelemetryPlugin } from "../JavaScriptSDK.Interfaces/ITelemetryPlugin";
6
- import { _InternalLogMessage } from "./DiagnosticLogger";
7
- import { _InternalMessageId } from "../JavaScriptSDK.Enums/LoggingEnums";
8
- import { ProcessTelemetryContext } from "./ProcessTelemetryContext";
6
+ import { IProcessTelemetryContext } from "../JavaScriptSDK.Interfaces/IProcessTelemetryContext";
9
7
  import { ITelemetryPluginChain } from "../JavaScriptSDK.Interfaces/ITelemetryPluginChain";
10
8
  import { arrForEach, isFunction } from "./HelperFuncs";
11
9
 
@@ -21,7 +19,7 @@ let isInitialized = "isInitialized";
21
19
  * @param core THe current core instance
22
20
  * @param extensions The extensions
23
21
  */
24
- export function initializePlugins(processContext:ProcessTelemetryContext, extensions: IPlugin[]) {
22
+ export function initializePlugins(processContext: IProcessTelemetryContext, extensions: IPlugin[]) {
25
23
 
26
24
  // Set the next plugin and identified the uninitialized plugins
27
25
  let initPlugins:ITelemetryPlugin[] = [];
@@ -46,7 +44,7 @@ export function initializePlugins(processContext:ProcessTelemetryContext, extens
46
44
  }
47
45
  }
48
46
 
49
- // Now initiatilize the plugins
47
+ // Now initialize the plugins
50
48
  arrForEach(initPlugins, thePlugin => {
51
49
  thePlugin.initialize(
52
50
  processContext.getCfg(),
@@ -56,7 +54,7 @@ export function initializePlugins(processContext:ProcessTelemetryContext, extens
56
54
  });
57
55
  }
58
56
 
59
- export function sortPlugins(plugins:IPlugin[]) {
57
+ export function sortPlugins<T = IPlugin>(plugins:T[]) {
60
58
  // Sort by priority
61
59
  return plugins.sort((extA, extB) => {
62
60
  let result = 0;