@fluidframework/telemetry-utils 2.0.0-internal.5.4.0 → 2.0.0-internal.6.0.0

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 (58) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/config.js +25 -31
  3. package/dist/config.js.map +1 -1
  4. package/dist/errorLogging.js +16 -10
  5. package/dist/errorLogging.js.map +1 -1
  6. package/dist/fluidErrorBase.js +7 -7
  7. package/dist/fluidErrorBase.js.map +1 -1
  8. package/dist/index.d.ts +1 -2
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1 -9
  11. package/dist/index.js.map +1 -1
  12. package/dist/logger.d.ts +1 -56
  13. package/dist/logger.d.ts.map +1 -1
  14. package/dist/logger.js +42 -129
  15. package/dist/logger.js.map +1 -1
  16. package/dist/mockLogger.d.ts +3 -5
  17. package/dist/mockLogger.d.ts.map +1 -1
  18. package/dist/mockLogger.js +6 -15
  19. package/dist/mockLogger.js.map +1 -1
  20. package/dist/sampledTelemetryHelper.js +8 -5
  21. package/dist/sampledTelemetryHelper.js.map +1 -1
  22. package/dist/utils.js +1 -1
  23. package/dist/utils.js.map +1 -1
  24. package/lib/config.js +25 -31
  25. package/lib/config.js.map +1 -1
  26. package/lib/errorLogging.js +16 -10
  27. package/lib/errorLogging.js.map +1 -1
  28. package/lib/fluidErrorBase.js +7 -7
  29. package/lib/fluidErrorBase.js.map +1 -1
  30. package/lib/index.d.ts +1 -2
  31. package/lib/index.d.ts.map +1 -1
  32. package/lib/index.js +1 -2
  33. package/lib/index.js.map +1 -1
  34. package/lib/logger.d.ts +1 -56
  35. package/lib/logger.d.ts.map +1 -1
  36. package/lib/logger.js +41 -125
  37. package/lib/logger.js.map +1 -1
  38. package/lib/mockLogger.d.ts +3 -5
  39. package/lib/mockLogger.d.ts.map +1 -1
  40. package/lib/mockLogger.js +7 -16
  41. package/lib/mockLogger.js.map +1 -1
  42. package/lib/sampledTelemetryHelper.js +8 -5
  43. package/lib/sampledTelemetryHelper.js.map +1 -1
  44. package/lib/utils.js +1 -1
  45. package/lib/utils.js.map +1 -1
  46. package/package.json +39 -6
  47. package/src/index.ts +0 -7
  48. package/src/logger.ts +11 -98
  49. package/src/mockLogger.ts +8 -8
  50. package/dist/debugLogger.d.ts +0 -39
  51. package/dist/debugLogger.d.ts.map +0 -1
  52. package/dist/debugLogger.js +0 -105
  53. package/dist/debugLogger.js.map +0 -1
  54. package/lib/debugLogger.d.ts +0 -39
  55. package/lib/debugLogger.d.ts.map +0 -1
  56. package/lib/debugLogger.js +0 -101
  57. package/lib/debugLogger.js.map +0 -1
  58. package/src/debugLogger.ts +0 -138
