@fluidframework/telemetry-utils 2.0.0-dev-rc.5.0.0.271717 → 2.0.0-dev-rc.5.0.0.272251

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 (94) hide show
  1. package/.eslintrc.cjs +1 -1
  2. package/api-extractor/api-extractor-lint-bundle.json +5 -0
  3. package/api-extractor/api-extractor-lint-legacy.cjs.json +5 -0
  4. package/api-extractor/api-extractor-lint-legacy.esm.json +5 -0
  5. package/api-extractor/api-extractor-lint-public.cjs.json +5 -0
  6. package/api-extractor/api-extractor-lint-public.esm.json +5 -0
  7. package/api-report/telemetry-utils.alpha.api.md +13 -28
  8. package/api-report/telemetry-utils.beta.api.md +7 -7
  9. package/api-report/telemetry-utils.public.api.md +7 -7
  10. package/dist/config.d.ts +2 -2
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/config.js.map +1 -1
  13. package/dist/error.d.ts +5 -5
  14. package/dist/error.d.ts.map +1 -1
  15. package/dist/error.js.map +1 -1
  16. package/dist/errorLogging.d.ts +1 -1
  17. package/dist/errorLogging.d.ts.map +1 -1
  18. package/dist/errorLogging.js +21 -8
  19. package/dist/errorLogging.js.map +1 -1
  20. package/dist/eventEmitterWithErrorHandling.d.ts +2 -2
  21. package/dist/eventEmitterWithErrorHandling.d.ts.map +1 -1
  22. package/dist/eventEmitterWithErrorHandling.js.map +1 -1
  23. package/dist/index.d.ts +6 -6
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/logger.d.ts +3 -5
  27. package/dist/logger.d.ts.map +1 -1
  28. package/dist/logger.js.map +1 -1
  29. package/dist/mockLogger.d.ts +15 -7
  30. package/dist/mockLogger.d.ts.map +1 -1
  31. package/dist/mockLogger.js +16 -9
  32. package/dist/mockLogger.js.map +1 -1
  33. package/dist/sampledTelemetryHelper.d.ts +6 -2
  34. package/dist/sampledTelemetryHelper.d.ts.map +1 -1
  35. package/dist/sampledTelemetryHelper.js +10 -2
  36. package/dist/sampledTelemetryHelper.js.map +1 -1
  37. package/dist/telemetryTypes.d.ts +32 -18
  38. package/dist/telemetryTypes.d.ts.map +1 -1
  39. package/dist/telemetryTypes.js.map +1 -1
  40. package/dist/thresholdCounter.d.ts +1 -1
  41. package/dist/thresholdCounter.d.ts.map +1 -1
  42. package/dist/thresholdCounter.js.map +1 -1
  43. package/dist/utils.d.ts +1 -1
  44. package/dist/utils.d.ts.map +1 -1
  45. package/dist/utils.js.map +1 -1
  46. package/lib/config.d.ts +2 -2
  47. package/lib/config.d.ts.map +1 -1
  48. package/lib/config.js.map +1 -1
  49. package/lib/error.d.ts +5 -5
  50. package/lib/error.d.ts.map +1 -1
  51. package/lib/error.js.map +1 -1
  52. package/lib/errorLogging.d.ts +1 -1
  53. package/lib/errorLogging.d.ts.map +1 -1
  54. package/lib/errorLogging.js +21 -8
  55. package/lib/errorLogging.js.map +1 -1
  56. package/lib/eventEmitterWithErrorHandling.d.ts +2 -2
  57. package/lib/eventEmitterWithErrorHandling.d.ts.map +1 -1
  58. package/lib/eventEmitterWithErrorHandling.js.map +1 -1
  59. package/lib/index.d.ts +6 -6
  60. package/lib/index.d.ts.map +1 -1
  61. package/lib/index.js.map +1 -1
  62. package/lib/logger.d.ts +3 -5
  63. package/lib/logger.d.ts.map +1 -1
  64. package/lib/logger.js.map +1 -1
  65. package/lib/mockLogger.d.ts +15 -7
  66. package/lib/mockLogger.d.ts.map +1 -1
  67. package/lib/mockLogger.js +16 -9
  68. package/lib/mockLogger.js.map +1 -1
  69. package/lib/sampledTelemetryHelper.d.ts +6 -2
  70. package/lib/sampledTelemetryHelper.d.ts.map +1 -1
  71. package/lib/sampledTelemetryHelper.js +10 -2
  72. package/lib/sampledTelemetryHelper.js.map +1 -1
  73. package/lib/telemetryTypes.d.ts +32 -18
  74. package/lib/telemetryTypes.d.ts.map +1 -1
  75. package/lib/telemetryTypes.js.map +1 -1
  76. package/lib/thresholdCounter.d.ts +1 -1
  77. package/lib/thresholdCounter.d.ts.map +1 -1
  78. package/lib/thresholdCounter.js.map +1 -1
  79. package/lib/utils.d.ts +1 -1
  80. package/lib/utils.d.ts.map +1 -1
  81. package/lib/utils.js.map +1 -1
  82. package/package.json +16 -7
  83. package/src/config.ts +10 -10
  84. package/src/error.ts +13 -13
  85. package/src/errorLogging.ts +27 -14
  86. package/src/eventEmitterWithErrorHandling.ts +3 -3
  87. package/src/index.ts +11 -11
  88. package/src/logger.ts +11 -10
  89. package/src/mockLogger.ts +34 -20
  90. package/src/sampledTelemetryHelper.ts +15 -5
  91. package/src/telemetryTypes.ts +38 -19
  92. package/src/thresholdCounter.ts +1 -1
  93. package/src/utils.ts +2 -2
  94. package/tsdoc.json +4 -0
@@ -5,18 +5,22 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.MockLogger = void 0;
8
+ const core_interfaces_1 = require("@fluidframework/core-interfaces");
8
9
  const internal_1 = require("@fluidframework/core-utils/internal");
9
10
  const logger_js_1 = require("./logger.js");
10
11
  /**
11
- * The MockLogger records events sent to it, and then can walk back over those events
12
- * searching for a set of expected events to match against the logged events.
12
+ * Mock {@link @fluidframework/core-interfaces#ITelemetryBaseLogger} implementation.
13
+ *
14
+ * Records events sent to it, and then can walk back over those events, searching for a set of expected events to
15
+ * match against the logged events.
13
16
  *
14
17
  * @alpha
15
18
  */