@@ -1 +1 @@
1
- {"version":3,"file":"mockLogger.js","sourceRoot":"","sources":["../src/mockLogger.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryBaseEvent } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/common-utils\";\nimport { TelemetryLogger } from \"./logger\";\nimport { ITelemetryLoggerExt, ITelemetryPropertiesExt } from \"./telemetryTypes\";\n\n/**\n * The MockLogger records events sent to it, and then can walk back over those events\n * searching for a set of expected events to match against the logged events.\n */\nexport class MockLogger extends TelemetryLogger implements ITelemetryLoggerExt {\n\tevents: ITelemetryBaseEvent[] = [];\n\n\tconstructor() {\n\t\tsuper();\n\t}\n\n\tclear() {\n\t\tthis.events = [];\n\t}\n\n\tsend(event: ITelemetryBaseEvent): void {\n\t\tthis.events.push(event);\n\t}\n\n\t/**\n\t * Search events logged since the last time matchEvents was called, looking for the given expected\n\t * events in order.\n\t * @param expectedEvents - events in order that are expected to appear in the recorded log.\n\t * @param inlineDetailsProp - true if the \"details\" property in the actual event should be extracted and inlined.\n\t * These event objects may be subsets of the logged events.\n\t * Note: category is omitted from the type because it's usually uninteresting and tedious to type.\n\t */\n\tmatchEvents(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tinlineDetailsProp: boolean = false,\n\t): boolean {\n\t\tconst matchedExpectedEventCount = this.getMatchedEventsCount(\n\t\t\texpectedEvents,\n\t\t\tinlineDetailsProp,\n\t\t);\n\t\t// How many expected events were left over? Hopefully none.\n\t\tconst unmatchedExpectedEventCount = expectedEvents.length - matchedExpectedEventCount;\n\t\treturn unmatchedExpectedEventCount === 0;\n\t}\n\n\t/** Asserts that matchEvents is true, and prints the actual/expected output if not */\n\tassertMatch(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t) {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchEvents(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\t/**\n\t * Search events logged since the last time matchEvents was called, looking for any of the given\n\t * expected events.\n\t * @param expectedEvents - events that are expected to appear in the recorded log.\n\t * @param inlineDetailsProp - true if the \"details\" property in the actual event should be extracted and inlined.\n\t * These event objects may be subsets of the logged events.\n\t * Note: category is omitted from the type because it's usually uninteresting and tedious to type.\n\t * @returns if any of the expected events is found.\n\t */\n\tmatchAnyEvent(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tinlineDetailsProp: boolean = false,\n\t): boolean {\n\t\tconst matchedExpectedEventCount = this.getMatchedEventsCount(\n\t\t\texpectedEvents,\n\t\t\tinlineDetailsProp,\n\t\t);\n\t\treturn matchedExpectedEventCount > 0;\n\t}\n\n\t/** Asserts that matchAnyEvent is true, and prints the actual/expected output if not */\n\tassertMatchAny(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t) {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchAnyEvent(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\t/**\n\t * Search events logged since the last time matchEvents was called, looking only for the given expected\n\t * events in order.\n\t * @param expectedEvents - events in order that are expected to be the only events in the recorded log.\n\t * @param inlineDetailsProp - true if the \"details\" property in the actual event should be extracted and inlined.\n\t * These event objects may be subsets of the logged events.\n\t * Note: category is omitted from the type because it's usually uninteresting and tedious to type.\n\t */\n\tmatchEventStrict(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tinlineDetailsProp: boolean = false,\n\t): boolean {\n\t\treturn (\n\t\t\texpectedEvents.length === this.events.length &&\n\t\t\tthis.matchEvents(expectedEvents, inlineDetailsProp)\n\t\t);\n\t}\n\n\t/** Asserts that matchEvents is true, and prints the actual/expected output if not */\n\tassertMatchStrict(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t) {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchEventStrict(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\t/** Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not */\n\tassertMatchNone(\n\t\tdisallowedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t) {\n\t\tconst actualEvents = this.events;\n\t\tif (this.matchAnyEvent(disallowedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message}\ndisallowed events:\n${JSON.stringify(disallowedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\tprivate getMatchedEventsCount(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tinlineDetailsProp: boolean,\n\t): number {\n\t\tlet iExpectedEvent = 0;\n\t\tthis.events.forEach((event) => {\n\t\t\tif (\n\t\t\t\tiExpectedEvent < expectedEvents.length &&\n\t\t\t\tMockLogger.eventsMatch(event, expectedEvents[iExpectedEvent], inlineDetailsProp)\n\t\t\t) {\n\t\t\t\t// We found the next expected event; increment\n\t\t\t\t++iExpectedEvent;\n\t\t\t}\n\t\t});\n\n\t\t// Remove the events so far; next call will just compare subsequent events from here\n\t\tthis.events = [];\n\n\t\t// Return the count of matched events.\n\t\treturn iExpectedEvent;\n\t}\n\n\t/**\n\t * Ensure the expected event is a strict subset of the actual event\n\t */\n\tprivate static eventsMatch(\n\t\tactual: ITelemetryBaseEvent,\n\t\texpected: Omit<ITelemetryBaseEvent, \"category\">,\n\t\tinlineDetailsProp: boolean,\n\t): boolean {\n\t\tconst { details, ...actualForMatching } = actual;\n\t\t// \"details\" is used in a lot of telemetry logs to group a bunch of properties together and stringify them.\n\t\t// Some of the properties in the expected event may be inside \"details\". So, if inlineDetailsProp is true,\n\t\t// extract the properties from \"details\" in the actual event and inline them in the actual event.\n\t\tif (inlineDetailsProp && details !== undefined) {\n\t\t\tassert(\n\t\t\t\ttypeof details === \"string\",\n\t\t\t\t0x6c9 /* Details should a JSON stringified string if inlineDetailsProp is true */,\n\t\t\t);\n\t\t\tconst detailsExpanded = JSON.parse(details);\n\t\t\treturn matchObjects({ ...actualForMatching, ...detailsExpanded }, expected);\n\t\t}\n\t\treturn matchObjects(actual, expected);\n\t}\n}\n\nfunction matchObjects(actual: ITelemetryPropertiesExt, expected: ITelemetryPropertiesExt) {\n\tfor (const [expectedKey, expectedValue] of Object.entries(expected)) {\n\t\tconst actualValue = actual[expectedKey];\n\t\tif (\n\t\t\t!Array.isArray(expectedValue) &&\n\t\t\texpectedValue !== null &&\n\t\t\ttypeof expectedValue === \"object\"\n\t\t) {\n\t\t\tif (\n\t\t\t\tArray.isArray(actualValue) ||\n\t\t\t\tactualValue === null ||\n\t\t\t\ttypeof actualValue !== \"object\" ||\n\t\t\t\t!matchObjects(\n\t\t\t\t\tactualValue as ITelemetryPropertiesExt,\n\t\t\t\t\texpectedValue as ITelemetryPropertiesExt,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} else if (JSON.stringify(actualValue) !== JSON.stringify(expectedValue)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n"]}
1
+ {"version":3,"file":"mockLogger.js","sourceRoot":"","sources":["../src/mockLogger.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryBaseEvent, ITelemetryBaseLogger } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/common-utils\";\nimport { ITelemetryPropertiesExt } from \"./telemetryTypes\";\nimport { createChildLogger } from \"./logger\";\n\n/**\n * The MockLogger records events sent to it, and then can walk back over those events\n * searching for a set of expected events to match against the logged events.\n */\nexport class MockLogger implements ITelemetryBaseLogger {\n\tevents: ITelemetryBaseEvent[] = [];\n\n\tclear() {\n\t\tthis.events = [];\n\t}\n\n\ttoTelemetryLogger() {\n\t\treturn createChildLogger({ logger: this });\n\t}\n\n\tsend(event: ITelemetryBaseEvent): void {\n\t\tthis.events.push(event);\n\t}\n\n\t/**\n\t * Search events logged since the last time matchEvents was called, looking for the given expected\n\t * events in order.\n\t * @param expectedEvents - events in order that are expected to appear in the recorded log.\n\t * @param inlineDetailsProp - true if the \"details\" property in the actual event should be extracted and inlined.\n\t * These event objects may be subsets of the logged events.\n\t * Note: category is omitted from the type because it's usually uninteresting and tedious to type.\n\t */\n\tmatchEvents(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tinlineDetailsProp: boolean = false,\n\t): boolean {\n\t\tconst matchedExpectedEventCount = this.getMatchedEventsCount(\n\t\t\texpectedEvents,\n\t\t\tinlineDetailsProp,\n\t\t);\n\t\t// How many expected events were left over? Hopefully none.\n\t\tconst unmatchedExpectedEventCount = expectedEvents.length - matchedExpectedEventCount;\n\t\treturn unmatchedExpectedEventCount === 0;\n\t}\n\n\t/** Asserts that matchEvents is true, and prints the actual/expected output if not */\n\tassertMatch(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t) {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchEvents(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\t/**\n\t * Search events logged since the last time matchEvents was called, looking for any of the given\n\t * expected events.\n\t * @param expectedEvents - events that are expected to appear in the recorded log.\n\t * @param inlineDetailsProp - true if the \"details\" property in the actual event should be extracted and inlined.\n\t * These event objects may be subsets of the logged events.\n\t * Note: category is omitted from the type because it's usually uninteresting and tedious to type.\n\t * @returns if any of the expected events is found.\n\t */\n\tmatchAnyEvent(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tinlineDetailsProp: boolean = false,\n\t): boolean {\n\t\tconst matchedExpectedEventCount = this.getMatchedEventsCount(\n\t\t\texpectedEvents,\n\t\t\tinlineDetailsProp,\n\t\t);\n\t\treturn matchedExpectedEventCount > 0;\n\t}\n\n\t/** Asserts that matchAnyEvent is true, and prints the actual/expected output if not */\n\tassertMatchAny(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t) {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchAnyEvent(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\t/**\n\t * Search events logged since the last time matchEvents was called, looking only for the given expected\n\t * events in order.\n\t * @param expectedEvents - events in order that are expected to be the only events in the recorded log.\n\t * @param inlineDetailsProp - true if the \"details\" property in the actual event should be extracted and inlined.\n\t * These event objects may be subsets of the logged events.\n\t * Note: category is omitted from the type because it's usually uninteresting and tedious to type.\n\t */\n\tmatchEventStrict(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tinlineDetailsProp: boolean = false,\n\t): boolean {\n\t\treturn (\n\t\t\texpectedEvents.length === this.events.length &&\n\t\t\tthis.matchEvents(expectedEvents, inlineDetailsProp)\n\t\t);\n\t}\n\n\t/** Asserts that matchEvents is true, and prints the actual/expected output if not */\n\tassertMatchStrict(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t) {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchEventStrict(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\t/** Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not */\n\tassertMatchNone(\n\t\tdisallowedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t) {\n\t\tconst actualEvents = this.events;\n\t\tif (this.matchAnyEvent(disallowedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message}\ndisallowed events:\n${JSON.stringify(disallowedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\tprivate getMatchedEventsCount(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tinlineDetailsProp: boolean,\n\t): number {\n\t\tlet iExpectedEvent = 0;\n\t\tthis.events.forEach((event) => {\n\t\t\tif (\n\t\t\t\tiExpectedEvent < expectedEvents.length &&\n\t\t\t\tMockLogger.eventsMatch(event, expectedEvents[iExpectedEvent], inlineDetailsProp)\n\t\t\t) {\n\t\t\t\t// We found the next expected event; increment\n\t\t\t\t++iExpectedEvent;\n\t\t\t}\n\t\t});\n\n\t\t// Remove the events so far; next call will just compare subsequent events from here\n\t\tthis.events = [];\n\n\t\t// Return the count of matched events.\n\t\treturn iExpectedEvent;\n\t}\n\n\t/**\n\t * Ensure the expected event is a strict subset of the actual event\n\t */\n\tprivate static eventsMatch(\n\t\tactual: ITelemetryBaseEvent,\n\t\texpected: Omit<ITelemetryBaseEvent, \"category\">,\n\t\tinlineDetailsProp: boolean,\n\t): boolean {\n\t\tconst { details, ...actualForMatching } = actual;\n\t\t// \"details\" is used in a lot of telemetry logs to group a bunch of properties together and stringify them.\n\t\t// Some of the properties in the expected event may be inside \"details\". So, if inlineDetailsProp is true,\n\t\t// extract the properties from \"details\" in the actual event and inline them in the actual event.\n\t\tif (inlineDetailsProp && details !== undefined) {\n\t\t\tassert(\n\t\t\t\ttypeof details === \"string\",\n\t\t\t\t0x6c9 /* Details should a JSON stringified string if inlineDetailsProp is true */,\n\t\t\t);\n\t\t\tconst detailsExpanded = JSON.parse(details);\n\t\t\treturn matchObjects({ ...actualForMatching, ...detailsExpanded }, expected);\n\t\t}\n\t\treturn matchObjects(actual, expected);\n\t}\n}\n\nfunction matchObjects(actual: ITelemetryPropertiesExt, expected: ITelemetryPropertiesExt) {\n\tfor (const [expectedKey, expectedValue] of Object.entries(expected)) {\n\t\tconst actualValue = actual[expectedKey];\n\t\tif (\n\t\t\t!Array.isArray(expectedValue) &&\n\t\t\texpectedValue !== null &&\n\t\t\ttypeof expectedValue === \"object\"\n\t\t) {\n\t\t\tif (\n\t\t\t\tArray.isArray(actualValue) ||\n\t\t\t\tactualValue === null ||\n\t\t\t\ttypeof actualValue !== \"object\" ||\n\t\t\t\t!matchObjects(\n\t\t\t\t\tactualValue as ITelemetryPropertiesExt,\n\t\t\t\t\texpectedValue as ITelemetryPropertiesExt,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} else if (JSON.stringify(actualValue) !== JSON.stringify(expectedValue)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n"]}
@@ -48,7 +48,6 @@ export class SampledTelemetryHelper {
48
48
  * @returns Whatever the passed-in code block returns.
49
49
  */
50
50
  measure(codeToMeasure, bucket = "") {
51
- var _a, _b, _c;
52
51
  const start = performance.now();
53
52
  const returnValue = codeToMeasure();
54
53
  const duration = performance.now() - start;
@@ -60,9 +59,9 @@ export class SampledTelemetryHelper {
60
59
  m.count++;
61
60
  m.duration = duration;
62
61
  if (this.includeAggregateMetrics) {
63
- m.totalDuration = ((_a = m.totalDuration) !== null && _a !== void 0 ? _a : 0) + duration;
64
- m.minDuration = Math.min((_b = m.minDuration) !== null && _b !== void 0 ? _b : duration, duration);
65
- m.maxDuration = Math.max((_c = m.maxDuration) !== null && _c !== void 0 ? _c : 0, duration);
62
+ m.totalDuration = (m.totalDuration ?? 0) + duration;
63
+ m.minDuration = Math.min(m.minDuration ?? duration, duration);
64
+ m.maxDuration = Math.max(m.maxDuration ?? 0, duration);
66
65
  }
67
66
  if (m.count >= this.sampleThreshold) {
68
67
  this.flushBucket(bucket);
@@ -76,7 +75,11 @@ export class SampledTelemetryHelper {
76
75
  }
77
76
  if (measurements.count !== 0) {
78
77
  const bucketProperties = this.perBucketProperties.get(bucket);
79
- const telemetryEvent = Object.assign(Object.assign(Object.assign({}, this.eventBase), bucketProperties), measurements);
78
+ const telemetryEvent = {
79
+ ...this.eventBase,
80
+ ...bucketProperties,
81
+ ...measurements,
82
+ };
80
83
  this.logger.sendPerformanceEvent(telemetryEvent);
81
84
  this.measurementsMap.delete(bucket);
82
85
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sampledTelemetryHelper.js","sourceRoot":"","sources":["../src/sampledTelemetryHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAkC3D;;;;;;GAMG;AACH,MAAM,OAAO,sBAAsB;IAKlC;;;;;;;;;;;;;;;;;OAiBG;IACH,YACkB,SAAiC,EACjC,MAA2B,EAC3B,eAAuB,EACvB,0BAAmC,KAAK,EACxC,sBAAsB,IAAI,GAAG,EAAgC;QAJ7D,cAAS,GAAT,SAAS,CAAwB;QACjC,WAAM,GAAN,MAAM,CAAqB;QAC3B,oBAAe,GAAf,eAAe,CAAQ;QACvB,4BAAuB,GAAvB,uBAAuB,CAAiB;QACxC,wBAAmB,GAAnB,mBAAmB,CAA0C;QA3B/E,aAAQ,GAAY,KAAK,CAAC;QAET,oBAAe,GAAG,IAAI,GAAG,EAAwB,CAAC;IA0BhE,CAAC;IAEJ;;;;;;;;OAQG;IACI,OAAO,CAAI,aAAsB,EAAE,SAAiB,EAAE;;QAC5D,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAChC,MAAM,WAAW,GAAG,aAAa,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QAE3C,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK,SAAS,EAAE;YACpB,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;SACpC;QACD,CAAC,CAAC,KAAK,EAAE,CAAC;QACV,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAEtB,IAAI,IAAI,CAAC,uBAAuB,EAAE;YACjC,CAAC,CAAC,aAAa,GAAG,CAAC,MAAA,CAAC,CAAC,aAAa,mCAAI,CAAC,CAAC,GAAG,QAAQ,CAAC;YACpD,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,MAAA,CAAC,CAAC,WAAW,mCAAI,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC9D,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,MAAA,CAAC,CAAC,WAAW,mCAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;SACvD;QAED,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE;YACpC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;SACzB;QAED,OAAO,WAAW,CAAC;IACpB,CAAC;IAEO,WAAW,CAAC,MAAc;QACjC,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtD,IAAI,YAAY,KAAK,SAAS,EAAE;YAC/B,OAAO;SACP;QAED,IAAI,YAAY,CAAC,KAAK,KAAK,CAAC,EAAE;YAC7B,MAAM,gBAAgB,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAE9D,MAAM,cAAc,iDAChB,IAAI,CAAC,SAAS,GACd,gBAAgB,GAChB,YAAY,CACf,CAAC;YAEF,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC;YACjD,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;SACpC;IACF,CAAC;IAEM,OAAO,CAAC,KAAyB;QACvC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tITelemetryGenericEvent,\n\tITelemetryPerformanceEvent,\n\tITelemetryProperties,\n\tIDisposable,\n} from \"@fluidframework/core-interfaces\";\nimport { performance } from \"@fluidframework/common-utils\";\nimport { ITelemetryLoggerExt } from \"./telemetryTypes\";\n\ninterface Measurements {\n\t// The names of the properties in this interface are the ones that will get stamped in the\n\t// telemetry event, changes should be considered carefully. The optional properties should\n\t// only be populated if 'includeAggregateMetrics' is true.\n\n\t/**\n\t * The duration of the latest execution.\n\t */\n\tduration: number;\n\n\t/**\n\t * The number of executions since the last time an event was generated.\n\t */\n\tcount: number;\n\n\t/**\n\t * Total duration across all the executions since the last event was generated.\n\t */\n\ttotalDuration?: number;\n\n\t/**\n\t * Min duration across all the executions since the last event was generated.\n\t */\n\tminDuration?: number;\n\n\t/**\n\t * Max duration across all the executions since the last event was generated.\n\t */\n\tmaxDuration?: number;\n}\n\n/**\n * Helper class that executes a specified code block and writes an\n * {@link @fluidframework/common-definitions#ITelemetryPerformanceEvent} to a specified logger every time a specified\n * number of executions is reached (or when the class is disposed). The `duration` field in the telemetry event is\n * the duration of the latest execution (sample) of the specified function. See the documentation of the\n * `includeAggregateMetrics` parameter for additional details that can be included.\n */\nexport class SampledTelemetryHelper implements IDisposable {\n\tdisposed: boolean = false;\n\n\tprivate readonly measurementsMap = new Map<string, Measurements>();\n\n\t/**\n\t * @param eventBase -\n\t * Custom properties to include in the telemetry performance event when it is written.\n\t * @param logger -\n\t * The logger to use to write the telemetry performance event.\n\t * @param sampleThreshold -\n\t * Telemetry performance events will be generated every time we hit this many executions of the code block.\n\t * @param includeAggregateMetrics -\n\t * If set to `true`, the telemetry performance event will include aggregated metrics (total duration, min duration,\n\t * max duration) for all the executions in between generated events.\n\t * @param perBucketProperties -\n\t * Map of strings that represent different buckets (which can be specified when calling the 'measure' method), to\n\t * properties which should be added to the telemetry event for that bucket. If a bucket being measured does not\n\t * have an entry in this map, no additional properties will be added to its telemetry events. The following keys are\n\t * reserved for use by this class: \"duration\", \"count\", \"totalDuration\", \"minDuration\", \"maxDuration\". If any of\n\t * them is specified as a key in one of the ITelemetryProperties objects in this map, that key-value pair will be\n\t * ignored.\n\t */\n\tpublic constructor(\n\t\tprivate readonly eventBase: ITelemetryGenericEvent,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate readonly sampleThreshold: number,\n\t\tprivate readonly includeAggregateMetrics: boolean = false,\n\t\tprivate readonly perBucketProperties = new Map<string, ITelemetryProperties>(),\n\t) {}\n\n\t/**\n\t * @param codeToMeasure -\n\t * The code to be executed and measured.\n\t * @param bucket -\n\t * A key to track executions of the code block separately. Each different value of this parameter has a separate\n\t * set of executions and metrics tracked by the class. If no such distinction needs to be made, do not provide a\n\t * value.\n\t * @returns Whatever the passed-in code block returns.\n\t */\n\tpublic measure<T>(codeToMeasure: () => T, bucket: string = \"\"): T {\n\t\tconst start = performance.now();\n\t\tconst returnValue = codeToMeasure();\n\t\tconst duration = performance.now() - start;\n\n\t\tlet m = this.measurementsMap.get(bucket);\n\t\tif (m === undefined) {\n\t\t\tm = { count: 0, duration: -1 };\n\t\t\tthis.measurementsMap.set(bucket, m);\n\t\t}\n\t\tm.count++;\n\t\tm.duration = duration;\n\n\t\tif (this.includeAggregateMetrics) {\n\t\t\tm.totalDuration = (m.totalDuration ?? 0) + duration;\n\t\t\tm.minDuration = Math.min(m.minDuration ?? duration, duration);\n\t\t\tm.maxDuration = Math.max(m.maxDuration ?? 0, duration);\n\t\t}\n\n\t\tif (m.count >= this.sampleThreshold) {\n\t\t\tthis.flushBucket(bucket);\n\t\t}\n\n\t\treturn returnValue;\n\t}\n\n\tprivate flushBucket(bucket: string) {\n\t\tconst measurements = this.measurementsMap.get(bucket);\n\t\tif (measurements === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (measurements.count !== 0) {\n\t\t\tconst bucketProperties = this.perBucketProperties.get(bucket);\n\n\t\t\tconst telemetryEvent: ITelemetryPerformanceEvent = {\n\t\t\t\t...this.eventBase,\n\t\t\t\t...bucketProperties, // If the bucket doesn't exist and this is undefined, things work as expected\n\t\t\t\t...measurements,\n\t\t\t};\n\n\t\t\tthis.logger.sendPerformanceEvent(telemetryEvent);\n\t\t\tthis.measurementsMap.delete(bucket);\n\t\t}\n\t}\n\n\tpublic dispose(error?: Error | undefined): void {\n\t\tthis.measurementsMap.forEach((_, k) => this.flushBucket(k));\n\t}\n}\n"]}
1
+ {"version":3,"file":"sampledTelemetryHelper.js","sourceRoot":"","sources":["../src/sampledTelemetryHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAkC3D;;;;;;GAMG;AACH,MAAM,OAAO,sBAAsB;IAKlC;;;;;;;;;;;;;;;;;OAiBG;IACH,YACkB,SAAiC,EACjC,MAA2B,EAC3B,eAAuB,EACvB,0BAAmC,KAAK,EACxC,sBAAsB,IAAI,GAAG,EAAgC;QAJ7D,cAAS,GAAT,SAAS,CAAwB;QACjC,WAAM,GAAN,MAAM,CAAqB;QAC3B,oBAAe,GAAf,eAAe,CAAQ;QACvB,4BAAuB,GAAvB,uBAAuB,CAAiB;QACxC,wBAAmB,GAAnB,mBAAmB,CAA0C;QA3B/E,aAAQ,GAAY,KAAK,CAAC;QAET,oBAAe,GAAG,IAAI,GAAG,EAAwB,CAAC;IA0BhE,CAAC;IAEJ;;;;;;;;OAQG;IACI,OAAO,CAAI,aAAsB,EAAE,SAAiB,EAAE;QAC5D,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAChC,MAAM,WAAW,GAAG,aAAa,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QAE3C,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK,SAAS,EAAE;YACpB,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC;YAC/B,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;SACpC;QACD,CAAC,CAAC,KAAK,EAAE,CAAC;QACV,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAEtB,IAAI,IAAI,CAAC,uBAAuB,EAAE;YACjC,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC;YACpD,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC9D,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;SACvD;QAED,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE;YACpC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;SACzB;QAED,OAAO,WAAW,CAAC;IACpB,CAAC;IAEO,WAAW,CAAC,MAAc;QACjC,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtD,IAAI,YAAY,KAAK,SAAS,EAAE;YAC/B,OAAO;SACP;QAED,IAAI,YAAY,CAAC,KAAK,KAAK,CAAC,EAAE;YAC7B,MAAM,gBAAgB,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAE9D,MAAM,cAAc,GAA+B;gBAClD,GAAG,IAAI,CAAC,SAAS;gBACjB,GAAG,gBAAgB;gBACnB,GAAG,YAAY;aACf,CAAC;YAEF,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC;YACjD,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;SACpC;IACF,CAAC;IAEM,OAAO,CAAC,KAAyB;QACvC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tITelemetryGenericEvent,\n\tITelemetryPerformanceEvent,\n\tITelemetryProperties,\n\tIDisposable,\n} from \"@fluidframework/core-interfaces\";\nimport { performance } from \"@fluidframework/common-utils\";\nimport { ITelemetryLoggerExt } from \"./telemetryTypes\";\n\ninterface Measurements {\n\t// The names of the properties in this interface are the ones that will get stamped in the\n\t// telemetry event, changes should be considered carefully. The optional properties should\n\t// only be populated if 'includeAggregateMetrics' is true.\n\n\t/**\n\t * The duration of the latest execution.\n\t */\n\tduration: number;\n\n\t/**\n\t * The number of executions since the last time an event was generated.\n\t */\n\tcount: number;\n\n\t/**\n\t * Total duration across all the executions since the last event was generated.\n\t */\n\ttotalDuration?: number;\n\n\t/**\n\t * Min duration across all the executions since the last event was generated.\n\t */\n\tminDuration?: number;\n\n\t/**\n\t * Max duration across all the executions since the last event was generated.\n\t */\n\tmaxDuration?: number;\n}\n\n/**\n * Helper class that executes a specified code block and writes an\n * {@link @fluidframework/common-definitions#ITelemetryPerformanceEvent} to a specified logger every time a specified\n * number of executions is reached (or when the class is disposed). The `duration` field in the telemetry event is\n * the duration of the latest execution (sample) of the specified function. See the documentation of the\n * `includeAggregateMetrics` parameter for additional details that can be included.\n */\nexport class SampledTelemetryHelper implements IDisposable {\n\tdisposed: boolean = false;\n\n\tprivate readonly measurementsMap = new Map<string, Measurements>();\n\n\t/**\n\t * @param eventBase -\n\t * Custom properties to include in the telemetry performance event when it is written.\n\t * @param logger -\n\t * The logger to use to write the telemetry performance event.\n\t * @param sampleThreshold -\n\t * Telemetry performance events will be generated every time we hit this many executions of the code block.\n\t * @param includeAggregateMetrics -\n\t * If set to `true`, the telemetry performance event will include aggregated metrics (total duration, min duration,\n\t * max duration) for all the executions in between generated events.\n\t * @param perBucketProperties -\n\t * Map of strings that represent different buckets (which can be specified when calling the 'measure' method), to\n\t * properties which should be added to the telemetry event for that bucket. If a bucket being measured does not\n\t * have an entry in this map, no additional properties will be added to its telemetry events. The following keys are\n\t * reserved for use by this class: \"duration\", \"count\", \"totalDuration\", \"minDuration\", \"maxDuration\". If any of\n\t * them is specified as a key in one of the ITelemetryProperties objects in this map, that key-value pair will be\n\t * ignored.\n\t */\n\tpublic constructor(\n\t\tprivate readonly eventBase: ITelemetryGenericEvent,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate readonly sampleThreshold: number,\n\t\tprivate readonly includeAggregateMetrics: boolean = false,\n\t\tprivate readonly perBucketProperties = new Map<string, ITelemetryProperties>(),\n\t) {}\n\n\t/**\n\t * @param codeToMeasure -\n\t * The code to be executed and measured.\n\t * @param bucket -\n\t * A key to track executions of the code block separately. Each different value of this parameter has a separate\n\t * set of executions and metrics tracked by the class. If no such distinction needs to be made, do not provide a\n\t * value.\n\t * @returns Whatever the passed-in code block returns.\n\t */\n\tpublic measure<T>(codeToMeasure: () => T, bucket: string = \"\"): T {\n\t\tconst start = performance.now();\n\t\tconst returnValue = codeToMeasure();\n\t\tconst duration = performance.now() - start;\n\n\t\tlet m = this.measurementsMap.get(bucket);\n\t\tif (m === undefined) {\n\t\t\tm = { count: 0, duration: -1 };\n\t\t\tthis.measurementsMap.set(bucket, m);\n\t\t}\n\t\tm.count++;\n\t\tm.duration = duration;\n\n\t\tif (this.includeAggregateMetrics) {\n\t\t\tm.totalDuration = (m.totalDuration ?? 0) + duration;\n\t\t\tm.minDuration = Math.min(m.minDuration ?? duration, duration);\n\t\t\tm.maxDuration = Math.max(m.maxDuration ?? 0, duration);\n\t\t}\n\n\t\tif (m.count >= this.sampleThreshold) {\n\t\t\tthis.flushBucket(bucket);\n\t\t}\n\n\t\treturn returnValue;\n\t}\n\n\tprivate flushBucket(bucket: string) {\n\t\tconst measurements = this.measurementsMap.get(bucket);\n\t\tif (measurements === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (measurements.count !== 0) {\n\t\t\tconst bucketProperties = this.perBucketProperties.get(bucket);\n\n\t\t\tconst telemetryEvent: ITelemetryPerformanceEvent = {\n\t\t\t\t...this.eventBase,\n\t\t\t\t...bucketProperties, // If the bucket doesn't exist and this is undefined, things work as expected\n\t\t\t\t...measurements,\n\t\t\t};\n\n\t\t\tthis.logger.sendPerformanceEvent(telemetryEvent);\n\t\t\tthis.measurementsMap.delete(bucket);\n\t\t}\n\t}\n\n\tpublic dispose(error?: Error | undefined): void {\n\t\tthis.measurementsMap.forEach((_, k) => this.flushBucket(k));\n\t}\n}\n"]}
package/lib/utils.js CHANGED
@@ -11,7 +11,7 @@ export function logIfFalse(condition, logger, event) {
11
11
  }
12
12
  const newEvent = typeof event === "string"
13
13
  ? { eventName: event, category: "error" }
14
- : Object.assign({ category: "error" }, event);
14
+ : { category: "error", ...event };
15
15
  logger.send(newEvent);
16
16
  return false;
17
17
  }
package/lib/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAUA;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CACzB,SAAc,EACd,MAA4B,EAC5B,KAAsC;IAEtC,IAAI,SAAS,EAAE;QACd,OAAO,IAAI,CAAC;KACZ;IACD,MAAM,QAAQ,GACb,OAAO,KAAK,KAAK,QAAQ;QACxB,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE;QACzC,CAAC,iBAAG,QAAQ,EAAE,OAAO,IAAK,KAAK,CAAE,CAAC;IACpC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtB,OAAO,KAAK,CAAC;AACd,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\nimport {\n\tITelemetryBaseEvent,\n\tITelemetryBaseLogger,\n\tITelemetryGenericEvent,\n} from \"@fluidframework/core-interfaces\";\n\n/**\n * Like assert, but logs only if the condition is false, rather than throwing\n * @param condition - The condition to attest too\n * @param logger - The logger to log with\n * @param event - The string or event to log\n * @returns - The outcome of the condition\n */\nexport function logIfFalse(\n\tcondition: any,\n\tlogger: ITelemetryBaseLogger,\n\tevent: string | ITelemetryGenericEvent,\n): condition is true {\n\tif (condition) {\n\t\treturn true;\n\t}\n\tconst newEvent: ITelemetryBaseEvent =\n\t\ttypeof event === \"string\"\n\t\t\t? { eventName: event, category: \"error\" }\n\t\t\t: { category: \"error\", ...event };\n\tlogger.send(newEvent);\n\treturn false;\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAUA;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CACzB,SAAc,EACd,MAA4B,EAC5B,KAAsC;IAEtC,IAAI,SAAS,EAAE;QACd,OAAO,IAAI,CAAC;KACZ;IACD,MAAM,QAAQ,GACb,OAAO,KAAK,KAAK,QAAQ;QACxB,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE;QACzC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;IACpC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtB,OAAO,KAAK,CAAC;AACd,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\nimport {\n\tITelemetryBaseEvent,\n\tITelemetryBaseLogger,\n\tITelemetryGenericEvent,\n} from \"@fluidframework/core-interfaces\";\n\n/**\n * Like assert, but logs only if the condition is false, rather than throwing\n * @param condition - The condition to attest too\n * @param logger - The logger to log with\n * @param event - The string or event to log\n * @returns - The outcome of the condition\n */\nexport function logIfFalse(\n\tcondition: any,\n\tlogger: ITelemetryBaseLogger,\n\tevent: string | ITelemetryGenericEvent,\n): condition is true {\n\tif (condition) {\n\t\treturn true;\n\t}\n\tconst newEvent: ITelemetryBaseEvent =\n\t\ttypeof event === \"string\"\n\t\t\t? { eventName: event, category: \"error\" }\n\t\t\t: { category: \"error\", ...event };\n\tlogger.send(newEvent);\n\treturn false;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/telemetry-utils",
3
- "version": "2.0.0-internal.5.4.0",
3
+ "version": "2.0.0-internal.6.0.0",
4
4
  "description": "Collection of telemetry relates utilities for Fluid",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -41,18 +41,18 @@
41
41
  "dependencies": {
42
42
  "@fluidframework/common-definitions": "^0.20.1",
43
43
  "@fluidframework/common-utils": "^1.1.1",
44
- "@fluidframework/core-interfaces": ">=2.0.0-internal.5.4.0 <2.0.0-internal.5.5.0",
45
- "@fluidframework/core-utils": ">=2.0.0-internal.5.4.0 <2.0.0-internal.5.5.0",
44
+ "@fluidframework/core-interfaces": ">=2.0.0-internal.6.0.0 <2.0.0-internal.6.1.0",
45
+ "@fluidframework/core-utils": ">=2.0.0-internal.6.0.0 <2.0.0-internal.6.1.0",
46
46
  "debug": "^4.1.1",
47
47
  "events": "^3.1.0",
48
48
  "uuid": "^8.3.1"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@fluid-tools/build-cli": "^0.21.0",
52
- "@fluidframework/build-common": "^1.2.0",
52
+ "@fluidframework/build-common": "^2.0.0",
53
53
  "@fluidframework/build-tools": "^0.21.0",
54
54
  "@fluidframework/eslint-config-fluid": "^2.0.0",
55
- "@fluidframework/mocha-test-setup": ">=2.0.0-internal.5.4.0 <2.0.0-internal.5.5.0",
55
+ "@fluidframework/mocha-test-setup": ">=2.0.0-internal.6.0.0 <2.0.0-internal.6.1.0",
56
56
  "@fluidframework/telemetry-utils-previous": "npm:@fluidframework/telemetry-utils@2.0.0-internal.5.2.0",
57
57
  "@microsoft/api-extractor": "^7.34.4",
58
58
  "@types/debug": "^4.1.5",
@@ -75,7 +75,40 @@
75
75
  "typescript": "~4.5.5"
76
76
  },
77
77
  "typeValidation": {
78
- "broken": {}
78
+ "broken": {
79
+ "RemovedClassDeclaration_BaseTelemetryNullLogger": {
80
+ "forwardCompat": false,
81
+ "backCompat": false
82
+ },
83
+ "RemovedClassDeclaration_ChildLogger": {
84
+ "forwardCompat": false,
85
+ "backCompat": false
86
+ },
87
+ "RemovedClassDeclaration_DebugLogger": {
88
+ "forwardCompat": false,
89
+ "backCompat": false
90
+ },
91
+ "RemovedClassDeclaration_MultiSinkLogger": {
92
+ "forwardCompat": false,
93
+ "backCompat": false
94
+ },
95
+ "RemovedClassDeclaration_TelemetryLogger": {
96
+ "forwardCompat": false,
97
+ "backCompat": false
98
+ },
99
+ "RemovedClassDeclaration_TelemetryNullLogger": {
100
+ "forwardCompat": false,
101
+ "backCompat": false
102
+ },
103
+ "RemovedClassDeclaration_TelemetryUTLogger": {
104
+ "forwardCompat": false,
105
+ "backCompat": false
106
+ },
107
+ "ClassDeclaration_MockLogger": {
108
+ "forwardCompat": false,
109
+ "backCompat": false
110
+ }
111
+ }
79
112
  },
80
113
  "scripts": {
81
114
  "build": "fluid-build . --task build",
package/src/index.ts CHANGED
@@ -12,7 +12,6 @@ export {
12
12
  ConfigTypes,
13
13
  loggerToMonitoringContext,
14
14
  } from "./config";
15
- export { DebugLogger } from "./debugLogger";
16
15
  export {
17
16
  extractLogSafeErrorProperties,
18
17
  generateErrorWithStack,
@@ -43,15 +42,12 @@ export {
43
42
  } from "./fluidErrorBase";
44
43
  export {
45
44
  eventNamespaceSeparator,
46
- BaseTelemetryNullLogger,
47
- ChildLogger,
48
45
  createChildLogger,
49
46
  createMultiSinkLogger,
50
47
  formatTick,
51
48
  IPerformanceEventMarkers,
52
49
  ITelemetryLoggerPropertyBag,
53
50
  ITelemetryLoggerPropertyBags,
54
- MultiSinkLogger,
55
51
  numberFromString,
56
52
  PerformanceEvent,
57
53
  TaggedLoggerAdapter,
@@ -59,9 +55,6 @@ export {
59
55
  tagCodeArtifacts,
60
56
  TelemetryDataTag,
61
57
  TelemetryEventPropertyTypes,
62
- TelemetryLogger,
63
- TelemetryNullLogger,
64
- TelemetryUTLogger,
65
58
  } from "./logger";
66
59
  export { MockLogger } from "./mockLogger";
67
60
  export { ThresholdCounter } from "./thresholdCounter";
package/src/logger.ts CHANGED
@@ -84,33 +84,10 @@ export const eventNamespaceSeparator = ":" as const;
84
84
  * encoding in one place schemas for various types of Fluid telemetry events.
85
85
  * Creates sub-logger that appends properties to all events
86
86
  *
87
- * @deprecated - In a subsequent release this type will no longer be exported, use ITelemetryLogger instead
88
87
  */
89
88
  export abstract class TelemetryLogger implements ITelemetryLoggerExt {
90
89
  public static readonly eventNamespaceSeparator = eventNamespaceSeparator;
91
90
 
92
- /**
93
- * @deprecated - use formatTick
94
- */
95
- public static formatTick(tick: number): number {
96
- return Math.floor(tick);
97
- }
98
-
99
- /**
100
- * Attempts to parse number from string.
101
- * If fails,returns original string.
102
- * Used to make telemetry data typed (and support math operations, like comparison),
103
- * in places where we do expect numbers (like contentsize/duration property in http header)
104
- * @deprecated - use numberFromString
105
- */
106
- public static numberFromString(str: string | null | undefined): string | number | undefined {
107
- if (str === undefined || str === null) {
108
- return undefined;
109
- }
110
- const num = Number(str);
111
- return Number.isNaN(num) ? str : num;
112
- }
113
-
114
91
  public static sanitizePkgName(name: string) {
115
92
  return name.replace("@", "").replace("/", "-");
116
93
  }
@@ -330,9 +307,6 @@ export function createChildLogger(props?: {
330
307
  namespace?: string;
331
308
  properties?: ITelemetryLoggerPropertyBags;
332
309
  }): ITelemetryLoggerExt {
333
- if (props === undefined) {
334
- return new TelemetryNullLogger();
335
- }
336
310
  return ChildLogger.create(props?.logger, props?.namespace, props?.properties);
337
311
  }
338
312
 
@@ -340,7 +314,6 @@ export function createChildLogger(props?: {
340
314
  * ChildLogger class contains various helper telemetry methods,
341
315
  * encoding in one place schemas for various types of Fluid telemetry events.
342
316
  * Creates sub-logger that appends properties to all events
343
- * @deprecated - Use createChildLogger instead
344
317
  */
345
318
  export class ChildLogger extends TelemetryLogger {
346
319
  /**
@@ -383,14 +356,19 @@ export class ChildLogger extends TelemetryLogger {
383
356
  ? baseLogger.namespace
384
357
  : `${baseLogger.namespace}${TelemetryLogger.eventNamespaceSeparator}${namespace}`;
385
358
 
386
- return new ChildLogger(baseLogger.baseLogger, combinedNamespace, combinedProperties);
359
+ const child = new ChildLogger(
360
+ baseLogger.baseLogger,
361
+ combinedNamespace,
362
+ combinedProperties,
363
+ );
364
+
365
+ if (!loggerIsMonitoringContext(child) && loggerIsMonitoringContext(baseLogger)) {
366
+ mixinMonitoringContext(child, baseLogger.config);
367
+ }
368
+ return child;
387
369
  }
388
370
 
389
- return new ChildLogger(
390
- baseLogger ? baseLogger : new BaseTelemetryNullLogger(),
391
- namespace,
392
- properties,
393
- );
371
+ return new ChildLogger(baseLogger ? baseLogger : { send() {} }, namespace, properties);
394
372
  }
395
373
 
396
374
  private constructor(
@@ -438,7 +416,6 @@ export function createMultiSinkLogger(props: {
438
416
  /**
439
417
  * Multi-sink logger
440
418
  * Takes multiple ITelemetryBaseLogger objects (sinks) and logs all events into each sink
441
- * @deprecated - use createMultiSinkLogger instead
442
419
  */
443
420
  export class MultiSinkLogger extends TelemetryLogger {
444
421
  protected loggers: ITelemetryBaseLogger[];
@@ -651,70 +628,6 @@ export class PerformanceEvent {
651
628
  }
652
629
  }
653
630
 
654
- /**
655
- * Logger that is useful for UT
656
- * It can be used in places where logger instance is required, but events should be not send over.
657
- * @deprecated - Use createChildLogger instead
658
- */
659
- export class TelemetryUTLogger implements ITelemetryLoggerExt {
660
- public send(event: ITelemetryBaseEvent): void {}
661
- public sendTelemetryEvent(event: ITelemetryGenericEvent, error?: any) {}
662
- public sendErrorEvent(event: ITelemetryErrorEvent, error?: any) {
663
- this.reportError("errorEvent in UT logger!", event, error);
664
- }
665
- public sendPerformanceEvent(event: ITelemetryPerformanceEvent, error?: any): void {}
666
- public logGenericError(eventName: string, error: any) {
667
- this.reportError(`genericError in UT logger!`, { eventName }, error);
668
- }
669
- public logException(event: ITelemetryErrorEvent, exception: any): void {
670
- this.reportError("exception in UT logger!", event, exception);
671
- }
672
- public debugAssert(condition: boolean, event?: ITelemetryErrorEvent): void {
673
- this.reportError("debugAssert in UT logger!");
674
- }
675
- public shipAssert(condition: boolean, event?: ITelemetryErrorEvent): void {
676
- this.reportError("shipAssert in UT logger!");
677
- }
678
-
679
- private reportError(message: string, event?: ITelemetryErrorEvent, err?: any) {
680
- const error = new Error(message);
681
- (error as any).error = error;
682
- (error as any).event = event;
683
- // report to console as exception can be eaten
684
- console.error(message);
685
- console.error(error);
686
- throw error;
687
- }
688
- }
689
-
690
- /**
691
- * Null logger
692
- * It can be used in places where logger instance is required, but events should be not send over.
693
- * @deprecated - for internal use only
694
- */
695
- export class BaseTelemetryNullLogger implements ITelemetryBaseLogger {
696
- /**
697
- * Send an event with the logger
698
- *
699
- * @param event - the event to send
700
- */
701
- public send(event: ITelemetryBaseEvent): void {
702
- return;
703
- }
704
- }
705
-
706
- /**
707
- * Null logger
708
- * It can be used in places where logger instance is required, but events should be not send over.
709
- * @deprecated - for internal use only
710
- */
711
- export class TelemetryNullLogger implements ITelemetryLoggerExt {
712
- public send(event: ITelemetryBaseEvent): void {}
713
- public sendTelemetryEvent(event: ITelemetryGenericEvent, error?: any): void {}
714
- public sendErrorEvent(event: ITelemetryErrorEvent, error?: any): void {}
715
- public sendPerformanceEvent(event: ITelemetryPerformanceEvent, error?: any): void {}
716
- }
717
-
718
631
  /**
719
632
  * Takes in an event object, and converts all of its values to a basePropertyType.
720
633
  * In the case of an invalid property type, the value will be converted to an error string.
package/src/mockLogger.ts CHANGED
@@ -3,26 +3,26 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import { ITelemetryBaseEvent } from "@fluidframework/core-interfaces";
6
+ import { ITelemetryBaseEvent, ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
7
7
  import { assert } from "@fluidframework/common-utils";
8
- import { TelemetryLogger } from "./logger";
9
- import { ITelemetryLoggerExt, ITelemetryPropertiesExt } from "./telemetryTypes";
8
+ import { ITelemetryPropertiesExt } from "./telemetryTypes";
9
+ import { createChildLogger } from "./logger";
10
10
 
11
11
  /**
12
12
  * The MockLogger records events sent to it, and then can walk back over those events
13
13
  * searching for a set of expected events to match against the logged events.
14
14
  */
15
- export class MockLogger extends TelemetryLogger implements ITelemetryLoggerExt {
15
+ export class MockLogger implements ITelemetryBaseLogger {
16
16
  events: ITelemetryBaseEvent[] = [];
17
17
 
18
- constructor() {
19
- super();
20
- }
21
-
22
18
  clear() {
23
19
  this.events = [];
24
20
  }
25
21
 
22
+ toTelemetryLogger() {
23
+ return createChildLogger({ logger: this });
24
+ }
25
+
26
26
  send(event: ITelemetryBaseEvent): void {
27
27
  this.events.push(event);
28
28
  }
@@ -1,39 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
- import { ITelemetryBaseEvent, ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
6
- import { IDebugger } from "debug";
7
- import { TelemetryLogger, ITelemetryLoggerPropertyBags } from "./logger";
8
- /**
9
- * Implementation of debug logger
10
- * @deprecated - DebugLogger is internal and will no longer be exported.
11
- */
12
- export declare class DebugLogger extends TelemetryLogger {
13
- private readonly debug;
14
- private readonly debugErr;
15
- /**
16
- * Create debug logger - all events are output to debug npm library
17
- * @param namespace - Telemetry event name prefix to add to all events
18
- * @param properties - Base properties to add to all events
19
- * @param propertyGetters - Getters to add additional properties to all events
20
- */
21
- static create(namespace: string, properties?: ITelemetryLoggerPropertyBags): TelemetryLogger;
22
- /**
23
- * Mix in debug logger with another logger.
24
- * Returned logger will output events to both newly created debug logger, as well as base logger
25
- * @param namespace - Telemetry event name prefix to add to all events
26
- * @param properties - Base properties to add to all events
27
- * @param propertyGetters - Getters to add additional properties to all events
28
- * @param logger - Base logger to output events (in addition to debug logger being created). Can be undefined.
29
- */
30
- static mixinDebugLogger(namespace: string, logger?: ITelemetryBaseLogger, properties?: ITelemetryLoggerPropertyBags): TelemetryLogger;
31
- constructor(debug: IDebugger, debugErr: IDebugger, properties?: ITelemetryLoggerPropertyBags);
32
- /**
33
- * Send an event to debug loggers
34
- *
35
- * @param event - the event to send
36
- */
37
- send(event: ITelemetryBaseEvent): void;
38
- }
39
- //# sourceMappingURL=debugLogger.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"debugLogger.d.ts","sourceRoot":"","sources":["../src/debugLogger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,mBAAmB,EACnB,oBAAoB,EAEpB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAA0B,SAAS,EAAE,MAAM,OAAO,CAAC;AAC1D,OAAO,EACN,eAAe,EAEf,4BAA4B,EAG5B,MAAM,UAAU,CAAC;AAClB;;;GAGG;AACH,qBAAa,WAAY,SAAQ,eAAe;IA2D9C,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IA3D1B;;;;;OAKG;WACW,MAAM,CACnB,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,4BAA4B,GACvC,eAAe;IAqBlB;;;;;;;OAOG;WACW,gBAAgB,CAC7B,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,oBAAoB,EAC7B,UAAU,CAAC,EAAE,4BAA4B,GACvC,eAAe;gBAgBA,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,SAAS,EACpC,UAAU,CAAC,EAAE,4BAA4B;IAK1C;;;;OAIG;IACI,IAAI,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;CA2C7C"}
@@ -1,105 +0,0 @@
1
- "use strict";
2
- /*!
3
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
- * Licensed under the MIT License.
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.DebugLogger = void 0;
8
- const common_utils_1 = require("@fluidframework/common-utils");
9
- const debug_1 = require("debug");
10
- const logger_1 = require("./logger");
11
- /**
12
- * Implementation of debug logger
13
- * @deprecated - DebugLogger is internal and will no longer be exported.
14
- */
15
- class DebugLogger extends logger_1.TelemetryLogger {
16
- constructor(debug, debugErr, properties) {
17
- super(undefined, properties);
18
- this.debug = debug;
19
- this.debugErr = debugErr;
20
- }
21
- /**
22
- * Create debug logger - all events are output to debug npm library
23
- * @param namespace - Telemetry event name prefix to add to all events
24
- * @param properties - Base properties to add to all events
25
- * @param propertyGetters - Getters to add additional properties to all events
26
- */
27
- static create(namespace, properties) {
28
- // Setup base logger upfront, such that host can disable it (if needed)
29
- const debug = (0, debug_1.debug)(namespace);
30
- // Create one for errors that is always enabled
31
- // It can be silenced by replacing console.error if the debug namespace is not enabled.
32
- const debugErr = (0, debug_1.debug)(namespace);
33
- debugErr.log = function () {
34
- if (debug.enabled) {
35
- // if the namespace is enabled, just use the default logger
36
- debug_1.debug.log(...arguments);
37
- }
38
- else {
39
- // other wise, use the console logger (which could be replaced and silenced)
40
- console.error(...arguments);
41
- }
42
- };
43
- debugErr.enabled = true;
44
- return new DebugLogger(debug, debugErr, properties);
45
- }
46
- /**
47
- * Mix in debug logger with another logger.
48
- * Returned logger will output events to both newly created debug logger, as well as base logger
49
- * @param namespace - Telemetry event name prefix to add to all events
50
- * @param properties - Base properties to add to all events
51
- * @param propertyGetters - Getters to add additional properties to all events
52
- * @param logger - Base logger to output events (in addition to debug logger being created). Can be undefined.
53
- */
54
- static mixinDebugLogger(namespace, logger, properties) {
55
- if (!logger) {
56
- return DebugLogger.create(namespace, properties);
57
- }
58
- const multiSinkLogger = new logger_1.MultiSinkLogger(undefined, properties, [(0, logger_1.createChildLogger)({ logger, namespace }), DebugLogger.create(namespace)], true);
59
- return multiSinkLogger;
60
- }
61
- /**
62
- * Send an event to debug loggers
63
- *
64
- * @param event - the event to send
65
- */
66
- send(event) {
67
- const newEvent = this.prepareEvent(event);
68
- const isError = newEvent.category === "error";
69
- let logger = isError ? this.debugErr : this.debug;
70
- // Use debug's coloring schema for base of the event
71
- const index = event.eventName.lastIndexOf(logger_1.TelemetryLogger.eventNamespaceSeparator);
72
- const name = event.eventName.substring(index + 1);
73
- if (index > 0) {
74
- logger = logger.extend(event.eventName.substring(0, index));
75
- }
76
- newEvent.eventName = undefined;
77
- let tick = "";
78
- tick = `tick=${(0, logger_1.formatTick)(common_utils_1.performance.now())}`;
79
- // Extract stack to put it last, but also to avoid escaping '\n' in it by JSON.stringify below
80
- const stack = newEvent.stack ? newEvent.stack : "";
81
- newEvent.stack = undefined;
82
- // Watch out for circular references - they can come from two sources
83
- // 1) error object - we do not control it and should remove it and retry
84
- // 2) properties supplied by telemetry caller - that's a bug that should be addressed!
85
- let payload;
86
- try {
87
- payload = JSON.stringify(newEvent);
88
- }
89
- catch (error) {
90
- newEvent.error = undefined;
91
- payload = JSON.stringify(newEvent);
92
- }
93
- if (payload === "{}") {
94
- payload = "";
95
- }
96
- // Force errors out, to help with diagnostics
97
- if (isError) {
98
- logger.enabled = true;
99
- }
100
- // Print multi-line.
101
- logger(`${name} ${payload} ${tick} ${stack}`);
102
- }
103
- }
104
- exports.DebugLogger = DebugLogger;
105
- //# sourceMappingURL=debugLogger.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"debugLogger.js","sourceRoot":"","sources":["../src/debugLogger.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tITelemetryBaseEvent,\n\tITelemetryBaseLogger,\n\tITelemetryProperties,\n} from \"@fluidframework/core-interfaces\";\nimport { performance } from \"@fluidframework/common-utils\";\nimport { debug as registerDebug, IDebugger } from \"debug\";\nimport {\n\tTelemetryLogger,\n\tMultiSinkLogger,\n\tITelemetryLoggerPropertyBags,\n\tformatTick,\n\tcreateChildLogger,\n} from \"./logger\";\n/**\n * Implementation of debug logger\n * @deprecated - DebugLogger is internal and will no longer be exported.\n */\nexport class DebugLogger extends TelemetryLogger {\n\t/**\n\t * Create debug logger - all events are output to debug npm library\n\t * @param namespace - Telemetry event name prefix to add to all events\n\t * @param properties - Base properties to add to all events\n\t * @param propertyGetters - Getters to add additional properties to all events\n\t */\n\tpublic static create(\n\t\tnamespace: string,\n\t\tproperties?: ITelemetryLoggerPropertyBags,\n\t): TelemetryLogger {\n\t\t// Setup base logger upfront, such that host can disable it (if needed)\n\t\tconst debug = registerDebug(namespace);\n\n\t\t// Create one for errors that is always enabled\n\t\t// It can be silenced by replacing console.error if the debug namespace is not enabled.\n\t\tconst debugErr = registerDebug(namespace);\n\t\tdebugErr.log = function () {\n\t\t\tif (debug.enabled) {\n\t\t\t\t// if the namespace is enabled, just use the default logger\n\t\t\t\tregisterDebug.log(...arguments);\n\t\t\t} else {\n\t\t\t\t// other wise, use the console logger (which could be replaced and silenced)\n\t\t\t\tconsole.error(...arguments);\n\t\t\t}\n\t\t};\n\t\tdebugErr.enabled = true;\n\n\t\treturn new DebugLogger(debug, debugErr, properties);\n\t}\n\n\t/**\n\t * Mix in debug logger with another logger.\n\t * Returned logger will output events to both newly created debug logger, as well as base logger\n\t * @param namespace - Telemetry event name prefix to add to all events\n\t * @param properties - Base properties to add to all events\n\t * @param propertyGetters - Getters to add additional properties to all events\n\t * @param logger - Base logger to output events (in addition to debug logger being created). Can be undefined.\n\t */\n\tpublic static mixinDebugLogger(\n\t\tnamespace: string,\n\t\tlogger?: ITelemetryBaseLogger,\n\t\tproperties?: ITelemetryLoggerPropertyBags,\n\t): TelemetryLogger {\n\t\tif (!logger) {\n\t\t\treturn DebugLogger.create(namespace, properties);\n\t\t}\n\n\t\tconst multiSinkLogger = new MultiSinkLogger(\n\t\t\tundefined,\n\t\t\tproperties,\n\t\t\t[createChildLogger({ logger, namespace }), DebugLogger.create(namespace)],\n\t\t\ttrue,\n\t\t);\n\n\t\treturn multiSinkLogger;\n\t}\n\n\tconstructor(\n\t\tprivate readonly debug: IDebugger,\n\t\tprivate readonly debugErr: IDebugger,\n\t\tproperties?: ITelemetryLoggerPropertyBags,\n\t) {\n\t\tsuper(undefined, properties);\n\t}\n\n\t/**\n\t * Send an event to debug loggers\n\t *\n\t * @param event - the event to send\n\t */\n\tpublic send(event: ITelemetryBaseEvent): void {\n\t\tconst newEvent: ITelemetryProperties = this.prepareEvent(event);\n\t\tconst isError = newEvent.category === \"error\";\n\t\tlet logger = isError ? this.debugErr : this.debug;\n\n\t\t// Use debug's coloring schema for base of the event\n\t\tconst index = event.eventName.lastIndexOf(TelemetryLogger.eventNamespaceSeparator);\n\t\tconst name = event.eventName.substring(index + 1);\n\t\tif (index > 0) {\n\t\t\tlogger = logger.extend(event.eventName.substring(0, index));\n\t\t}\n\t\tnewEvent.eventName = undefined;\n\n\t\tlet tick = \"\";\n\t\ttick = `tick=${formatTick(performance.now())}`;\n\n\t\t// Extract stack to put it last, but also to avoid escaping '\\n' in it by JSON.stringify below\n\t\tconst stack = newEvent.stack ? newEvent.stack : \"\";\n\t\tnewEvent.stack = undefined;\n\n\t\t// Watch out for circular references - they can come from two sources\n\t\t// 1) error object - we do not control it and should remove it and retry\n\t\t// 2) properties supplied by telemetry caller - that's a bug that should be addressed!\n\t\tlet payload: string;\n\t\ttry {\n\t\t\tpayload = JSON.stringify(newEvent);\n\t\t} catch (error) {\n\t\t\tnewEvent.error = undefined;\n\t\t\tpayload = JSON.stringify(newEvent);\n\t\t}\n\n\t\tif (payload === \"{}\") {\n\t\t\tpayload = \"\";\n\t\t}\n\n\t\t// Force errors out, to help with diagnostics\n\t\tif (isError) {\n\t\t\tlogger.enabled = true;\n\t\t}\n\n\t\t// Print multi-line.\n\t\tlogger(`${name} ${payload} ${tick} ${stack}`);\n\t}\n}\n"]}