16
19
  class MockLogger {
17
20
  constructor(minLogLevel) {
18
- this.minLogLevel = minLogLevel;
21
+ // TODO: don't expose mutability to external consumers
19
22
  this.events = [];
23
+ this.minLogLevel = minLogLevel ?? core_interfaces_1.LogLevel.default;
20
24
  }
21
25
  clear() {
22
26
  this.events = [];
@@ -24,8 +28,13 @@ class MockLogger {
24
28
  toTelemetryLogger() {
25
29
  return (0, logger_js_1.createChildLogger)({ logger: this });
26
30
  }
27
- send(event) {
28
- this.events.push(event);
31
+ /**
32
+ * {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseLogger.send}
33
+ */
34
+ send(event, logLevel) {
35
+ if (logLevel ?? core_interfaces_1.LogLevel.default >= this.minLogLevel) {
36
+ this.events.push(event);
37
+ }
29
38
  }
30
39
  /**
31
40
  * Search events logged since the last time matchEvents was called, looking for the given expected
@@ -132,7 +141,7 @@ ${JSON.stringify(actualEvents)}`);
132
141
  }
133
142
  }
134
143
  // Remove the events so far; next call will just compare subsequent events from here
135
- this.events = [];
144
+ this.clear();
136
145
  // Return the count of matched events.
137
146
  return iExpectedEvent;
138
147
  }
@@ -145,9 +154,7 @@ ${JSON.stringify(actualEvents)}`);
145
154
  // Some of the properties in the expected event may be inside "details". So, if inlineDetailsProp is true,
146
155
  // extract the properties from "details" in the actual event and inline them in the actual event.
147
156
  if (inlineDetailsProp && details !== undefined) {
148
- (0, internal_1.assert)(typeof details === "string",
149
- // eslint-disable-next-line unicorn/numeric-separators-style
150
- 0x6c9 /* Details should a JSON stringified string if inlineDetailsProp is true */);
157
+ (0, internal_1.assert)(typeof details === "string", 0x6c9 /* Details should a JSON stringified string if inlineDetailsProp is true */);
151
158
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
152
159
  const detailsExpanded = JSON.parse(details);
153
160
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
@@ -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 {\n\tITelemetryBaseEvent,\n\tITelemetryBaseLogger,\n\tLogLevel,\n} from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\n\nimport { createChildLogger } from \"./logger.js\";\nimport { ITelemetryLoggerExt, ITelemetryPropertiesExt } from \"./telemetryTypes.js\";\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 *\n * @alpha\n */\nexport class MockLogger implements ITelemetryBaseLogger {\n\tevents: ITelemetryBaseEvent[] = [];\n\n\tconstructor(public readonly minLogLevel?: LogLevel) {}\n\n\tclear(): void {\n\t\tthis.events = [];\n\t}\n\n\ttoTelemetryLogger(): ITelemetryLoggerExt {\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/**\n\t * Asserts that matchEvents is true, and prints the actual/expected output if not.\n\t */\n\tassertMatch(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t): void {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchEvents(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message ?? \"Logs don't match\"}\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/**\n\t * Asserts that matchAnyEvent is true, and prints the actual/expected output if not.\n\t */\n\tassertMatchAny(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t): void {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchAnyEvent(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message ?? \"Logs don't match\"}\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/**\n\t * Asserts that matchEvents is true, and prints the actual/expected output if not\n\t */\n\tassertMatchStrict(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t): void {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchEventStrict(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message ?? \"Logs don't match\"}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\t/**\n\t * Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not\n\t */\n\tassertMatchNone(\n\t\tdisallowedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t): void {\n\t\tconst actualEvents = this.events;\n\t\tif (this.matchAnyEvent(disallowedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message ?? \"Logs don't match\"}\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\tfor (const event of this.events) {\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\t// eslint-disable-next-line unicorn/numeric-separators-style\n\t\t\t\t0x6c9 /* Details should a JSON stringified string if inlineDetailsProp is true */,\n\t\t\t);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\tconst detailsExpanded = JSON.parse(details);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-argument\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): boolean {\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 {\n\ttype ITelemetryBaseEvent,\n\ttype ITelemetryBaseLogger,\n\tLogLevel,\n} from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\n\nimport { createChildLogger } from \"./logger.js\";\nimport type { ITelemetryLoggerExt, ITelemetryPropertiesExt } from \"./telemetryTypes.js\";\n\n/**\n * Mock {@link @fluidframework/core-interfaces#ITelemetryBaseLogger} implementation.\n *\n * Records events sent to it, and then can walk back over those events, searching for a set of expected events to\n * match against the logged events.\n *\n * @alpha\n */\nexport class MockLogger implements ITelemetryBaseLogger {\n\t// TODO: don't expose mutability to external consumers\n\tpublic events: ITelemetryBaseEvent[] = [];\n\n\t/**\n\t * {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseLogger.minLogLevel}\n\t */\n\tpublic readonly minLogLevel: LogLevel;\n\n\tpublic constructor(minLogLevel?: LogLevel) {\n\t\tthis.minLogLevel = minLogLevel ?? LogLevel.default;\n\t}\n\n\tpublic clear(): void {\n\t\tthis.events = [];\n\t}\n\n\tpublic toTelemetryLogger(): ITelemetryLoggerExt {\n\t\treturn createChildLogger({ logger: this });\n\t}\n\n\t/**\n\t * {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseLogger.send}\n\t */\n\tpublic send(event: ITelemetryBaseEvent, logLevel?: LogLevel): void {\n\t\tif (logLevel ?? LogLevel.default >= this.minLogLevel) {\n\t\t\tthis.events.push(event);\n\t\t}\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\tpublic matchEvents(\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/**\n\t * Asserts that matchEvents is true, and prints the actual/expected output if not.\n\t */\n\tpublic assertMatch(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t): void {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchEvents(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message ?? \"Logs don't match\"}\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\tpublic matchAnyEvent(\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/**\n\t * Asserts that matchAnyEvent is true, and prints the actual/expected output if not.\n\t */\n\tpublic assertMatchAny(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t): void {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchAnyEvent(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message ?? \"Logs don't match\"}\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\tpublic matchEventStrict(\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/**\n\t * Asserts that matchEvents is true, and prints the actual/expected output if not\n\t */\n\tpublic assertMatchStrict(\n\t\texpectedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t): void {\n\t\tconst actualEvents = this.events;\n\t\tif (!this.matchEventStrict(expectedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message ?? \"Logs don't match\"}\nexpected:\n${JSON.stringify(expectedEvents)}\n\nactual:\n${JSON.stringify(actualEvents)}`);\n\t\t}\n\t}\n\n\t/**\n\t * Asserts that matchAnyEvent is false for the given events, and prints the actual/expected output if not\n\t */\n\tpublic assertMatchNone(\n\t\tdisallowedEvents: Omit<ITelemetryBaseEvent, \"category\">[],\n\t\tmessage?: string,\n\t\tinlineDetailsProp: boolean = false,\n\t): void {\n\t\tconst actualEvents = this.events;\n\t\tif (this.matchAnyEvent(disallowedEvents, inlineDetailsProp)) {\n\t\t\tthrow new Error(`${message ?? \"Logs don't match\"}\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\tfor (const event of this.events) {\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.clear();\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\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\tconst detailsExpanded = JSON.parse(details);\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-argument\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): boolean {\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"]}
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
  import type { IDisposable, ITelemetryBaseProperties } from "@fluidframework/core-interfaces";
6
- import { type ITelemetryGenericEventExt, ITelemetryLoggerExt } from "./telemetryTypes.js";
6
+ import type { ITelemetryGenericEventExt, ITelemetryLoggerExt } from "./telemetryTypes.js";
7
7
  /**
8
8
  * Helper class that executes a specified code block and writes an
9
9
  * {@link @fluidframework/core-interfaces#ITelemetryPerformanceEvent} to a specified logger every time a specified
@@ -21,7 +21,11 @@ export declare class SampledTelemetryHelper implements IDisposable {
21
21
  private readonly sampleThreshold;
22
22
  private readonly includeAggregateMetrics;
23
23
  private readonly perBucketProperties;
24
- disposed: boolean;
24
+ private _disposed;
25
+ /**
26
+ * {@inheritDoc @fluidframework/core-interfaces#IDisposable.disposed}
27
+ */
28
+ get disposed(): boolean;
25
29
  private readonly measurementsMap;
26
30
  /**
27
31
  * @param eventBase -
@@ -1 +1 @@
1
- {"version":3,"file":"sampledTelemetryHelper.d.ts","sourceRoot":"","sources":["../src/sampledTelemetryHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAE7F,OAAO,EACN,KAAK,yBAAyB,EAC9B,mBAAmB,EAEnB,MAAM,qBAAqB,CAAC;AAoC7B;;;;;;;;;;GAUG;AACH,qBAAa,sBAAuB,YAAW,WAAW;IAwBxD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IA3BrC,QAAQ,EAAE,OAAO,CAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAmC;IAEnE;;;;;;;;;;;;;;;;;OAiBG;gBAEe,SAAS,EAAE,yBAAyB,EACpC,MAAM,EAAE,mBAAmB,EAC3B,eAAe,EAAE,MAAM,EACvB,uBAAuB,GAAE,OAAe,EACxC,mBAAmB,wCAA8C;IAGnF;;;;;;;;;OASG;IACI,OAAO,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,MAAM,GAAE,MAAW,GAAG,CAAC;IA0BjE,OAAO,CAAC,WAAW;IAoBZ,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI;CAG/C"}
1
+ {"version":3,"file":"sampledTelemetryHelper.d.ts","sourceRoot":"","sources":["../src/sampledTelemetryHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAE7F,OAAO,KAAK,EACX,yBAAyB,EACzB,mBAAmB,EAEnB,MAAM,qBAAqB,CAAC;AAoC7B;;;;;;;;;;GAUG;AACH,qBAAa,sBAAuB,YAAW,WAAW;IA+BxD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IAlCrC,OAAO,CAAC,SAAS,CAAkB;IAEnC;;OAEG;IACH,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAmC;IAEnE;;;;;;;;;;;;;;;;;OAiBG;gBAEe,SAAS,EAAE,yBAAyB,EACpC,MAAM,EAAE,mBAAmB,EAC3B,eAAe,EAAE,MAAM,EACvB,uBAAuB,GAAE,OAAe,EACxC,mBAAmB,wCAA8C;IAGnF;;;;;;;;;OASG;IACI,OAAO,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,MAAM,GAAE,MAAW,GAAG,CAAC;IA0BjE,OAAO,CAAC,WAAW;IAoBZ,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI;CAM/C"}
@@ -18,6 +18,12 @@ const client_utils_1 = require("@fluid-internal/client-utils");
18
18
  * @internal
19
19
  */
20
20
  class SampledTelemetryHelper {
21
+ /**
22
+ * {@inheritDoc @fluidframework/core-interfaces#IDisposable.disposed}
23
+ */
24
+ get disposed() {
25
+ return this._disposed;
26
+ }
21
27
  /**
22
28
  * @param eventBase -
23
29
  * Custom properties to include in the telemetry performance event when it is written.
@@ -42,7 +48,7 @@ class SampledTelemetryHelper {
42
48
  this.sampleThreshold = sampleThreshold;
43
49
  this.includeAggregateMetrics = includeAggregateMetrics;
44
50
  this.perBucketProperties = perBucketProperties;
45
- this.disposed = false;
51
+ this._disposed = false;
46
52
  this.measurementsMap = new Map();
47
53
  }
48
54
  /**
@@ -93,8 +99,10 @@ class SampledTelemetryHelper {
93
99
  }
94
100
  }
95
101
  dispose(error) {
96
- for (const [k] of this.measurementsMap.entries())
102
+ for (const [k] of this.measurementsMap.entries()) {
97
103
  this.flushBucket(k);
104
+ }
105
+ this._disposed = true;
98
106
  }
99
107
  }
100
108
  exports.SampledTelemetryHelper = SampledTelemetryHelper;
@@ -1 +1 @@
1
- {"version":3,"file":"sampledTelemetryHelper.js","sourceRoot":"","sources":["../src/sampledTelemetryHelper.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAA2D;AA2C3D;;;;;;;;;;GAUG;AACH,MAAa,sBAAsB;IAKlC;;;;;;;;;;;;;;;;;OAiBG;IACH,YACkB,SAAoC,EACpC,MAA2B,EAC3B,eAAuB,EACvB,0BAAmC,KAAK,EACxC,sBAAsB,IAAI,GAAG,EAAoC;QAJjE,cAAS,GAAT,SAAS,CAA2B;QACpC,WAAM,GAAN,MAAM,CAAqB;QAC3B,oBAAe,GAAf,eAAe,CAAQ;QACvB,4BAAuB,GAAvB,uBAAuB,CAAiB;QACxC,wBAAmB,GAAnB,mBAAmB,CAA8C;QA3BnF,aAAQ,GAAY,KAAK,CAAC;QAET,oBAAe,GAAG,IAAI,GAAG,EAAwB,CAAC;IA0BhE,CAAC;IAEJ;;;;;;;;;OASG;IACI,OAAO,CAAI,aAAsB,EAAE,SAAiB,EAAE;QAC5D,MAAM,KAAK,GAAG,0BAAW,CAAC,GAAG,EAAE,CAAC;QAChC,MAAM,WAAW,GAAG,aAAa,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,0BAAW,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,CAAC;YACrB,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;QACrC,CAAC;QACD,CAAC,CAAC,KAAK,EAAE,CAAC;QACV,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAEtB,IAAI,IAAI,CAAC,uBAAuB,EAAE,CAAC;YAClC,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;QACxD,CAAC;QAED,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACrC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;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,CAAC;YAChC,OAAO;QACR,CAAC;QAED,IAAI,YAAY,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,gBAAgB,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAE9D,MAAM,cAAc,GAAkC;gBACrD,GAAG,IAAI,CAAC,SAAS;gBACjB,GAAG,gBAAgB,EAAE,6EAA6E;gBAClG,GAAG,YAAY;aACf,CAAC;YAEF,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC;YACjD,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC;IACF,CAAC;IAEM,OAAO,CAAC,KAAyB;QACvC,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE;YAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC;CACD;AA1FD,wDA0FC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { performance } from \"@fluid-internal/client-utils\";\nimport type { IDisposable, ITelemetryBaseProperties } from \"@fluidframework/core-interfaces\";\n\nimport {\n\ttype ITelemetryGenericEventExt,\n\tITelemetryLoggerExt,\n\ttype ITelemetryPerformanceEventExt,\n} from \"./telemetryTypes.js\";\n\n/**\n * @privateRemarks\n *\n * The names of the properties in this interface are the ones that will get stamped in the\n * telemetry event, changes should be considered carefully. The optional properties should\n * only be populated if 'includeAggregateMetrics' is true.\n */\ninterface Measurements {\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/core-interfaces#ITelemetryPerformanceEvent} to a specified logger every time a specified\n * number of executions is reached (or when the class is disposed).\n *\n * The `duration` field in the telemetry event is the duration of the latest execution (sample) of the specified\n * function. See the documentation of the `includeAggregateMetrics` parameter for additional details that can be\n * included.\n *\n * @internal\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 ITelemetryBaseProperties objects in this map, that key-value pair will be\n\t * ignored.\n\t */\n\tpublic constructor(\n\t\tprivate readonly eventBase: ITelemetryGenericEventExt,\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, ITelemetryBaseProperties>(),\n\t) {}\n\n\t/**\n\t * Executes the specified code and keeps track of execution time statistics.\n\t * If it's been called enough times (the sampleThreshold for the class) then it generates a log message with the necessary information.\n\t *\n\t * @param codeToMeasure - The code to be executed and measured.\n\t * @param bucket - A key to track executions of the code block separately.\n\t * Each different value of this parameter has a separate set of executions and metrics tracked by the class.\n\t * If no such distinction needs to be made, do not provide a 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): void {\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: ITelemetryPerformanceEventExt = {\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\tfor (const [k] of this.measurementsMap.entries()) this.flushBucket(k);\n\t}\n}\n"]}
1
+ {"version":3,"file":"sampledTelemetryHelper.js","sourceRoot":"","sources":["../src/sampledTelemetryHelper.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 { performance } from \"@fluid-internal/client-utils\";\nimport type { IDisposable, ITelemetryBaseProperties } from \"@fluidframework/core-interfaces\";\n\nimport type {\n\tITelemetryGenericEventExt,\n\tITelemetryLoggerExt,\n\tITelemetryPerformanceEventExt,\n} from \"./telemetryTypes.js\";\n\n/**\n * @privateRemarks\n *\n * The names of the properties in this interface are the ones that will get stamped in the\n * telemetry event, changes should be considered carefully. The optional properties should\n * only be populated if 'includeAggregateMetrics' is true.\n */\ninterface Measurements {\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/core-interfaces#ITelemetryPerformanceEvent} to a specified logger every time a specified\n * number of executions is reached (or when the class is disposed).\n *\n * The `duration` field in the telemetry event is the duration of the latest execution (sample) of the specified\n * function. See the documentation of the `includeAggregateMetrics` parameter for additional details that can be\n * included.\n *\n * @internal\n */\nexport class SampledTelemetryHelper implements IDisposable {\n\tprivate _disposed: boolean = false;\n\n\t/**\n\t * {@inheritDoc @fluidframework/core-interfaces#IDisposable.disposed}\n\t */\n\tpublic get disposed(): boolean {\n\t\treturn this._disposed;\n\t}\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 ITelemetryBaseProperties objects in this map, that key-value pair will be\n\t * ignored.\n\t */\n\tpublic constructor(\n\t\tprivate readonly eventBase: ITelemetryGenericEventExt,\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, ITelemetryBaseProperties>(),\n\t) {}\n\n\t/**\n\t * Executes the specified code and keeps track of execution time statistics.\n\t * If it's been called enough times (the sampleThreshold for the class) then it generates a log message with the necessary information.\n\t *\n\t * @param codeToMeasure - The code to be executed and measured.\n\t * @param bucket - A key to track executions of the code block separately.\n\t * Each different value of this parameter has a separate set of executions and metrics tracked by the class.\n\t * If no such distinction needs to be made, do not provide a 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): void {\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: ITelemetryPerformanceEventExt = {\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\tfor (const [k] of this.measurementsMap.entries()) {\n\t\t\tthis.flushBucket(k);\n\t\t}\n\t\tthis._disposed = true;\n\t}\n}\n"]}
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { ITelemetryBaseLogger, LogLevel, Tagged } from "@fluidframework/core-interfaces";
5
+ import type { ITelemetryBaseLogger, LogLevel, Tagged } from "@fluidframework/core-interfaces";
6
6
  /**
7
7
  * The categories FF uses when instrumenting the code.
8
8
  *
@@ -22,10 +22,7 @@ export type TelemetryEventCategory = "generic" | "error" | "performance";
22
22
  * converted before sending to a base logger.
23
23
  * @alpha
24
24
  */
25
- export type TelemetryEventPropertyTypeExt = string | number | boolean | undefined | (string | number | boolean)[] | {
26
- [key: string]: // Flat objects can have the same properties as the event itself
27
- string | number | boolean | undefined | (string | number | boolean)[];
28
- };
25
+ export type TelemetryEventPropertyTypeExt = string | number | boolean | undefined | (string | number | boolean)[] | Record<string, string | number | boolean | undefined | (string | number | boolean)[]>;
29
26
  /**
30
27
  * A property to be logged to telemetry containing both the value and a tag. Tags are generic strings that can be used
31
28
  * to mark pieces of information that should be organized or handled differently by loggers in various first or third
@@ -42,9 +39,7 @@ export interface ITaggedTelemetryPropertyTypeExt {
42
39
  * JSON-serializable properties, which will be logged with telemetry.
43
40
  * @alpha
44
41
  */
45
- export interface ITelemetryPropertiesExt {
46
- [index: string]: TelemetryEventPropertyTypeExt | Tagged<TelemetryEventPropertyTypeExt>;
47
- }
42
+ export type ITelemetryPropertiesExt = Record<string, TelemetryEventPropertyTypeExt | Tagged<TelemetryEventPropertyTypeExt>>;
48
43
  /**
49
44
  * Interface for logging telemetry statements.
50
45
  * @remarks May contain any number of properties that get serialized as json payload.
@@ -54,7 +49,13 @@ export interface ITelemetryPropertiesExt {
54
49
  * @internal
55
50
  */
56
51
  export interface ITelemetryEventExt extends ITelemetryPropertiesExt {
52
+ /**
53
+ * {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseEvent.category}
54
+ */
57
55
  category: string;
56
+ /**
57
+ * {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseEvent.eventName}
58
+ */
58
59
  eventName: string;
59
60
  }
60
61
  /**
@@ -63,7 +64,14 @@ export interface ITelemetryEventExt extends ITelemetryPropertiesExt {
63
64
  * @alpha
64
65
  */
65
66
  export interface ITelemetryGenericEventExt extends ITelemetryPropertiesExt {
67
+ /**
68
+ * {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseEvent.eventName}
69
+ */
66
70
  eventName: string;
71
+ /**
72
+ * Optional event {@link @fluidframework/core-interfaces#ITelemetryBaseEvent.category}.
73
+ * @defaultValue "generic"
74
+ */
67
75
  category?: TelemetryEventCategory;
68
76
  }
69
77
  /**
@@ -72,6 +80,9 @@ export interface ITelemetryGenericEventExt extends ITelemetryPropertiesExt {
72
80
  * @alpha
73
81
  */
74
82
  export interface ITelemetryErrorEventExt extends ITelemetryPropertiesExt {
83
+ /**
84
+ * {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseEvent.eventName}
85
+ */
75
86
  eventName: string;
76
87
  }
77
88
  /**
@@ -80,6 +91,9 @@ export interface ITelemetryErrorEventExt extends ITelemetryPropertiesExt {
80
91
  * @alpha
81
92
  */
82
93
  export interface ITelemetryPerformanceEventExt extends ITelemetryGenericEventExt {
94
+ /**
95
+ * Duration of event (optional)
96
+ */
83
97
  duration?: number;
84
98
  }
85
99
  /**
@@ -92,23 +106,23 @@ export interface ITelemetryPerformanceEventExt extends ITelemetryGenericEventExt
92
106
  */
93
107
  export interface ITelemetryLoggerExt extends ITelemetryBaseLogger {
94
108
  /**
95
- * Send information telemetry event
96
- * @param event - Event to send
97
- * @param error - optional error object to log
98
- * @param logLevel - optional level of the log.
109
+ * Send an information telemetry event.
110
+ * @param event - Event to send.
111
+ * @param error - Optional error object to log.
112
+ * @param logLevel - Optional level of the log. Default: {@link @fluidframework/core-interfaces#LogLevel.default}.
99
113
  */
100
114
  sendTelemetryEvent(event: ITelemetryGenericEventExt, error?: unknown, logLevel?: typeof LogLevel.verbose | typeof LogLevel.default): void;
101
115
  /**
102
- * Send error telemetry event
103
- * @param event - Event to send
104
- * @param error - optional error object to log
116
+ * Send an error telemetry event.
117
+ * @param event - Event to send.
118
+ * @param error - Optional error object to log.
105
119
  */
106
120
  sendErrorEvent(event: ITelemetryErrorEventExt, error?: unknown): void;
107
121
  /**
108
- * Send performance telemetry event
122
+ * Send a performance telemetry event.
109
123
  * @param event - Event to send
110
- * @param error - optional error object to log
111
- * @param logLevel - optional level of the log.
124
+ * @param error - Optional error object to log.
125
+ * @param logLevel - Optional level of the log. Default: {@link @fluidframework/core-interfaces#LogLevel.default}.
112
126
  */
113
127
  sendPerformanceEvent(event: ITelemetryPerformanceEventExt, error?: unknown, logLevel?: typeof LogLevel.verbose | typeof LogLevel.default): void;
114
128
  }
@@ -1 +1 @@
1
- {"version":3,"file":"telemetryTypes.d.ts","sourceRoot":"","sources":["../src/telemetryTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAEzF;;;;;;;;;GASG;AACH,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,CAAC;AAEzE;;;;;;;GAOG;AACH,MAAM,MAAM,6BAA6B,GACtC,MAAM,GACN,MAAM,GACN,OAAO,GACP,SAAS,GACT,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAAE,GAC7B;IACA,CAAC,GAAG,EAAE,MAAM,GACZ,AADe,gEAAgE;IAC/E,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;CACrE,CAAC;AAEL;;;;;;;GAOG;AACH,MAAM,WAAW,+BAA+B;IAC/C,KAAK,EAAE,6BAA6B,CAAC;IACrC,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACvC,CAAC,KAAK,EAAE,MAAM,GAAG,6BAA6B,GAAG,MAAM,CAAC,6BAA6B,CAAC,CAAC;CACvF;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAmB,SAAQ,uBAAuB;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAA0B,SAAQ,uBAAuB;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,sBAAsB,CAAC;CAClC;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAwB,SAAQ,uBAAuB;IACvE,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,6BAA8B,SAAQ,yBAAyB;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAoB,SAAQ,oBAAoB;IAChE;;;;;OAKG;IACH,kBAAkB,CACjB,KAAK,EAAE,yBAAyB,EAChC,KAAK,CAAC,EAAE,OAAO,EACf,QAAQ,CAAC,EAAE,OAAO,QAAQ,CAAC,OAAO,GAAG,OAAO,QAAQ,CAAC,OAAO,GAC1D,IAAI,CAAC;IAER;;;;OAIG;IACH,cAAc,CAAC,KAAK,EAAE,uBAAuB,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAEtE;;;;;OAKG;IACH,oBAAoB,CACnB,KAAK,EAAE,6BAA6B,EACpC,KAAK,CAAC,EAAE,OAAO,EACf,QAAQ,CAAC,EAAE,OAAO,QAAQ,CAAC,OAAO,GAAG,OAAO,QAAQ,CAAC,OAAO,GAC1D,IAAI,CAAC;CACR"}
1
+ {"version":3,"file":"telemetryTypes.d.ts","sourceRoot":"","sources":["../src/telemetryTypes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAE9F;;;;;;;;;GASG;AACH,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG,OAAO,GAAG,aAAa,CAAC;AAEzE;;;;;;;GAOG;AACH,MAAM,MAAM,6BAA6B,GACtC,MAAM,GACN,MAAM,GACN,OAAO,GACP,SAAS,GACT,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAAE,GAC7B,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;AAEzF;;;;;;;GAOG;AACH,MAAM,WAAW,+BAA+B;IAC/C,KAAK,EAAE,6BAA6B,CAAC;IACrC,GAAG,EAAE,MAAM,CAAC;CACZ;AAED;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAC3C,MAAM,EACN,6BAA6B,GAAG,MAAM,CAAC,6BAA6B,CAAC,CACrE,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAmB,SAAQ,uBAAuB;IAClE;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAA0B,SAAQ,uBAAuB;IACzE;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,QAAQ,CAAC,EAAE,sBAAsB,CAAC;CAClC;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAwB,SAAQ,uBAAuB;IACvE;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,6BAA8B,SAAQ,yBAAyB;IAC/E;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAoB,SAAQ,oBAAoB;IAChE;;;;;OAKG;IACH,kBAAkB,CACjB,KAAK,EAAE,yBAAyB,EAChC,KAAK,CAAC,EAAE,OAAO,EACf,QAAQ,CAAC,EAAE,OAAO,QAAQ,CAAC,OAAO,GAAG,OAAO,QAAQ,CAAC,OAAO,GAC1D,IAAI,CAAC;IAER;;;;OAIG;IACH,cAAc,CAAC,KAAK,EAAE,uBAAuB,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAEtE;;;;;OAKG;IACH,oBAAoB,CACnB,KAAK,EAAE,6BAA6B,EACpC,KAAK,CAAC,EAAE,OAAO,EACf,QAAQ,CAAC,EAAE,OAAO,QAAQ,CAAC,OAAO,GAAG,OAAO,QAAQ,CAAC,OAAO,GAC1D,IAAI,CAAC;CACR"}
@@ -1 +1 @@
1
- {"version":3,"file":"telemetryTypes.js","sourceRoot":"","sources":["../src/telemetryTypes.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryBaseLogger, LogLevel, Tagged } from \"@fluidframework/core-interfaces\";\n\n/**\n * The categories FF uses when instrumenting the code.\n *\n * generic - Informational log event\n *\n * error - Error log event, ideally 0 of these are logged during a session\n *\n * performance - Includes duration, and often has _start, _end, or _cancel suffixes for activity tracking\n * @alpha\n */\nexport type TelemetryEventCategory = \"generic\" | \"error\" | \"performance\";\n\n/**\n * Property types that can be logged.\n *\n * @remarks\n * Includes extra types beyond {@link @fluidframework/core-interfaces#TelemetryBaseEventPropertyType}, which must be\n * converted before sending to a base logger.\n * @alpha\n */\nexport type TelemetryEventPropertyTypeExt =\n\t| string\n\t| number\n\t| boolean\n\t| undefined\n\t| (string | number | boolean)[]\n\t| {\n\t\t\t[key: string]: // Flat objects can have the same properties as the event itself\n\t\t\tstring | number | boolean | undefined | (string | number | boolean)[];\n\t };\n\n/**\n * A property to be logged to telemetry containing both the value and a tag. Tags are generic strings that can be used\n * to mark pieces of information that should be organized or handled differently by loggers in various first or third\n * party scenarios. For example, tags are used to mark personal information that should not be stored in logs.\n *\n * @deprecated Use {@link @fluidframework/core-interfaces#Tagged}\\<{@link TelemetryEventPropertyTypeExt}\\>\n * @internal\n */\nexport interface ITaggedTelemetryPropertyTypeExt {\n\tvalue: TelemetryEventPropertyTypeExt;\n\ttag: string;\n}\n\n/**\n * JSON-serializable properties, which will be logged with telemetry.\n * @alpha\n */\nexport interface ITelemetryPropertiesExt {\n\t[index: string]: TelemetryEventPropertyTypeExt | Tagged<TelemetryEventPropertyTypeExt>;\n}\n\n/**\n * Interface for logging telemetry statements.\n * @remarks May contain any number of properties that get serialized as json payload.\n * @param category - category of the event, like \"error\", \"performance\", \"generic\", etc.\n * @param eventName - name of the event.\n *\n * @internal\n */\nexport interface ITelemetryEventExt extends ITelemetryPropertiesExt {\n\tcategory: string;\n\teventName: string;\n}\n\n/**\n * Informational (non-error) telemetry event\n * @remarks Maps to category = \"generic\"\n * @alpha\n */\nexport interface ITelemetryGenericEventExt extends ITelemetryPropertiesExt {\n\teventName: string;\n\tcategory?: TelemetryEventCategory;\n}\n\n/**\n * Error telemetry event.\n * @remarks Maps to category = \"error\"\n * @alpha\n */\nexport interface ITelemetryErrorEventExt extends ITelemetryPropertiesExt {\n\teventName: string;\n}\n\n/**\n * Performance telemetry event.\n * @remarks Maps to category = \"performance\"\n * @alpha\n */\nexport interface ITelemetryPerformanceEventExt extends ITelemetryGenericEventExt {\n\tduration?: number; // Duration of event (optional)\n}\n\n/**\n * An extended {@link @fluidframework/core-interfaces#ITelemetryBaseLogger} which allows for more lenient event types.\n *\n * @remarks\n * This interface is meant to be used internally within the Fluid Framework,\n * and `ITelemetryBaseLogger` should be used when loggers are passed between layers.\n * @alpha\n */\nexport interface ITelemetryLoggerExt extends ITelemetryBaseLogger {\n\t/**\n\t * Send information telemetry event\n\t * @param event - Event to send\n\t * @param error - optional error object to log\n\t * @param logLevel - optional level of the log.\n\t */\n\tsendTelemetryEvent(\n\t\tevent: ITelemetryGenericEventExt,\n\t\terror?: unknown,\n\t\tlogLevel?: typeof LogLevel.verbose | typeof LogLevel.default,\n\t): void;\n\n\t/**\n\t * Send error telemetry event\n\t * @param event - Event to send\n\t * @param error - optional error object to log\n\t */\n\tsendErrorEvent(event: ITelemetryErrorEventExt, error?: unknown): void;\n\n\t/**\n\t * Send performance telemetry event\n\t * @param event - Event to send\n\t * @param error - optional error object to log\n\t * @param logLevel - optional level of the log.\n\t */\n\tsendPerformanceEvent(\n\t\tevent: ITelemetryPerformanceEventExt,\n\t\terror?: unknown,\n\t\tlogLevel?: typeof LogLevel.verbose | typeof LogLevel.default,\n\t): void;\n}\n"]}
1
+ {"version":3,"file":"telemetryTypes.js","sourceRoot":"","sources":["../src/telemetryTypes.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ITelemetryBaseLogger, LogLevel, Tagged } from \"@fluidframework/core-interfaces\";\n\n/**\n * The categories FF uses when instrumenting the code.\n *\n * generic - Informational log event\n *\n * error - Error log event, ideally 0 of these are logged during a session\n *\n * performance - Includes duration, and often has _start, _end, or _cancel suffixes for activity tracking\n * @alpha\n */\nexport type TelemetryEventCategory = \"generic\" | \"error\" | \"performance\";\n\n/**\n * Property types that can be logged.\n *\n * @remarks\n * Includes extra types beyond {@link @fluidframework/core-interfaces#TelemetryBaseEventPropertyType}, which must be\n * converted before sending to a base logger.\n * @alpha\n */\nexport type TelemetryEventPropertyTypeExt =\n\t| string\n\t| number\n\t| boolean\n\t| undefined\n\t| (string | number | boolean)[]\n\t| Record<string, string | number | boolean | undefined | (string | number | boolean)[]>;\n\n/**\n * A property to be logged to telemetry containing both the value and a tag. Tags are generic strings that can be used\n * to mark pieces of information that should be organized or handled differently by loggers in various first or third\n * party scenarios. For example, tags are used to mark personal information that should not be stored in logs.\n *\n * @deprecated Use {@link @fluidframework/core-interfaces#Tagged}\\<{@link TelemetryEventPropertyTypeExt}\\>\n * @internal\n */\nexport interface ITaggedTelemetryPropertyTypeExt {\n\tvalue: TelemetryEventPropertyTypeExt;\n\ttag: string;\n}\n\n/**\n * JSON-serializable properties, which will be logged with telemetry.\n * @alpha\n */\nexport type ITelemetryPropertiesExt = Record<\n\tstring,\n\tTelemetryEventPropertyTypeExt | Tagged<TelemetryEventPropertyTypeExt>\n>;\n\n/**\n * Interface for logging telemetry statements.\n * @remarks May contain any number of properties that get serialized as json payload.\n * @param category - category of the event, like \"error\", \"performance\", \"generic\", etc.\n * @param eventName - name of the event.\n *\n * @internal\n */\nexport interface ITelemetryEventExt extends ITelemetryPropertiesExt {\n\t/**\n\t * {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseEvent.category}\n\t */\n\tcategory: string;\n\n\t/**\n\t * {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseEvent.eventName}\n\t */\n\teventName: string;\n}\n\n/**\n * Informational (non-error) telemetry event\n * @remarks Maps to category = \"generic\"\n * @alpha\n */\nexport interface ITelemetryGenericEventExt extends ITelemetryPropertiesExt {\n\t/**\n\t * {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseEvent.eventName}\n\t */\n\teventName: string;\n\n\t/**\n\t * Optional event {@link @fluidframework/core-interfaces#ITelemetryBaseEvent.category}.\n\t * @defaultValue \"generic\"\n\t */\n\tcategory?: TelemetryEventCategory;\n}\n\n/**\n * Error telemetry event.\n * @remarks Maps to category = \"error\"\n * @alpha\n */\nexport interface ITelemetryErrorEventExt extends ITelemetryPropertiesExt {\n\t/**\n\t * {@inheritDoc @fluidframework/core-interfaces#ITelemetryBaseEvent.eventName}\n\t */\n\teventName: string;\n}\n\n/**\n * Performance telemetry event.\n * @remarks Maps to category = \"performance\"\n * @alpha\n */\nexport interface ITelemetryPerformanceEventExt extends ITelemetryGenericEventExt {\n\t/**\n\t * Duration of event (optional)\n\t */\n\tduration?: number;\n}\n\n/**\n * An extended {@link @fluidframework/core-interfaces#ITelemetryBaseLogger} which allows for more lenient event types.\n *\n * @remarks\n * This interface is meant to be used internally within the Fluid Framework,\n * and `ITelemetryBaseLogger` should be used when loggers are passed between layers.\n * @alpha\n */\nexport interface ITelemetryLoggerExt extends ITelemetryBaseLogger {\n\t/**\n\t * Send an information telemetry event.\n\t * @param event - Event to send.\n\t * @param error - Optional error object to log.\n\t * @param logLevel - Optional level of the log. Default: {@link @fluidframework/core-interfaces#LogLevel.default}.\n\t */\n\tsendTelemetryEvent(\n\t\tevent: ITelemetryGenericEventExt,\n\t\terror?: unknown,\n\t\tlogLevel?: typeof LogLevel.verbose | typeof LogLevel.default,\n\t): void;\n\n\t/**\n\t * Send an error telemetry event.\n\t * @param event - Event to send.\n\t * @param error - Optional error object to log.\n\t */\n\tsendErrorEvent(event: ITelemetryErrorEventExt, error?: unknown): void;\n\n\t/**\n\t * Send a performance telemetry event.\n\t * @param event - Event to send\n\t * @param error - Optional error object to log.\n\t * @param logLevel - Optional level of the log. Default: {@link @fluidframework/core-interfaces#LogLevel.default}.\n\t */\n\tsendPerformanceEvent(\n\t\tevent: ITelemetryPerformanceEventExt,\n\t\terror?: unknown,\n\t\tlogLevel?: typeof LogLevel.verbose | typeof LogLevel.default,\n\t): void;\n}\n"]}
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { ITelemetryLoggerExt } from "./telemetryTypes.js";
5
+ import type { ITelemetryLoggerExt } from "./telemetryTypes.js";
6
6
  /**
7
7
  * Utility counter which will send event only if the provided value is above a configured threshold.
8
8
  *
@@ -1 +1 @@
1
- {"version":3,"file":"thresholdCounter.d.ts","sourceRoot":"","sources":["../src/thresholdCounter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;GAIG;AACH,qBAAa,gBAAgB;IAE3B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,iBAAiB;gBAFR,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,mBAAmB,EACpC,iBAAiB,SAAY;IAGtC;;OAEG;IACI,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAUnD;;;;;;OAMG;IACI,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;CAU7D"}
1
+ {"version":3,"file":"thresholdCounter.d.ts","sourceRoot":"","sources":["../src/thresholdCounter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D;;;;GAIG;AACH,qBAAa,gBAAgB;IAE3B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,iBAAiB;gBAFR,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,mBAAmB,EACpC,iBAAiB,SAAY;IAGtC;;OAEG;IACI,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAUnD;;;;;;OAMG;IACI,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;CAU7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"thresholdCounter.js","sourceRoot":"","sources":["../src/thresholdCounter.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAIH;;;;GAIG;AACH,MAAa,gBAAgB;IAC5B,YACkB,SAAiB,EACjB,MAA2B,EACpC,oBAAoB,SAAS;QAFpB,cAAS,GAAT,SAAS,CAAQ;QACjB,WAAM,GAAN,MAAM,CAAqB;QACpC,sBAAiB,GAAjB,iBAAiB,CAAY;IACnC,CAAC;IAEJ;;OAEG;IACI,IAAI,CAAC,SAAiB,EAAE,KAAa;QAC3C,IAAI,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;YAC5B,OAAO;QACR,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;YAChC,SAAS;YACT,KAAK;SACL,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACI,cAAc,CAAC,SAAiB,EAAE,KAAa;QACrD,IAAI,KAAK,KAAK,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACtC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;gBAChC,SAAS;gBACT,KAAK;aACL,CAAC,CAAC;YACH,sCAAsC;YACtC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;QACrD,CAAC;IACF,CAAC;CACD;AArCD,4CAqCC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { ITelemetryLoggerExt } from \"./telemetryTypes.js\";\n\n/**\n * Utility counter which will send event only if the provided value is above a configured threshold.\n *\n * @internal\n */\nexport class ThresholdCounter {\n\tpublic constructor(\n\t\tprivate readonly threshold: number,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate thresholdMultiple = threshold,\n\t) {}\n\n\t/**\n\t * Sends the value if it's above the treshold.\n\t */\n\tpublic send(eventName: string, value: number): void {\n\t\tif (value < this.threshold) {\n\t\t\treturn;\n\t\t}\n\t\tthis.logger.sendPerformanceEvent({\n\t\t\teventName,\n\t\t\tvalue,\n\t\t});\n\t}\n\n\t/**\n\t * Sends the value if it's above the threshold\n\t * and a multiple of the threshold.\n\t *\n\t * To be used in scenarios where we'd like to record a\n\t * threshold violation while reducing telemetry noise.\n\t */\n\tpublic sendIfMultiple(eventName: string, value: number): void {\n\t\tif (value === this.thresholdMultiple) {\n\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\teventName,\n\t\t\t\tvalue,\n\t\t\t});\n\t\t\t// reduce number of \"multiple\" events.\n\t\t\tthis.thresholdMultiple = this.thresholdMultiple * 2;\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"thresholdCounter.js","sourceRoot":"","sources":["../src/thresholdCounter.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAIH;;;;GAIG;AACH,MAAa,gBAAgB;IAC5B,YACkB,SAAiB,EACjB,MAA2B,EACpC,oBAAoB,SAAS;QAFpB,cAAS,GAAT,SAAS,CAAQ;QACjB,WAAM,GAAN,MAAM,CAAqB;QACpC,sBAAiB,GAAjB,iBAAiB,CAAY;IACnC,CAAC;IAEJ;;OAEG;IACI,IAAI,CAAC,SAAiB,EAAE,KAAa;QAC3C,IAAI,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;YAC5B,OAAO;QACR,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;YAChC,SAAS;YACT,KAAK;SACL,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACI,cAAc,CAAC,SAAiB,EAAE,KAAa;QACrD,IAAI,KAAK,KAAK,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACtC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC;gBAChC,SAAS;gBACT,KAAK;aACL,CAAC,CAAC;YACH,sCAAsC;YACtC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;QACrD,CAAC;IACF,CAAC;CACD;AArCD,4CAqCC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ITelemetryLoggerExt } from \"./telemetryTypes.js\";\n\n/**\n * Utility counter which will send event only if the provided value is above a configured threshold.\n *\n * @internal\n */\nexport class ThresholdCounter {\n\tpublic constructor(\n\t\tprivate readonly threshold: number,\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\t\tprivate thresholdMultiple = threshold,\n\t) {}\n\n\t/**\n\t * Sends the value if it's above the treshold.\n\t */\n\tpublic send(eventName: string, value: number): void {\n\t\tif (value < this.threshold) {\n\t\t\treturn;\n\t\t}\n\t\tthis.logger.sendPerformanceEvent({\n\t\t\teventName,\n\t\t\tvalue,\n\t\t});\n\t}\n\n\t/**\n\t * Sends the value if it's above the threshold\n\t * and a multiple of the threshold.\n\t *\n\t * To be used in scenarios where we'd like to record a\n\t * threshold violation while reducing telemetry noise.\n\t */\n\tpublic sendIfMultiple(eventName: string, value: number): void {\n\t\tif (value === this.thresholdMultiple) {\n\t\t\tthis.logger.sendPerformanceEvent({\n\t\t\t\teventName,\n\t\t\t\tvalue,\n\t\t\t});\n\t\t\t// reduce number of \"multiple\" events.\n\t\t\tthis.thresholdMultiple = this.thresholdMultiple * 2;\n\t\t}\n\t}\n}\n"]}
package/dist/utils.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { ITelemetryLoggerExt } from "./telemetryTypes.js";
5
+ import type { ITelemetryLoggerExt } from "./telemetryTypes.js";
6
6
  /**
7
7
  * An object that contains a callback used in conjunction with the {@link createSampledLogger} utility function to provide custom logic for sampling events.
8
8
  *
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAA6B,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAErF;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC7B;;OAEG;IACH,MAAM,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;CAClC;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IACnE;;;;;;;OAOG;IACH,kBAAkB,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAClC,MAAM,EAAE,mBAAmB,EAC3B,YAAY,CAAC,EAAE,aAAa,EAC5B,iCAAiC,CAAC,EAAE,OAAO,GACzC,uBAAuB,CA8CzB"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAA6B,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1F;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC7B;;OAEG;IACH,MAAM,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;CAClC;AAED;;;;GAIG;AACH,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IACnE;;;;;;;OAOG;IACH,kBAAkB,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAClC,MAAM,EAAE,mBAAmB,EAC3B,YAAY,CAAC,EAAE,aAAa,EAC5B,iCAAiC,CAAC,EAAE,OAAO,GACzC,uBAAuB,CA8CzB"}
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAIH,2CAAwD;AAgCxD;;;;;;;;;;;;;;;GAeG;AACH,SAAgB,mBAAmB,CAClC,MAA2B,EAC3B,YAA4B,EAC5B,iCAA2C;IAE3C,MAAM,iBAAiB,GAAG,IAAA,qCAAyB,EAAC,MAAM,CAAC,CAAC;IAC5D,MAAM,kBAAkB,GACvB,iBAAiB,CAAC,MAAM,CAAC,UAAU,CAAC,iCAAiC,CAAC,IAAI,KAAK,CAAC;IAEjF,MAAM,aAAa,GAAG;QACrB,IAAI,EAAE,CAAC,KAA0B,EAAQ,EAAE;YAC1C,2DAA2D;YAC3D,gIAAgI;YAChI,2LAA2L;YAC3L,0EAA0E;YAC1E,IAAI,kBAAkB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC/E,IAAI,kBAAkB,IAAI,iCAAiC,EAAE,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpB,CAAC;QACF,CAAC;QACD,kBAAkB,EAAE,CAAC,KAAgC,EAAQ,EAAE;YAC9D,IAAI,kBAAkB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC/E,IAAI,kBAAkB,IAAI,iCAAiC,EAAE,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAClC,CAAC;QACF,CAAC;QACD,cAAc,EAAE,CAAC,KAAgC,EAAQ,EAAE;YAC1D,IAAI,kBAAkB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC/E,IAAI,kBAAkB,IAAI,iCAAiC,EAAE,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC;QACF,CAAC;QACD,oBAAoB,EAAE,CAAC,KAAgC,EAAQ,EAAE;YAChE,IAAI,kBAAkB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC/E,IAAI,kBAAkB,IAAI,iCAAiC,EAAE,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;QACF,CAAC;QACD,kBAAkB;KAClB,CAAC;IAEF,OAAO,aAAa,CAAC;AACtB,CAAC;AAlDD,kDAkDC","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\";\n\nimport { loggerToMonitoringContext } from \"./config.js\";\nimport { ITelemetryGenericEventExt, ITelemetryLoggerExt } from \"./telemetryTypes.js\";\n\n/**\n * An object that contains a callback used in conjunction with the {@link createSampledLogger} utility function to provide custom logic for sampling events.\n *\n * @internal\n */\nexport interface IEventSampler {\n\t/**\n\t * @returns true if the event should be sampled or false if not\n\t */\n\tsample: () => boolean | undefined;\n}\n\n/**\n * A telemetry logger that has sampling capabilities\n *\n * @internal\n */\nexport interface ISampledTelemetryLogger extends ITelemetryLoggerExt {\n\t/**\n\t * Indicates if the feature flag to disable sampling is set.\n\t *\n\t * @remarks Exposed to enable some advanced scenarios where the code using the sampled logger\n\t * could take advantage of skipping the execution of some logic when it can determine\n\t * it won't be necessary because the telemetry event that needs it wouldn't be\n\t * emitted anyway.\n\t */\n\tisSamplingDisabled: boolean;\n}\n\n/**\n * Wraps around an existing logger matching the {@link ITelemetryLoggerExt} interface and provides the ability to only log a subset of events using a sampling strategy provided by an ${@link IEventSampler}.\n * You can chose to not provide an event sampler which is effectively a no-op, meaning that it will be treated as if the sampler always returns true.\n *\n * @remarks\n * The sampling functionality uses the Fluid telemetry logging configuration along with the optionally provided event sampling callback to determine whether an event should\n * be logged or not.\n *\n * Configuration object parameters:\n * 'Fluid.Telemetry.DisableSampling': if this config value is set to true, all events will be unsampled and therefore logged.\n * Otherwise only a sample will be logged according to the provided event sampler callback.\n *\n * Note that the same sampler is used for all APIs of the returned logger. If you want separate events flowing through the returned logger to be sampled separately, the {@link IEventSampler} you provide should track them separately.\n *\n * @internal\n */\nexport function createSampledLogger(\n\tlogger: ITelemetryLoggerExt,\n\teventSampler?: IEventSampler,\n\tskipLoggingWhenSamplingIsDisabled?: boolean,\n): ISampledTelemetryLogger {\n\tconst monitoringContext = loggerToMonitoringContext(logger);\n\tconst isSamplingDisabled =\n\t\tmonitoringContext.config.getBoolean(\"Fluid.Telemetry.DisableSampling\") ?? false;\n\n\tconst sampledLogger = {\n\t\tsend: (event: ITelemetryBaseEvent): void => {\n\t\t\t// The sampler uses the following logic for sending events:\n\t\t\t// 1. If isSamplingDisabled is true, then this means events should be unsampled. Therefore we send the event without any checks.\n\t\t\t// 2. If isSamplingDisabled is false, then event should be sampled using the event sampler, if the sampler is not defined just send all events, other use the eventSampler.sample() method.\n\t\t\t// 3. If skipLoggingWhenSamplingIsDisabled is true, then no event is sent.\n\t\t\tif (isSamplingDisabled || eventSampler === undefined || eventSampler.sample()) {\n\t\t\t\tif (isSamplingDisabled && skipLoggingWhenSamplingIsDisabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlogger.send(event);\n\t\t\t}\n\t\t},\n\t\tsendTelemetryEvent: (event: ITelemetryGenericEventExt): void => {\n\t\t\tif (isSamplingDisabled || eventSampler === undefined || eventSampler.sample()) {\n\t\t\t\tif (isSamplingDisabled && skipLoggingWhenSamplingIsDisabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlogger.sendTelemetryEvent(event);\n\t\t\t}\n\t\t},\n\t\tsendErrorEvent: (event: ITelemetryGenericEventExt): void => {\n\t\t\tif (isSamplingDisabled || eventSampler === undefined || eventSampler.sample()) {\n\t\t\t\tif (isSamplingDisabled && skipLoggingWhenSamplingIsDisabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlogger.sendErrorEvent(event);\n\t\t\t}\n\t\t},\n\t\tsendPerformanceEvent: (event: ITelemetryGenericEventExt): void => {\n\t\t\tif (isSamplingDisabled || eventSampler === undefined || eventSampler.sample()) {\n\t\t\t\tif (isSamplingDisabled && skipLoggingWhenSamplingIsDisabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlogger.sendPerformanceEvent(event);\n\t\t\t}\n\t\t},\n\t\tisSamplingDisabled,\n\t};\n\n\treturn sampledLogger;\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAIH,2CAAwD;AAgCxD;;;;;;;;;;;;;;;GAeG;AACH,SAAgB,mBAAmB,CAClC,MAA2B,EAC3B,YAA4B,EAC5B,iCAA2C;IAE3C,MAAM,iBAAiB,GAAG,IAAA,qCAAyB,EAAC,MAAM,CAAC,CAAC;IAC5D,MAAM,kBAAkB,GACvB,iBAAiB,CAAC,MAAM,CAAC,UAAU,CAAC,iCAAiC,CAAC,IAAI,KAAK,CAAC;IAEjF,MAAM,aAAa,GAAG;QACrB,IAAI,EAAE,CAAC,KAA0B,EAAQ,EAAE;YAC1C,2DAA2D;YAC3D,gIAAgI;YAChI,2LAA2L;YAC3L,0EAA0E;YAC1E,IAAI,kBAAkB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC/E,IAAI,kBAAkB,IAAI,iCAAiC,EAAE,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpB,CAAC;QACF,CAAC;QACD,kBAAkB,EAAE,CAAC,KAAgC,EAAQ,EAAE;YAC9D,IAAI,kBAAkB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC/E,IAAI,kBAAkB,IAAI,iCAAiC,EAAE,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAClC,CAAC;QACF,CAAC;QACD,cAAc,EAAE,CAAC,KAAgC,EAAQ,EAAE;YAC1D,IAAI,kBAAkB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC/E,IAAI,kBAAkB,IAAI,iCAAiC,EAAE,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC;QACF,CAAC;QACD,oBAAoB,EAAE,CAAC,KAAgC,EAAQ,EAAE;YAChE,IAAI,kBAAkB,IAAI,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC/E,IAAI,kBAAkB,IAAI,iCAAiC,EAAE,CAAC;oBAC7D,OAAO;gBACR,CAAC;gBACD,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;QACF,CAAC;QACD,kBAAkB;KAClB,CAAC;IAEF,OAAO,aAAa,CAAC;AACtB,CAAC;AAlDD,kDAkDC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { ITelemetryBaseEvent } from \"@fluidframework/core-interfaces\";\n\nimport { loggerToMonitoringContext } from \"./config.js\";\nimport type { ITelemetryGenericEventExt, ITelemetryLoggerExt } from \"./telemetryTypes.js\";\n\n/**\n * An object that contains a callback used in conjunction with the {@link createSampledLogger} utility function to provide custom logic for sampling events.\n *\n * @internal\n */\nexport interface IEventSampler {\n\t/**\n\t * @returns true if the event should be sampled or false if not\n\t */\n\tsample: () => boolean | undefined;\n}\n\n/**\n * A telemetry logger that has sampling capabilities\n *\n * @internal\n */\nexport interface ISampledTelemetryLogger extends ITelemetryLoggerExt {\n\t/**\n\t * Indicates if the feature flag to disable sampling is set.\n\t *\n\t * @remarks Exposed to enable some advanced scenarios where the code using the sampled logger\n\t * could take advantage of skipping the execution of some logic when it can determine\n\t * it won't be necessary because the telemetry event that needs it wouldn't be\n\t * emitted anyway.\n\t */\n\tisSamplingDisabled: boolean;\n}\n\n/**\n * Wraps around an existing logger matching the {@link ITelemetryLoggerExt} interface and provides the ability to only log a subset of events using a sampling strategy provided by an ${@link IEventSampler}.\n * You can chose to not provide an event sampler which is effectively a no-op, meaning that it will be treated as if the sampler always returns true.\n *\n * @remarks\n * The sampling functionality uses the Fluid telemetry logging configuration along with the optionally provided event sampling callback to determine whether an event should\n * be logged or not.\n *\n * Configuration object parameters:\n * 'Fluid.Telemetry.DisableSampling': if this config value is set to true, all events will be unsampled and therefore logged.\n * Otherwise only a sample will be logged according to the provided event sampler callback.\n *\n * Note that the same sampler is used for all APIs of the returned logger. If you want separate events flowing through the returned logger to be sampled separately, the {@link IEventSampler} you provide should track them separately.\n *\n * @internal\n */\nexport function createSampledLogger(\n\tlogger: ITelemetryLoggerExt,\n\teventSampler?: IEventSampler,\n\tskipLoggingWhenSamplingIsDisabled?: boolean,\n): ISampledTelemetryLogger {\n\tconst monitoringContext = loggerToMonitoringContext(logger);\n\tconst isSamplingDisabled =\n\t\tmonitoringContext.config.getBoolean(\"Fluid.Telemetry.DisableSampling\") ?? false;\n\n\tconst sampledLogger = {\n\t\tsend: (event: ITelemetryBaseEvent): void => {\n\t\t\t// The sampler uses the following logic for sending events:\n\t\t\t// 1. If isSamplingDisabled is true, then this means events should be unsampled. Therefore we send the event without any checks.\n\t\t\t// 2. If isSamplingDisabled is false, then event should be sampled using the event sampler, if the sampler is not defined just send all events, other use the eventSampler.sample() method.\n\t\t\t// 3. If skipLoggingWhenSamplingIsDisabled is true, then no event is sent.\n\t\t\tif (isSamplingDisabled || eventSampler === undefined || eventSampler.sample()) {\n\t\t\t\tif (isSamplingDisabled && skipLoggingWhenSamplingIsDisabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlogger.send(event);\n\t\t\t}\n\t\t},\n\t\tsendTelemetryEvent: (event: ITelemetryGenericEventExt): void => {\n\t\t\tif (isSamplingDisabled || eventSampler === undefined || eventSampler.sample()) {\n\t\t\t\tif (isSamplingDisabled && skipLoggingWhenSamplingIsDisabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlogger.sendTelemetryEvent(event);\n\t\t\t}\n\t\t},\n\t\tsendErrorEvent: (event: ITelemetryGenericEventExt): void => {\n\t\t\tif (isSamplingDisabled || eventSampler === undefined || eventSampler.sample()) {\n\t\t\t\tif (isSamplingDisabled && skipLoggingWhenSamplingIsDisabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlogger.sendErrorEvent(event);\n\t\t\t}\n\t\t},\n\t\tsendPerformanceEvent: (event: ITelemetryGenericEventExt): void => {\n\t\t\tif (isSamplingDisabled || eventSampler === undefined || eventSampler.sample()) {\n\t\t\t\tif (isSamplingDisabled && skipLoggingWhenSamplingIsDisabled) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlogger.sendPerformanceEvent(event);\n\t\t\t}\n\t\t},\n\t\tisSamplingDisabled,\n\t};\n\n\treturn sampledLogger;\n}\n"]}
package/lib/config.d.ts CHANGED
@@ -2,10 +2,10 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { ConfigTypes, IConfigProviderBase, ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
5
+ import type { ConfigTypes, IConfigProviderBase, ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
6
6
  import { Lazy } from "@fluidframework/core-utils/internal";
7
7
  import { createChildLogger } from "./logger.js";
8
- import { ITelemetryLoggerExt } from "./telemetryTypes.js";
8
+ import type { ITelemetryLoggerExt } from "./telemetryTypes.js";
9
9
  /**
10
10
  * Explicitly typed interface for reading configurations.
11
11
  *
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/lib/config.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.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\tConfigTypes,\n\tIConfigProviderBase,\n\tITelemetryBaseLogger,\n} from \"@fluidframework/core-interfaces\";\nimport { Lazy } from \"@fluidframework/core-utils/internal\";\n\nimport { createChildLogger, tagCodeArtifacts } from \"./logger.js\";\nimport { ITelemetryLoggerExt } from \"./telemetryTypes.js\";\n\n/**\n * Explicitly typed interface for reading configurations.\n *\n * @internal\n */\nexport interface IConfigProvider extends IConfigProviderBase {\n\tgetBoolean(name: string): boolean | undefined;\n\tgetNumber(name: string): number | undefined;\n\tgetString(name: string): string | undefined;\n\tgetBooleanArray(name: string): boolean[] | undefined;\n\tgetNumberArray(name: string): number[] | undefined;\n\tgetStringArray(name: string): string[] | undefined;\n}\n/**\n * Creates a base configuration provider based on `sessionStorage`\n *\n * @returns A lazy initialized base configuration provider with `sessionStorage` as the underlying config store\n *\n * @internal\n */\nexport const sessionStorageConfigProvider = new Lazy<IConfigProviderBase>(() =>\n\tinMemoryConfigProvider(safeSessionStorage()),\n);\n\nconst NullConfigProvider: IConfigProviderBase = {\n\tgetRawConfig: () => undefined,\n};\n\n/**\n * Creates a base configuration provider based on the supplied `Storage` instance\n *\n * @param storage - instance of `Storage` to be used as storage media for the config\n * @returns A base configuration provider with\n * the supplied `Storage` instance as the underlying config store\n */\nexport const inMemoryConfigProvider = (storage: Storage | undefined): IConfigProviderBase => {\n\tif (storage !== undefined && storage !== null) {\n\t\treturn new CachedConfigProvider(undefined, {\n\t\t\tgetRawConfig: (name: string): ConfigTypes | undefined => {\n\t\t\t\ttry {\n\t\t\t\t\treturn stronglyTypedParse(storage.getItem(name) ?? undefined)?.raw;\n\t\t\t\t} catch {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t}\n\treturn NullConfigProvider;\n};\n\ninterface ConfigTypeStringToType {\n\tnumber: number;\n\tstring: string;\n\tboolean: boolean;\n\t[\"number[]\"]: number[];\n\t[\"string[]\"]: string[];\n\t[\"boolean[]\"]: boolean[];\n}\n\ntype PrimitiveTypeStrings = \"number\" | \"string\" | \"boolean\";\n\nfunction isPrimitiveType(type: string): type is PrimitiveTypeStrings {\n\tswitch (type) {\n\t\tcase \"boolean\":\n\t\tcase \"number\":\n\t\tcase \"string\": {\n\t\t\treturn true;\n\t\t}\n\t\tdefault: {\n\t\t\treturn false;\n\t\t}\n\t}\n}\n\ninterface StronglyTypedValue extends Partial<ConfigTypeStringToType> {\n\traw: ConfigTypes;\n}\n/**\n * Takes any supported config type, and returns the value with a strong type. If the type of\n * the config is not a supported type undefined will be returned.\n * The user of this function should cache the result to avoid duplicated work.\n *\n * Strings will be attempted to be parsed and coerced into a strong config type.\n * if it is not possible to parsed and coerce a string to a strong config type the original string\n * will be return with a string type for the consumer to handle further if necessary.\n */\nfunction stronglyTypedParse(input: ConfigTypes): StronglyTypedValue | undefined {\n\tlet output: ConfigTypes = input;\n\tlet defaultReturn: Pick<StronglyTypedValue, \"raw\" | \"string\"> | undefined;\n\t// we do special handling for strings to try and coerce\n\t// them into a config type if we can. This makes it easy\n\t// for config sources like sessionStorage which only\n\t// holds strings\n\tif (typeof input === \"string\") {\n\t\ttry {\n\t\t\toutput = JSON.parse(input) as ConfigTypes;\n\t\t\t// we succeeded in parsing, but we don't support parsing\n\t\t\t// for any object as we can't do it type safely\n\t\t\t// so in this case, the default return will be string\n\t\t\t// rather than undefined, and the consumer\n\t\t\t// can parse, as we don't want to provide\n\t\t\t// a false sense of security by just\n\t\t\t// casting.\n\t\t\tdefaultReturn = { raw: input, string: input };\n\t\t} catch {\n\t\t\t// No-op\n\t\t}\n\t}\n\n\tif (output === undefined) {\n\t\treturn defaultReturn;\n\t}\n\n\tconst outputType = typeof output;\n\tif (isPrimitiveType(outputType)) {\n\t\treturn { ...defaultReturn, raw: input, [outputType]: output };\n\t}\n\n\tif (Array.isArray(output)) {\n\t\tconst firstType = typeof output[0];\n\t\t// ensure the first elements is a primitive type\n\t\tif (!isPrimitiveType(firstType)) {\n\t\t\treturn defaultReturn;\n\t\t}\n\t\t// ensue all the elements types are homogeneous\n\t\t// aka they all have the same type as the first\n\t\tfor (const v of output) {\n\t\t\tif (typeof v !== firstType) {\n\t\t\t\treturn defaultReturn;\n\t\t\t}\n\t\t}\n\t\treturn { ...defaultReturn, raw: input, [`${firstType}[]`]: output };\n\t}\n\n\treturn defaultReturn;\n}\n\n/**\n * `sessionStorage` is undefined in some environments such as Node and web pages with session storage disabled.\n */\nconst safeSessionStorage = (): Storage | undefined => {\n\t// For some configurations accessing \"globalThis.sessionStorage\" throws\n\t// \"'sessionStorage' property from 'Window': Access is denied for this document\" rather than returning undefined.\n\t// Therefor check for it before accessing.\n\ttry {\n\t\t// Using globalThis and checking for undefined is preferred over just accessing global sessionStorage\n\t\t// since it avoids an exception when running in node.\n\t\t// In some cases this has returned null when disabled in the browser, so ensure its undefined in that case:\n\t\treturn globalThis.sessionStorage ?? undefined;\n\t} catch {\n\t\t// For browsers which error on the above when session storage is disabled:\n\t\treturn undefined;\n\t}\n};\n\n/**\n * Creates a wrapper on top of an existing config provider which allows for\n * specifying feature gates if not present in the original provider.\n *\n * @param original - the original config provider\n * @param defaults - default feature gate configs to be used if not specified by the original provider\n * @returns A config provider that looks for any requested feature gates in the original provider and falls\n * back to the values specified in the `defaults` feature gates if they're not present in the original.\n *\n * @internal\n */\nexport const wrapConfigProviderWithDefaults = (\n\toriginal: IConfigProviderBase | undefined,\n\tdefaults: Record<string, ConfigTypes>,\n): IConfigProviderBase => ({\n\tgetRawConfig: (name: string): ConfigTypes => original?.getRawConfig(name) ?? defaults[name],\n});\n\n/**\n * Implementation of {@link IConfigProvider} which contains nested {@link IConfigProviderBase} instances\n */\nexport class CachedConfigProvider implements IConfigProvider {\n\tprivate readonly configCache = new Map<string, StronglyTypedValue>();\n\tprivate readonly orderedBaseProviders: (IConfigProviderBase | undefined)[];\n\n\tconstructor(\n\t\tprivate readonly logger?: ITelemetryBaseLogger,\n\t\t...orderedBaseProviders: (IConfigProviderBase | undefined)[]\n\t) {\n\t\tthis.orderedBaseProviders = [];\n\t\tconst knownProviders = new Set<IConfigProviderBase>();\n\t\tconst candidateProviders = [...orderedBaseProviders];\n\t\twhile (candidateProviders.length > 0) {\n\t\t\tconst baseProvider = candidateProviders.shift()!;\n\t\t\tif (\n\t\t\t\tbaseProvider !== undefined &&\n\t\t\t\tisConfigProviderBase(baseProvider) &&\n\t\t\t\t!knownProviders.has(baseProvider)\n\t\t\t) {\n\t\t\t\tknownProviders.add(baseProvider);\n\t\t\t\tif (baseProvider instanceof CachedConfigProvider) {\n\t\t\t\t\tcandidateProviders.push(...baseProvider.orderedBaseProviders);\n\t\t\t\t} else {\n\t\t\t\t\tthis.orderedBaseProviders.push(baseProvider);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tgetBoolean(name: string): boolean | undefined {\n\t\treturn this.getCacheEntry(name)?.boolean;\n\t}\n\tgetNumber(name: string): number | undefined {\n\t\treturn this.getCacheEntry(name)?.number;\n\t}\n\tgetString(name: string): string | undefined {\n\t\treturn this.getCacheEntry(name)?.string;\n\t}\n\tgetBooleanArray(name: string): boolean[] | undefined {\n\t\treturn this.getCacheEntry(name)?.[\"boolean[]\"];\n\t}\n\tgetNumberArray(name: string): number[] | undefined {\n\t\treturn this.getCacheEntry(name)?.[\"number[]\"];\n\t}\n\tgetStringArray(name: string): string[] | undefined {\n\t\treturn this.getCacheEntry(name)?.[\"string[]\"];\n\t}\n\n\tgetRawConfig(name: string): ConfigTypes {\n\t\treturn this.getCacheEntry(name)?.raw;\n\t}\n\n\tprivate getCacheEntry(name: string): StronglyTypedValue | undefined {\n\t\tif (!this.configCache.has(name)) {\n\t\t\tfor (const provider of this.orderedBaseProviders) {\n\t\t\t\tconst parsed = stronglyTypedParse(provider?.getRawConfig(name));\n\t\t\t\tif (parsed !== undefined) {\n\t\t\t\t\tthis.configCache.set(name, parsed);\n\t\t\t\t\tthis.logger?.send({\n\t\t\t\t\t\tcategory: \"generic\",\n\t\t\t\t\t\teventName: \"ConfigRead\",\n\t\t\t\t\t\t...tagCodeArtifacts({\n\t\t\t\t\t\t\tconfigName: name,\n\t\t\t\t\t\t\tconfigValue: JSON.stringify(parsed),\n\t\t\t\t\t\t}),\n\t\t\t\t\t});\n\t\t\t\t\treturn parsed;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// configs are immutable, if the first lookup returned no results, all lookups should\n\t\t\tthis.configCache.set(name, { raw: undefined });\n\t\t}\n\t\treturn this.configCache.get(name);\n\t}\n}\n\n/**\n * A type containing both a telemetry logger and a configuration provider.\n *\n * @internal\n */\nexport interface MonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLoggerExt> {\n\tconfig: IConfigProvider;\n\tlogger: L;\n}\n\n/**\n * Determines whether or not the provided object is a {@link MonitoringContext}.\n * @remarks Can be used for type-narrowing.\n *\n * @internal\n */\nexport function loggerIsMonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLoggerExt>(\n\tobj: L,\n): obj is L & MonitoringContext<L> {\n\tconst maybeConfig = obj as Partial<MonitoringContext<L>> | undefined;\n\treturn isConfigProviderBase(maybeConfig?.config) && maybeConfig?.logger !== undefined;\n}\n\n/**\n * Creates a {@link MonitoringContext} from the provided logger, if it isn't already one.\n *\n * @internal\n */\nexport function loggerToMonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLoggerExt>(\n\tlogger: L,\n): MonitoringContext<L> {\n\tif (loggerIsMonitoringContext<L>(logger)) {\n\t\treturn logger;\n\t}\n\treturn mixinMonitoringContext<L>(logger, sessionStorageConfigProvider.value);\n}\n\n/**\n * Creates a {@link MonitoringContext} from the provided logger.\n *\n * @remarks\n * Assumes that the provided logger is not itself already a {@link MonitoringContext}, and will throw an error if it is.\n * If you are unsure, use {@link loggerToMonitoringContext} instead.\n *\n * @throws If the provided logger is already a {@link MonitoringContext}.\n *\n * @internal\n */\nexport function mixinMonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLoggerExt>(\n\tlogger: L,\n\t...configs: (IConfigProviderBase | undefined)[]\n): MonitoringContext<L> {\n\tif (loggerIsMonitoringContext<L>(logger)) {\n\t\tthrow new Error(\"Logger is already a monitoring context\");\n\t}\n\t/**\n\t * this is the tricky bit we use for now to smuggle monitoring context around.\n\t * To the logger we mixin both config and itself, so mc.logger === logger as it is self-referential.\n\t * We then expose it as a Monitoring context, so via types we hide the outer logger methods.\n\t * To layers that expect just a logger we can pass mc.logger, but this is still a MonitoringContext\n\t * so if a deeper layer then converts that logger to a monitoring context it can find the smuggled properties\n\t * of the MonitoringContext and get the config provider.\n\t */\n\tconst mc: L & Partial<MonitoringContext<L>> = logger;\n\tmc.config = new CachedConfigProvider(logger, ...configs);\n\tmc.logger = logger;\n\treturn mc as MonitoringContext<L>;\n}\n\nfunction isConfigProviderBase(obj: unknown): obj is IConfigProviderBase {\n\tconst maybeConfig = obj as Partial<IConfigProviderBase> | undefined;\n\treturn typeof maybeConfig?.getRawConfig === \"function\";\n}\n\n/**\n * Creates a child logger with a {@link MonitoringContext}.\n *\n * @see {@link loggerToMonitoringContext}\n * @internal\n */\nexport function createChildMonitoringContext(\n\tprops: Parameters<typeof createChildLogger>[0],\n): MonitoringContext {\n\treturn loggerToMonitoringContext(createChildLogger(props));\n}\n"]}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.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 type {\n\tConfigTypes,\n\tIConfigProviderBase,\n\tITelemetryBaseLogger,\n} from \"@fluidframework/core-interfaces\";\nimport { Lazy } from \"@fluidframework/core-utils/internal\";\n\nimport { createChildLogger, tagCodeArtifacts } from \"./logger.js\";\nimport type { ITelemetryLoggerExt } from \"./telemetryTypes.js\";\n\n/**\n * Explicitly typed interface for reading configurations.\n *\n * @internal\n */\nexport interface IConfigProvider extends IConfigProviderBase {\n\tgetBoolean(name: string): boolean | undefined;\n\tgetNumber(name: string): number | undefined;\n\tgetString(name: string): string | undefined;\n\tgetBooleanArray(name: string): boolean[] | undefined;\n\tgetNumberArray(name: string): number[] | undefined;\n\tgetStringArray(name: string): string[] | undefined;\n}\n/**\n * Creates a base configuration provider based on `sessionStorage`\n *\n * @returns A lazy initialized base configuration provider with `sessionStorage` as the underlying config store\n *\n * @internal\n */\nexport const sessionStorageConfigProvider = new Lazy<IConfigProviderBase>(() =>\n\tinMemoryConfigProvider(safeSessionStorage()),\n);\n\nconst NullConfigProvider: IConfigProviderBase = {\n\tgetRawConfig: () => undefined,\n};\n\n/**\n * Creates a base configuration provider based on the supplied `Storage` instance\n *\n * @param storage - instance of `Storage` to be used as storage media for the config\n * @returns A base configuration provider with\n * the supplied `Storage` instance as the underlying config store\n */\nexport const inMemoryConfigProvider = (storage: Storage | undefined): IConfigProviderBase => {\n\tif (storage !== undefined && storage !== null) {\n\t\treturn new CachedConfigProvider(undefined, {\n\t\t\tgetRawConfig: (name: string): ConfigTypes | undefined => {\n\t\t\t\ttry {\n\t\t\t\t\treturn stronglyTypedParse(storage.getItem(name) ?? undefined)?.raw;\n\t\t\t\t} catch {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t}\n\treturn NullConfigProvider;\n};\n\ninterface ConfigTypeStringToType {\n\tnumber: number;\n\tstring: string;\n\tboolean: boolean;\n\t[\"number[]\"]: number[];\n\t[\"string[]\"]: string[];\n\t[\"boolean[]\"]: boolean[];\n}\n\ntype PrimitiveTypeStrings = \"number\" | \"string\" | \"boolean\";\n\nfunction isPrimitiveType(type: string): type is PrimitiveTypeStrings {\n\tswitch (type) {\n\t\tcase \"boolean\":\n\t\tcase \"number\":\n\t\tcase \"string\": {\n\t\t\treturn true;\n\t\t}\n\t\tdefault: {\n\t\t\treturn false;\n\t\t}\n\t}\n}\n\ninterface StronglyTypedValue extends Partial<ConfigTypeStringToType> {\n\traw: ConfigTypes;\n}\n/**\n * Takes any supported config type, and returns the value with a strong type. If the type of\n * the config is not a supported type undefined will be returned.\n * The user of this function should cache the result to avoid duplicated work.\n *\n * Strings will be attempted to be parsed and coerced into a strong config type.\n * if it is not possible to parsed and coerce a string to a strong config type the original string\n * will be return with a string type for the consumer to handle further if necessary.\n */\nfunction stronglyTypedParse(input: ConfigTypes): StronglyTypedValue | undefined {\n\tlet output: ConfigTypes = input;\n\tlet defaultReturn: Pick<StronglyTypedValue, \"raw\" | \"string\"> | undefined;\n\t// we do special handling for strings to try and coerce\n\t// them into a config type if we can. This makes it easy\n\t// for config sources like sessionStorage which only\n\t// holds strings\n\tif (typeof input === \"string\") {\n\t\ttry {\n\t\t\toutput = JSON.parse(input) as ConfigTypes;\n\t\t\t// we succeeded in parsing, but we don't support parsing\n\t\t\t// for any object as we can't do it type safely\n\t\t\t// so in this case, the default return will be string\n\t\t\t// rather than undefined, and the consumer\n\t\t\t// can parse, as we don't want to provide\n\t\t\t// a false sense of security by just\n\t\t\t// casting.\n\t\t\tdefaultReturn = { raw: input, string: input };\n\t\t} catch {\n\t\t\t// No-op\n\t\t}\n\t}\n\n\tif (output === undefined) {\n\t\treturn defaultReturn;\n\t}\n\n\tconst outputType = typeof output;\n\tif (isPrimitiveType(outputType)) {\n\t\treturn { ...defaultReturn, raw: input, [outputType]: output };\n\t}\n\n\tif (Array.isArray(output)) {\n\t\tconst firstType = typeof output[0];\n\t\t// ensure the first elements is a primitive type\n\t\tif (!isPrimitiveType(firstType)) {\n\t\t\treturn defaultReturn;\n\t\t}\n\t\t// ensue all the elements types are homogeneous\n\t\t// aka they all have the same type as the first\n\t\tfor (const v of output) {\n\t\t\tif (typeof v !== firstType) {\n\t\t\t\treturn defaultReturn;\n\t\t\t}\n\t\t}\n\t\treturn { ...defaultReturn, raw: input, [`${firstType}[]`]: output };\n\t}\n\n\treturn defaultReturn;\n}\n\n/**\n * `sessionStorage` is undefined in some environments such as Node and web pages with session storage disabled.\n */\nconst safeSessionStorage = (): Storage | undefined => {\n\t// For some configurations accessing \"globalThis.sessionStorage\" throws\n\t// \"'sessionStorage' property from 'Window': Access is denied for this document\" rather than returning undefined.\n\t// Therefor check for it before accessing.\n\ttry {\n\t\t// Using globalThis and checking for undefined is preferred over just accessing global sessionStorage\n\t\t// since it avoids an exception when running in node.\n\t\t// In some cases this has returned null when disabled in the browser, so ensure its undefined in that case:\n\t\treturn globalThis.sessionStorage ?? undefined;\n\t} catch {\n\t\t// For browsers which error on the above when session storage is disabled:\n\t\treturn undefined;\n\t}\n};\n\n/**\n * Creates a wrapper on top of an existing config provider which allows for\n * specifying feature gates if not present in the original provider.\n *\n * @param original - the original config provider\n * @param defaults - default feature gate configs to be used if not specified by the original provider\n * @returns A config provider that looks for any requested feature gates in the original provider and falls\n * back to the values specified in the `defaults` feature gates if they're not present in the original.\n *\n * @internal\n */\nexport const wrapConfigProviderWithDefaults = (\n\toriginal: IConfigProviderBase | undefined,\n\tdefaults: Record<string, ConfigTypes>,\n): IConfigProviderBase => ({\n\tgetRawConfig: (name: string): ConfigTypes => original?.getRawConfig(name) ?? defaults[name],\n});\n\n/**\n * Implementation of {@link IConfigProvider} which contains nested {@link IConfigProviderBase} instances\n */\nexport class CachedConfigProvider implements IConfigProvider {\n\tprivate readonly configCache = new Map<string, StronglyTypedValue>();\n\tprivate readonly orderedBaseProviders: (IConfigProviderBase | undefined)[];\n\n\tpublic constructor(\n\t\tprivate readonly logger?: ITelemetryBaseLogger,\n\t\t...orderedBaseProviders: (IConfigProviderBase | undefined)[]\n\t) {\n\t\tthis.orderedBaseProviders = [];\n\t\tconst knownProviders = new Set<IConfigProviderBase>();\n\t\tconst candidateProviders = [...orderedBaseProviders];\n\t\twhile (candidateProviders.length > 0) {\n\t\t\tconst baseProvider = candidateProviders.shift()!;\n\t\t\tif (\n\t\t\t\tbaseProvider !== undefined &&\n\t\t\t\tisConfigProviderBase(baseProvider) &&\n\t\t\t\t!knownProviders.has(baseProvider)\n\t\t\t) {\n\t\t\t\tknownProviders.add(baseProvider);\n\t\t\t\tif (baseProvider instanceof CachedConfigProvider) {\n\t\t\t\t\tcandidateProviders.push(...baseProvider.orderedBaseProviders);\n\t\t\t\t} else {\n\t\t\t\t\tthis.orderedBaseProviders.push(baseProvider);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tpublic getBoolean(name: string): boolean | undefined {\n\t\treturn this.getCacheEntry(name)?.boolean;\n\t}\n\tpublic getNumber(name: string): number | undefined {\n\t\treturn this.getCacheEntry(name)?.number;\n\t}\n\tpublic getString(name: string): string | undefined {\n\t\treturn this.getCacheEntry(name)?.string;\n\t}\n\tpublic getBooleanArray(name: string): boolean[] | undefined {\n\t\treturn this.getCacheEntry(name)?.[\"boolean[]\"];\n\t}\n\tpublic getNumberArray(name: string): number[] | undefined {\n\t\treturn this.getCacheEntry(name)?.[\"number[]\"];\n\t}\n\tpublic getStringArray(name: string): string[] | undefined {\n\t\treturn this.getCacheEntry(name)?.[\"string[]\"];\n\t}\n\n\tpublic getRawConfig(name: string): ConfigTypes {\n\t\treturn this.getCacheEntry(name)?.raw;\n\t}\n\n\tprivate getCacheEntry(name: string): StronglyTypedValue | undefined {\n\t\tif (!this.configCache.has(name)) {\n\t\t\tfor (const provider of this.orderedBaseProviders) {\n\t\t\t\tconst parsed = stronglyTypedParse(provider?.getRawConfig(name));\n\t\t\t\tif (parsed !== undefined) {\n\t\t\t\t\tthis.configCache.set(name, parsed);\n\t\t\t\t\tthis.logger?.send({\n\t\t\t\t\t\tcategory: \"generic\",\n\t\t\t\t\t\teventName: \"ConfigRead\",\n\t\t\t\t\t\t...tagCodeArtifacts({\n\t\t\t\t\t\t\tconfigName: name,\n\t\t\t\t\t\t\tconfigValue: JSON.stringify(parsed),\n\t\t\t\t\t\t}),\n\t\t\t\t\t});\n\t\t\t\t\treturn parsed;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// configs are immutable, if the first lookup returned no results, all lookups should\n\t\t\tthis.configCache.set(name, { raw: undefined });\n\t\t}\n\t\treturn this.configCache.get(name);\n\t}\n}\n\n/**\n * A type containing both a telemetry logger and a configuration provider.\n *\n * @internal\n */\nexport interface MonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLoggerExt> {\n\tconfig: IConfigProvider;\n\tlogger: L;\n}\n\n/**\n * Determines whether or not the provided object is a {@link MonitoringContext}.\n * @remarks Can be used for type-narrowing.\n *\n * @internal\n */\nexport function loggerIsMonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLoggerExt>(\n\tobj: L,\n): obj is L & MonitoringContext<L> {\n\tconst maybeConfig = obj as Partial<MonitoringContext<L>> | undefined;\n\treturn isConfigProviderBase(maybeConfig?.config) && maybeConfig?.logger !== undefined;\n}\n\n/**\n * Creates a {@link MonitoringContext} from the provided logger, if it isn't already one.\n *\n * @internal\n */\nexport function loggerToMonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLoggerExt>(\n\tlogger: L,\n): MonitoringContext<L> {\n\tif (loggerIsMonitoringContext<L>(logger)) {\n\t\treturn logger;\n\t}\n\treturn mixinMonitoringContext<L>(logger, sessionStorageConfigProvider.value);\n}\n\n/**\n * Creates a {@link MonitoringContext} from the provided logger.\n *\n * @remarks\n * Assumes that the provided logger is not itself already a {@link MonitoringContext}, and will throw an error if it is.\n * If you are unsure, use {@link loggerToMonitoringContext} instead.\n *\n * @throws If the provided logger is already a {@link MonitoringContext}.\n *\n * @internal\n */\nexport function mixinMonitoringContext<L extends ITelemetryBaseLogger = ITelemetryLoggerExt>(\n\tlogger: L,\n\t...configs: (IConfigProviderBase | undefined)[]\n): MonitoringContext<L> {\n\tif (loggerIsMonitoringContext<L>(logger)) {\n\t\tthrow new Error(\"Logger is already a monitoring context\");\n\t}\n\t/**\n\t * this is the tricky bit we use for now to smuggle monitoring context around.\n\t * To the logger we mixin both config and itself, so mc.logger === logger as it is self-referential.\n\t * We then expose it as a Monitoring context, so via types we hide the outer logger methods.\n\t * To layers that expect just a logger we can pass mc.logger, but this is still a MonitoringContext\n\t * so if a deeper layer then converts that logger to a monitoring context it can find the smuggled properties\n\t * of the MonitoringContext and get the config provider.\n\t */\n\tconst mc: L & Partial<MonitoringContext<L>> = logger;\n\tmc.config = new CachedConfigProvider(logger, ...configs);\n\tmc.logger = logger;\n\treturn mc as MonitoringContext<L>;\n}\n\nfunction isConfigProviderBase(obj: unknown): obj is IConfigProviderBase {\n\tconst maybeConfig = obj as Partial<IConfigProviderBase> | undefined;\n\treturn typeof maybeConfig?.getRawConfig === \"function\";\n}\n\n/**\n * Creates a child logger with a {@link MonitoringContext}.\n *\n * @see {@link loggerToMonitoringContext}\n * @internal\n */\nexport function createChildMonitoringContext(\n\tprops: Parameters<typeof createChildLogger>[0],\n): MonitoringContext {\n\treturn loggerToMonitoringContext(createChildLogger(props));\n}\n"]}
package/lib/error.d.ts CHANGED
@@ -2,12 +2,12 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- import { IErrorBase, ITelemetryBaseProperties } from "@fluidframework/core-interfaces";
6
- import { IGenericError, IUsageError } from "@fluidframework/core-interfaces/internal";
7
- import { ISequencedDocumentMessage } from "@fluidframework/driver-definitions/internal";
5
+ import type { IErrorBase, ITelemetryBaseProperties } from "@fluidframework/core-interfaces";
6
+ import { type IGenericError, type IUsageError } from "@fluidframework/core-interfaces/internal";
7
+ import type { ISequencedDocumentMessage } from "@fluidframework/driver-definitions/internal";
8
8
  import { LoggingError } from "./errorLogging.js";
9
- import { IFluidErrorBase } from "./fluidErrorBase.js";
10
- import { ITelemetryPropertiesExt } from "./telemetryTypes.js";
9
+ import type { IFluidErrorBase } from "./fluidErrorBase.js";
10
+ import type { ITelemetryPropertiesExt } from "./telemetryTypes.js";
11
11
  /**
12
12
  * Throws a UsageError with the given message if the condition is not met.
13
13
  * Use this API when `false` indicates a precondition is not met on a public API (for any FF layer).