@fluidframework/telemetry-utils 2.72.0 → 2.74.0-365691

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @fluidframework/telemetry-utils
2
2
 
3
+ ## 2.73.0
4
+
5
+ Dependency updates only.
6
+
3
7
  ## 2.72.0
4
8
 
5
9
  Dependency updates only.
@@ -38,9 +38,7 @@ export interface ICustomData<T> {
38
38
  *
39
39
  * @internal
40
40
  */
41
- export type MeasureReturnType<TMeasureReturn, TCustomMetrics> = TCustomMetrics extends void ? TMeasureReturn : ICustomData<TCustomMetrics> & (TMeasureReturn extends void ? {
42
- [K in "returnValue"]?: never;
43
- } : {
41
+ export type MeasureReturnType<TMeasureReturn, TCustomMetrics> = TCustomMetrics extends void ? TMeasureReturn : ICustomData<TCustomMetrics> & (TMeasureReturn extends void ? Partial<Record<"returnValue", never>> : {
44
42
  returnValue: TMeasureReturn;
45
43
  });
46
44
  /**
@@ -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;AAI7F,OAAO,KAAK,EACX,yBAAyB,EACzB,mBAAmB,EAEnB,MAAM,qBAAqB,CAAC;AA2D7B;;;;GAIG;AACH,MAAM,MAAM,aAAa,CAAC,IAAI,IAAI;KAChC,CAAC,IAAI,MAAM,IAAI,GAAG,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,KAAK;CACpD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC7B,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,iBAAiB,CAAC,cAAc,EAAE,cAAc,IAAI,cAAc,SAAS,IAAI,GACxF,cAAc,GACd,WAAW,CAAC,cAAc,CAAC,GAC3B,CAAC,cAAc,SAAS,IAAI,GACzB;KAAG,CAAC,IAAI,aAAa,CAAC,CAAC,EAAE,KAAK;CAAE,GAChC;IAAE,WAAW,EAAE,cAAc,CAAA;CAAE,CAAC,CAAC;AAEvC;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,sBAAsB,CAClC,cAAc,GAAG,IAAI,EACrB,cAAc,SAAS,aAAa,CAAC,cAAc,CAAC,GAAG,IAAI,CAC1D,YAAW,WAAW;IA4BtB,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;IA9BrC,OAAO,CAAC,SAAS,CAAkB;IAEnC;;OAEG;IACH,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAiC;IAEjE;;;;;;;;;;;;;OAaG;gBAEe,SAAS,EAAE,yBAAyB,EACpC,MAAM,EAAE,mBAAmB,EAC3B,eAAe,EAAE,MAAM,EACvB,uBAAuB,GAAE,OAAe,EACxC,mBAAmB,wCAA8C;IAGnF;;;;;;;;;;;;;;OAcG;IACI,OAAO,CACb,aAAa,EAAE,MAAM,iBAAiB,CAAC,cAAc,EAAE,cAAc,CAAC,EACtE,MAAM,GAAE,MAAW,GACjB,iBAAiB,CAAC,cAAc,EAAE,cAAc,CAAC;IAwCpD,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,oBAAoB;IAkB5B,OAAO,CAAC,iBAAiB;IAmBzB,OAAO,CAAC,WAAW;IAyBZ,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI;CAM/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;AAI7F,OAAO,KAAK,EACX,yBAAyB,EACzB,mBAAmB,EAEnB,MAAM,qBAAqB,CAAC;AA2D7B;;;;GAIG;AACH,MAAM,MAAM,aAAa,CAAC,IAAI,IAAI;KAChC,CAAC,IAAI,MAAM,IAAI,GAAG,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,KAAK;CACpD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC7B,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,iBAAiB,CAAC,cAAc,EAAE,cAAc,IAAI,cAAc,SAAS,IAAI,GACxF,cAAc,GACd,WAAW,CAAC,cAAc,CAAC,GAC3B,CAAC,cAAc,SAAS,IAAI,GACzB,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC,GACrC;IAAE,WAAW,EAAE,cAAc,CAAA;CAAE,CAAC,CAAC;AAEvC;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,sBAAsB,CAClC,cAAc,GAAG,IAAI,EACrB,cAAc,SAAS,aAAa,CAAC,cAAc,CAAC,GAAG,IAAI,CAC1D,YAAW,WAAW;IA4BtB,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;IA9BrC,OAAO,CAAC,SAAS,CAAkB;IAEnC;;OAEG;IACH,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAiC;IAEjE;;;;;;;;;;;;;OAaG;gBAEe,SAAS,EAAE,yBAAyB,EACpC,MAAM,EAAE,mBAAmB,EAC3B,eAAe,EAAE,MAAM,EACvB,uBAAuB,GAAE,OAAe,EACxC,mBAAmB,wCAA8C;IAGnF;;;;;;;;;;;;;;OAcG;IACI,OAAO,CACb,aAAa,EAAE,MAAM,iBAAiB,CAAC,cAAc,EAAE,cAAc,CAAC,EACtE,MAAM,GAAE,MAAW,GACjB,iBAAiB,CAAC,cAAc,EAAE,cAAc,CAAC;IAwCpD,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,oBAAoB;IAkB5B,OAAO,CAAC,iBAAiB;IAmBzB,OAAO,CAAC,WAAW;IAyBZ,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI;CAM/C"}
@@ -1 +1 @@
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 { performanceNow } from \"@fluid-internal/client-utils\";\nimport type { IDisposable, ITelemetryBaseProperties } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\n\nimport { roundToDecimalPlaces } from \"./mathTools.js\";\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\t/**\n\t * Average duration across all the executions since the last event was generated.\n\t */\n\taverageDuration?: number;\n}\n\n/**\n * The data that will be logged in the telemetry event.\n */\ninterface LoggerData {\n\tmeasurements: Measurements;\n\n\t/**\n\t * The sum of the custom data passed into the logger for each key.\n\t * Absence of a given key should be interpreted as 0.\n\t */\n\tdataSums: Record<string, number>;\n\n\t/**\n\t * The max of the custom data passed into the logger for each key.\n\t */\n\tdataMaxes: Record<string, number>;\n}\n\n/**\n * Helper type for an object whose properties are all numbers\n *\n * @internal\n */\nexport type CustomMetrics<TKey> = {\n\t[K in keyof TKey]: K extends string ? number : never;\n};\n\n/**\n * Potentially part of the structure of the return value of the function provided to {@link SampledTelemetryHelper.measure}.\n *\n * @see {@link MeasureReturnType} for more details on how this type is used.\n *\n * @internal\n */\nexport interface ICustomData<T> {\n\tcustomData: CustomMetrics<T>;\n}\n\n/**\n * Encapsulates the type-level logic for {@link SampledTelemetryHelper.measure}, to determine the expected return type\n * for the function that method receives (and by extension, its own return type). In words: {@link SampledTelemetryHelper}\n * is optionally provided with two generic types: one for custom metrics, and one for the actual return value of the\n * code that will be measured.\n *\n * - If no generic type is provided for custom metrics, then this type is simply the generic type provided for the actual\n * return value of the measured code (which could be void!).\n * - If a generic type is provided for custom metrics, then this type has a `customData` property whose type matches that\n * generic. Then if the generic type for the actual return value is not void, this type also has a property `returnValue`\n * whose type matches the generic type for the actual return value; if the generic type for the actual return value is\n * void, then this type _forbids_ a `returnValue` property (technically, it can exist but must be undefined in that case),\n * to try to ensure that the caller doesn't accidentally provide a function that actually returns a value.\n *\n * @internal\n */\nexport type MeasureReturnType<TMeasureReturn, TCustomMetrics> = TCustomMetrics extends void\n\t? TMeasureReturn\n\t: ICustomData<TCustomMetrics> &\n\t\t\t(TMeasureReturn extends void\n\t\t\t\t? { [K in \"returnValue\"]?: never }\n\t\t\t\t: { returnValue: TMeasureReturn });\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 * @remarks\n * The `duration` field in the telemetry event this class generates is the duration of the latest execution (sample)\n * of the specified code block.\n * See the documentation of the `includeAggregateMetrics` parameter for additional details that can be included.\n *\n * @typeParam TMeasurementReturn - The return type (in a vacuum) of the code block that will be measured, ignoring\n * any custom metric data that might be required by this class. E.g., the code might just return a boolean.\n * @typeParam TCustomMetrics - A type that contains the custom properties that will be used by an instance of this class\n * for custom metrics. Each property in this type should be a number.\n *\n * @internal\n */\nexport class SampledTelemetryHelper<\n\tTMeasureReturn = void,\n\tTCustomMetrics extends CustomMetrics<TCustomMetrics> = void,\n> implements IDisposable\n{\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, LoggerData>();\n\n\t/**\n\t * @param eventBase - Custom properties to include in the telemetry performance event when it is written.\n\t * @param logger - The logger to use to write the telemetry performance event.\n\t * @param sampleThreshold - Telemetry performance events will be generated every time we hit this many executions\n\t * of the code block.\n\t * @param includeAggregateMetrics - If set to `true`, the telemetry performance event will include aggregated\n\t * metrics (total duration, min duration, max duration) for all the executions in between generated events.\n\t * @param perBucketProperties - Map of strings that represent different buckets (which can be specified when calling\n\t * the 'measure' method), to properties which should be added to the telemetry event for that bucket.\n\t * If a bucket being measured does not have an entry in this map, no additional properties will be added to its\n\t * telemetry events. The following keys are reserved for use by this class: \"duration\", \"count\", \"totalDuration\",\n\t * \"minDuration\", \"maxDuration\". If any of them is specified as a key in one of the ITelemetryBaseProperties objects\n\t * in this map, that key-value pair will be 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 * When it's been called enough times (the sampleThreshold for the class) then it generates a log message with the\n\t * necessary information.\n\t *\n\t * @remarks It's the responsibility of the caller to ensure that the same same set of custom metric properties is\n\t * provided each time this method is called on a given instance of {@link SampledTelemetryHelper}.\n\t * Otherwise the final measurements in the telemetry event may not be accurate.\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(\n\t\tcodeToMeasure: () => MeasureReturnType<TMeasureReturn, TCustomMetrics>,\n\t\tbucket: string = \"\",\n\t): MeasureReturnType<TMeasureReturn, TCustomMetrics> {\n\t\tconst start = performanceNow();\n\t\tconst returnValue = codeToMeasure();\n\t\tconst duration = performanceNow() - start;\n\n\t\tlet loggerData = this.measurementsMap.get(bucket);\n\t\tif (loggerData === undefined) {\n\t\t\tloggerData = {\n\t\t\t\tmeasurements: { count: 0, duration: -1 },\n\t\t\t\tdataSums: {},\n\t\t\t\tdataMaxes: {},\n\t\t\t};\n\t\t\tthis.measurementsMap.set(bucket, loggerData);\n\t\t}\n\n\t\tconst m = loggerData.measurements;\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 (this.isCustomData(returnValue)) {\n\t\t\tloggerData = this.accumulateCustomData(returnValue.customData, loggerData);\n\t\t}\n\n\t\tif (m.count >= this.sampleThreshold) {\n\t\t\t// Computed separately to avoid multiple division operations.\n\t\t\tif (this.includeAggregateMetrics) {\n\t\t\t\tm.averageDuration = (m.totalDuration ?? 0) / m.count;\n\t\t\t}\n\t\t\tthis.flushBucket(bucket);\n\t\t}\n\n\t\treturn returnValue;\n\t}\n\n\tprivate isCustomData(data: unknown): data is ICustomData<TCustomMetrics> {\n\t\treturn (\n\t\t\ttypeof data === \"object\" &&\n\t\t\tdata !== null &&\n\t\t\t\"customData\" in data &&\n\t\t\ttypeof data.customData === \"object\"\n\t\t);\n\t}\n\n\tprivate accumulateCustomData(\n\t\tcustomData: CustomMetrics<TCustomMetrics>,\n\t\tloggerData: LoggerData,\n\t): LoggerData {\n\t\tfor (const [key, val] of Object.entries(customData)) {\n\t\t\tassert(typeof key === \"string\", 0x9df /* Key should be a string */);\n\t\t\tassert(typeof val === \"number\", 0x9e0 /* Value should be a number */);\n\n\t\t\tloggerData.dataSums[key] = (loggerData.dataSums[key] ?? 0) + val;\n\t\t\tloggerData.dataMaxes[key] = Math.max(\n\t\t\t\tloggerData.dataMaxes[key] ?? Number.NEGATIVE_INFINITY,\n\t\t\t\tval,\n\t\t\t);\n\t\t}\n\n\t\treturn loggerData;\n\t}\n\n\tprivate processCustomData(loggerData: LoggerData, count: number): Record<string, number> {\n\t\tconst processedCustomData: Record<string, number> = {};\n\n\t\tif (loggerData.dataSums === undefined || loggerData.dataMaxes === undefined) {\n\t\t\treturn processedCustomData;\n\t\t}\n\n\t\tconst dataSums = loggerData.dataSums;\n\t\tconst dataMaxes = loggerData.dataMaxes;\n\n\t\tfor (const [key, val] of Object.entries(dataSums)) {\n\t\t\t// implementation of class guarantees the keys between dataMaxes and dataSums align.\n\t\t\tprocessedCustomData[`avg_${key}`] = roundToDecimalPlaces(val / count, 6);\n\t\t\tprocessedCustomData[`max_${key}`] = dataMaxes[key] ?? 0;\n\t\t}\n\n\t\treturn processedCustomData;\n\t}\n\n\tprivate flushBucket(bucket: string): void {\n\t\tconst loggerData = this.measurementsMap.get(bucket);\n\t\tif (loggerData === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst measurements = loggerData.measurements;\n\n\t\tconst processedCustomData = this.processCustomData(loggerData, measurements.count);\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\t...processedCustomData,\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"]}
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 { performanceNow } from \"@fluid-internal/client-utils\";\nimport type { IDisposable, ITelemetryBaseProperties } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\n\nimport { roundToDecimalPlaces } from \"./mathTools.js\";\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\t/**\n\t * Average duration across all the executions since the last event was generated.\n\t */\n\taverageDuration?: number;\n}\n\n/**\n * The data that will be logged in the telemetry event.\n */\ninterface LoggerData {\n\tmeasurements: Measurements;\n\n\t/**\n\t * The sum of the custom data passed into the logger for each key.\n\t * Absence of a given key should be interpreted as 0.\n\t */\n\tdataSums: Record<string, number>;\n\n\t/**\n\t * The max of the custom data passed into the logger for each key.\n\t */\n\tdataMaxes: Record<string, number>;\n}\n\n/**\n * Helper type for an object whose properties are all numbers\n *\n * @internal\n */\nexport type CustomMetrics<TKey> = {\n\t[K in keyof TKey]: K extends string ? number : never;\n};\n\n/**\n * Potentially part of the structure of the return value of the function provided to {@link SampledTelemetryHelper.measure}.\n *\n * @see {@link MeasureReturnType} for more details on how this type is used.\n *\n * @internal\n */\nexport interface ICustomData<T> {\n\tcustomData: CustomMetrics<T>;\n}\n\n/**\n * Encapsulates the type-level logic for {@link SampledTelemetryHelper.measure}, to determine the expected return type\n * for the function that method receives (and by extension, its own return type). In words: {@link SampledTelemetryHelper}\n * is optionally provided with two generic types: one for custom metrics, and one for the actual return value of the\n * code that will be measured.\n *\n * - If no generic type is provided for custom metrics, then this type is simply the generic type provided for the actual\n * return value of the measured code (which could be void!).\n * - If a generic type is provided for custom metrics, then this type has a `customData` property whose type matches that\n * generic. Then if the generic type for the actual return value is not void, this type also has a property `returnValue`\n * whose type matches the generic type for the actual return value; if the generic type for the actual return value is\n * void, then this type _forbids_ a `returnValue` property (technically, it can exist but must be undefined in that case),\n * to try to ensure that the caller doesn't accidentally provide a function that actually returns a value.\n *\n * @internal\n */\nexport type MeasureReturnType<TMeasureReturn, TCustomMetrics> = TCustomMetrics extends void\n\t? TMeasureReturn\n\t: ICustomData<TCustomMetrics> &\n\t\t\t(TMeasureReturn extends void\n\t\t\t\t? Partial<Record<\"returnValue\", never>>\n\t\t\t\t: { returnValue: TMeasureReturn });\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 * @remarks\n * The `duration` field in the telemetry event this class generates is the duration of the latest execution (sample)\n * of the specified code block.\n * See the documentation of the `includeAggregateMetrics` parameter for additional details that can be included.\n *\n * @typeParam TMeasurementReturn - The return type (in a vacuum) of the code block that will be measured, ignoring\n * any custom metric data that might be required by this class. E.g., the code might just return a boolean.\n * @typeParam TCustomMetrics - A type that contains the custom properties that will be used by an instance of this class\n * for custom metrics. Each property in this type should be a number.\n *\n * @internal\n */\nexport class SampledTelemetryHelper<\n\tTMeasureReturn = void,\n\tTCustomMetrics extends CustomMetrics<TCustomMetrics> = void,\n> implements IDisposable\n{\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, LoggerData>();\n\n\t/**\n\t * @param eventBase - Custom properties to include in the telemetry performance event when it is written.\n\t * @param logger - The logger to use to write the telemetry performance event.\n\t * @param sampleThreshold - Telemetry performance events will be generated every time we hit this many executions\n\t * of the code block.\n\t * @param includeAggregateMetrics - If set to `true`, the telemetry performance event will include aggregated\n\t * metrics (total duration, min duration, max duration) for all the executions in between generated events.\n\t * @param perBucketProperties - Map of strings that represent different buckets (which can be specified when calling\n\t * the 'measure' method), to properties which should be added to the telemetry event for that bucket.\n\t * If a bucket being measured does not have an entry in this map, no additional properties will be added to its\n\t * telemetry events. The following keys are reserved for use by this class: \"duration\", \"count\", \"totalDuration\",\n\t * \"minDuration\", \"maxDuration\". If any of them is specified as a key in one of the ITelemetryBaseProperties objects\n\t * in this map, that key-value pair will be 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 * When it's been called enough times (the sampleThreshold for the class) then it generates a log message with the\n\t * necessary information.\n\t *\n\t * @remarks It's the responsibility of the caller to ensure that the same same set of custom metric properties is\n\t * provided each time this method is called on a given instance of {@link SampledTelemetryHelper}.\n\t * Otherwise the final measurements in the telemetry event may not be accurate.\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(\n\t\tcodeToMeasure: () => MeasureReturnType<TMeasureReturn, TCustomMetrics>,\n\t\tbucket: string = \"\",\n\t): MeasureReturnType<TMeasureReturn, TCustomMetrics> {\n\t\tconst start = performanceNow();\n\t\tconst returnValue = codeToMeasure();\n\t\tconst duration = performanceNow() - start;\n\n\t\tlet loggerData = this.measurementsMap.get(bucket);\n\t\tif (loggerData === undefined) {\n\t\t\tloggerData = {\n\t\t\t\tmeasurements: { count: 0, duration: -1 },\n\t\t\t\tdataSums: {},\n\t\t\t\tdataMaxes: {},\n\t\t\t};\n\t\t\tthis.measurementsMap.set(bucket, loggerData);\n\t\t}\n\n\t\tconst m = loggerData.measurements;\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 (this.isCustomData(returnValue)) {\n\t\t\tloggerData = this.accumulateCustomData(returnValue.customData, loggerData);\n\t\t}\n\n\t\tif (m.count >= this.sampleThreshold) {\n\t\t\t// Computed separately to avoid multiple division operations.\n\t\t\tif (this.includeAggregateMetrics) {\n\t\t\t\tm.averageDuration = (m.totalDuration ?? 0) / m.count;\n\t\t\t}\n\t\t\tthis.flushBucket(bucket);\n\t\t}\n\n\t\treturn returnValue;\n\t}\n\n\tprivate isCustomData(data: unknown): data is ICustomData<TCustomMetrics> {\n\t\treturn (\n\t\t\ttypeof data === \"object\" &&\n\t\t\tdata !== null &&\n\t\t\t\"customData\" in data &&\n\t\t\ttypeof data.customData === \"object\"\n\t\t);\n\t}\n\n\tprivate accumulateCustomData(\n\t\tcustomData: CustomMetrics<TCustomMetrics>,\n\t\tloggerData: LoggerData,\n\t): LoggerData {\n\t\tfor (const [key, val] of Object.entries(customData)) {\n\t\t\tassert(typeof key === \"string\", 0x9df /* Key should be a string */);\n\t\t\tassert(typeof val === \"number\", 0x9e0 /* Value should be a number */);\n\n\t\t\tloggerData.dataSums[key] = (loggerData.dataSums[key] ?? 0) + val;\n\t\t\tloggerData.dataMaxes[key] = Math.max(\n\t\t\t\tloggerData.dataMaxes[key] ?? Number.NEGATIVE_INFINITY,\n\t\t\t\tval,\n\t\t\t);\n\t\t}\n\n\t\treturn loggerData;\n\t}\n\n\tprivate processCustomData(loggerData: LoggerData, count: number): Record<string, number> {\n\t\tconst processedCustomData: Record<string, number> = {};\n\n\t\tif (loggerData.dataSums === undefined || loggerData.dataMaxes === undefined) {\n\t\t\treturn processedCustomData;\n\t\t}\n\n\t\tconst dataSums = loggerData.dataSums;\n\t\tconst dataMaxes = loggerData.dataMaxes;\n\n\t\tfor (const [key, val] of Object.entries(dataSums)) {\n\t\t\t// implementation of class guarantees the keys between dataMaxes and dataSums align.\n\t\t\tprocessedCustomData[`avg_${key}`] = roundToDecimalPlaces(val / count, 6);\n\t\t\tprocessedCustomData[`max_${key}`] = dataMaxes[key] ?? 0;\n\t\t}\n\n\t\treturn processedCustomData;\n\t}\n\n\tprivate flushBucket(bucket: string): void {\n\t\tconst loggerData = this.measurementsMap.get(bucket);\n\t\tif (loggerData === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst measurements = loggerData.measurements;\n\n\t\tconst processedCustomData = this.processCustomData(loggerData, measurements.count);\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\t...processedCustomData,\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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"telemetryEventBatcher.d.ts","sourceRoot":"","sources":["../src/telemetryEventBatcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,yBAAyB,EACzB,mBAAmB,EAEnB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;GAUG;AACH,qBAAa,qBAAqB,CAAC,QAAQ,SAAS,MAAM;IAiBxD;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM;IAEvB;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS;IA7B3B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAsC;IAEtD;;OAEG;IACH,OAAO,CAAC,SAAS,CAAsC;IAEvD;;OAEG;IACH,OAAO,CAAC,OAAO,CAAK;;IAGnB;;OAEG;IACc,SAAS,EAAE,yBAAyB;IAErD;;OAEG;IACc,MAAM,EAAE,mBAAmB;IAE5C;;OAEG;IACc,SAAS,EAAE,MAAM;IAGnC;;;;OAIG;IACI,gBAAgB,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,IAAI;IAgBnE,OAAO,CAAC,QAAQ;CAsBhB"}
1
+ {"version":3,"file":"telemetryEventBatcher.d.ts","sourceRoot":"","sources":["../src/telemetryEventBatcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,yBAAyB,EACzB,mBAAmB,EAEnB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;GAUG;AACH,qBAAa,qBAAqB,CAAC,QAAQ,SAAS,MAAM;IAiBxD;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM;IAEvB;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS;IA7B3B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAyC;IAEzD;;OAEG;IACH,OAAO,CAAC,SAAS,CAAyC;IAE1D;;OAEG;IACH,OAAO,CAAC,OAAO,CAAK;;IAGnB;;OAEG;IACc,SAAS,EAAE,yBAAyB;IAErD;;OAEG;IACc,MAAM,EAAE,mBAAmB;IAE5C;;OAEG;IACc,SAAS,EAAE,MAAM;IAGnC;;;;OAIG;IACI,gBAAgB,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,IAAI;IAgBnE,OAAO,CAAC,QAAQ;CAsBhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"telemetryEventBatcher.js","sourceRoot":"","sources":["../src/telemetryEventBatcher.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,iDAAsD;AAOtD;;;;;;;;;;GAUG;AACH,MAAa,qBAAqB;IAgBjC;IACC;;OAEG;IACc,SAAoC;IAErD;;OAEG;IACc,MAA2B;IAE5C;;OAEG;IACc,SAAiB;QAVjB,cAAS,GAAT,SAAS,CAA2B;QAKpC,WAAM,GAAN,MAAM,CAAqB;QAK3B,cAAS,GAAT,SAAS,CAAQ;QA7BnC;;WAEG;QACK,aAAQ,GAAmC,EAAE,CAAC;QAEtD;;WAEG;QACK,cAAS,GAAmC,EAAE,CAAC;QAEvD;;WAEG;QACK,YAAO,GAAG,CAAC,CAAC;IAiBjB,CAAC;IAEJ;;;;OAIG;IACI,gBAAgB,CAAC,UAAoC;QAC3D,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAe,EAAE,CAAC;YACzD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;YACjE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAC7B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,iBAAiB,EAC/C,UAAU,CAAC,GAAG,CAAC,CACf,CAAC;QACH,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;QAEf,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjB,CAAC;IACF,CAAC;IAEO,QAAQ;QACf,MAAM,cAAc,GAAkC;YACrD,GAAG,IAAI,CAAC,SAAS;SACjB,CAAC;QAEF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAe,EAAE,CAAC;YAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YACnC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC3B,cAAc,CAAC,OAAO,GAAG,EAAE,CAAC,GAAG,IAAA,mCAAoB,EAAC,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAChF,CAAC;YACD,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;gBACvC,cAAc,CAAC,OAAO,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACpD,CAAC;QACF,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC;QAEjD,kCAAkC;QAClC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;IACrB,CAAC;CACD;AA5ED,sDA4EC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { roundToDecimalPlaces } from \"./mathTools.js\";\nimport type {\n\tITelemetryGenericEventExt,\n\tITelemetryLoggerExt,\n\tITelemetryPerformanceEventExt,\n} from \"./telemetryTypes.js\";\n\n/**\n * Telemetry class that accumulates measurements which are eventually logged in a telemetry event through the provided\n * {@link TelemetryEventBatcher.logger | logger} when the number of calls to the function reaches the specified {@link TelemetryEventBatcher.threshold | threshold}.\n *\n * @remarks It is expected to be used for a single event type. If different properties should be logged at different times, a separate `TelemetryEventBatcher` should be created with separate `TMetrics` type.\n * @typeparam TMetrics - The set of keys that should be logged.\n * E.g., `keyof Foo` for logging properties `bar` and `baz` from `type Foo = { bar: number, baz: number }`.\n *\n * @sealed\n * @internal\n */\nexport class TelemetryEventBatcher<TMetrics extends string> {\n\t/**\n\t * Stores the sum of the custom data passed into the logger.\n\t */\n\tprivate dataSums: { [key in TMetrics]?: number } = {};\n\n\t/**\n\t * Stores the maximum value of the custom data passed into the logger.\n\t */\n\tprivate dataMaxes: { [key in TMetrics]?: number } = {};\n\n\t/**\n\t * Counter to keep track of the number of times the log function is called.\n\t */\n\tprivate counter = 0;\n\n\tpublic constructor(\n\t\t/**\n\t\t * Custom properties to include in the telemetry performance event when it is written.\n\t\t */\n\t\tprivate readonly eventBase: ITelemetryGenericEventExt,\n\n\t\t/**\n\t\t * The logger to use to write the telemetry performance event.\n\t\t */\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\n\t\t/**\n\t\t * The number of logs to accumulate before sending the data to the logger.\n\t\t */\n\t\tprivate readonly threshold: number,\n\t) {}\n\n\t/**\n\t * Accumulates the custom data and sends it to the logger every {@link TelemetryEventBatcher.threshold} calls.\n\t *\n\t * @param customData - A record storing the custom data to be accumulated and eventually logged.\n\t */\n\tpublic accumulateAndLog(customData: Record<TMetrics, number>): void {\n\t\tfor (const key of Object.keys(customData) as TMetrics[]) {\n\t\t\tthis.dataSums[key] = (this.dataSums[key] ?? 0) + customData[key];\n\t\t\tthis.dataMaxes[key] = Math.max(\n\t\t\t\tthis.dataMaxes[key] ?? Number.NEGATIVE_INFINITY,\n\t\t\t\tcustomData[key],\n\t\t\t);\n\t\t}\n\n\t\tthis.counter++;\n\n\t\tif (this.counter >= this.threshold) {\n\t\t\tthis.sendData();\n\t\t}\n\t}\n\n\tprivate sendData(): void {\n\t\tconst telemetryEvent: ITelemetryPerformanceEventExt = {\n\t\t\t...this.eventBase,\n\t\t};\n\n\t\tfor (const key of Object.keys(this.dataSums) as TMetrics[]) {\n\t\t\tconst dataSum = this.dataSums[key];\n\t\t\tif (dataSum !== undefined) {\n\t\t\t\ttelemetryEvent[`avg_${key}`] = roundToDecimalPlaces(dataSum / this.counter, 6);\n\t\t\t}\n\t\t\tif (this.dataMaxes[key] !== undefined) {\n\t\t\t\ttelemetryEvent[`max_${key}`] = this.dataMaxes[key];\n\t\t\t}\n\t\t}\n\n\t\tthis.logger.sendPerformanceEvent(telemetryEvent);\n\n\t\t// Reset the counter and the data.\n\t\tthis.counter = 0;\n\t\tthis.dataSums = {};\n\t\tthis.dataMaxes = {};\n\t}\n}\n"]}
1
+ {"version":3,"file":"telemetryEventBatcher.js","sourceRoot":"","sources":["../src/telemetryEventBatcher.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,iDAAsD;AAOtD;;;;;;;;;;GAUG;AACH,MAAa,qBAAqB;IAgBjC;IACC;;OAEG;IACc,SAAoC;IAErD;;OAEG;IACc,MAA2B;IAE5C;;OAEG;IACc,SAAiB;QAVjB,cAAS,GAAT,SAAS,CAA2B;QAKpC,WAAM,GAAN,MAAM,CAAqB;QAK3B,cAAS,GAAT,SAAS,CAAQ;QA7BnC;;WAEG;QACK,aAAQ,GAAsC,EAAE,CAAC;QAEzD;;WAEG;QACK,cAAS,GAAsC,EAAE,CAAC;QAE1D;;WAEG;QACK,YAAO,GAAG,CAAC,CAAC;IAiBjB,CAAC;IAEJ;;;;OAIG;IACI,gBAAgB,CAAC,UAAoC;QAC3D,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAe,EAAE,CAAC;YACzD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;YACjE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAC7B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,iBAAiB,EAC/C,UAAU,CAAC,GAAG,CAAC,CACf,CAAC;QACH,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;QAEf,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjB,CAAC;IACF,CAAC;IAEO,QAAQ;QACf,MAAM,cAAc,GAAkC;YACrD,GAAG,IAAI,CAAC,SAAS;SACjB,CAAC;QAEF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAe,EAAE,CAAC;YAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YACnC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC3B,cAAc,CAAC,OAAO,GAAG,EAAE,CAAC,GAAG,IAAA,mCAAoB,EAAC,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAChF,CAAC;YACD,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;gBACvC,cAAc,CAAC,OAAO,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACpD,CAAC;QACF,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC;QAEjD,kCAAkC;QAClC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;IACrB,CAAC;CACD;AA5ED,sDA4EC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { roundToDecimalPlaces } from \"./mathTools.js\";\nimport type {\n\tITelemetryGenericEventExt,\n\tITelemetryLoggerExt,\n\tITelemetryPerformanceEventExt,\n} from \"./telemetryTypes.js\";\n\n/**\n * Telemetry class that accumulates measurements which are eventually logged in a telemetry event through the provided\n * {@link TelemetryEventBatcher.logger | logger} when the number of calls to the function reaches the specified {@link TelemetryEventBatcher.threshold | threshold}.\n *\n * @remarks It is expected to be used for a single event type. If different properties should be logged at different times, a separate `TelemetryEventBatcher` should be created with separate `TMetrics` type.\n * @typeparam TMetrics - The set of keys that should be logged.\n * E.g., `keyof Foo` for logging properties `bar` and `baz` from `type Foo = { bar: number, baz: number }`.\n *\n * @sealed\n * @internal\n */\nexport class TelemetryEventBatcher<TMetrics extends string> {\n\t/**\n\t * Stores the sum of the custom data passed into the logger.\n\t */\n\tprivate dataSums: Partial<Record<TMetrics, number>> = {};\n\n\t/**\n\t * Stores the maximum value of the custom data passed into the logger.\n\t */\n\tprivate dataMaxes: Partial<Record<TMetrics, number>> = {};\n\n\t/**\n\t * Counter to keep track of the number of times the log function is called.\n\t */\n\tprivate counter = 0;\n\n\tpublic constructor(\n\t\t/**\n\t\t * Custom properties to include in the telemetry performance event when it is written.\n\t\t */\n\t\tprivate readonly eventBase: ITelemetryGenericEventExt,\n\n\t\t/**\n\t\t * The logger to use to write the telemetry performance event.\n\t\t */\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\n\t\t/**\n\t\t * The number of logs to accumulate before sending the data to the logger.\n\t\t */\n\t\tprivate readonly threshold: number,\n\t) {}\n\n\t/**\n\t * Accumulates the custom data and sends it to the logger every {@link TelemetryEventBatcher.threshold} calls.\n\t *\n\t * @param customData - A record storing the custom data to be accumulated and eventually logged.\n\t */\n\tpublic accumulateAndLog(customData: Record<TMetrics, number>): void {\n\t\tfor (const key of Object.keys(customData) as TMetrics[]) {\n\t\t\tthis.dataSums[key] = (this.dataSums[key] ?? 0) + customData[key];\n\t\t\tthis.dataMaxes[key] = Math.max(\n\t\t\t\tthis.dataMaxes[key] ?? Number.NEGATIVE_INFINITY,\n\t\t\t\tcustomData[key],\n\t\t\t);\n\t\t}\n\n\t\tthis.counter++;\n\n\t\tif (this.counter >= this.threshold) {\n\t\t\tthis.sendData();\n\t\t}\n\t}\n\n\tprivate sendData(): void {\n\t\tconst telemetryEvent: ITelemetryPerformanceEventExt = {\n\t\t\t...this.eventBase,\n\t\t};\n\n\t\tfor (const key of Object.keys(this.dataSums) as TMetrics[]) {\n\t\t\tconst dataSum = this.dataSums[key];\n\t\t\tif (dataSum !== undefined) {\n\t\t\t\ttelemetryEvent[`avg_${key}`] = roundToDecimalPlaces(dataSum / this.counter, 6);\n\t\t\t}\n\t\t\tif (this.dataMaxes[key] !== undefined) {\n\t\t\t\ttelemetryEvent[`max_${key}`] = this.dataMaxes[key];\n\t\t\t}\n\t\t}\n\n\t\tthis.logger.sendPerformanceEvent(telemetryEvent);\n\n\t\t// Reset the counter and the data.\n\t\tthis.counter = 0;\n\t\tthis.dataSums = {};\n\t\tthis.dataMaxes = {};\n\t}\n}\n"]}
@@ -38,9 +38,7 @@ export interface ICustomData<T> {
38
38
  *
39
39
  * @internal
40
40
  */
41
- export type MeasureReturnType<TMeasureReturn, TCustomMetrics> = TCustomMetrics extends void ? TMeasureReturn : ICustomData<TCustomMetrics> & (TMeasureReturn extends void ? {
42
- [K in "returnValue"]?: never;
43
- } : {
41
+ export type MeasureReturnType<TMeasureReturn, TCustomMetrics> = TCustomMetrics extends void ? TMeasureReturn : ICustomData<TCustomMetrics> & (TMeasureReturn extends void ? Partial<Record<"returnValue", never>> : {
44
42
  returnValue: TMeasureReturn;
45
43
  });
46
44
  /**
@@ -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;AAI7F,OAAO,KAAK,EACX,yBAAyB,EACzB,mBAAmB,EAEnB,MAAM,qBAAqB,CAAC;AA2D7B;;;;GAIG;AACH,MAAM,MAAM,aAAa,CAAC,IAAI,IAAI;KAChC,CAAC,IAAI,MAAM,IAAI,GAAG,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,KAAK;CACpD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC7B,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,iBAAiB,CAAC,cAAc,EAAE,cAAc,IAAI,cAAc,SAAS,IAAI,GACxF,cAAc,GACd,WAAW,CAAC,cAAc,CAAC,GAC3B,CAAC,cAAc,SAAS,IAAI,GACzB;KAAG,CAAC,IAAI,aAAa,CAAC,CAAC,EAAE,KAAK;CAAE,GAChC;IAAE,WAAW,EAAE,cAAc,CAAA;CAAE,CAAC,CAAC;AAEvC;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,sBAAsB,CAClC,cAAc,GAAG,IAAI,EACrB,cAAc,SAAS,aAAa,CAAC,cAAc,CAAC,GAAG,IAAI,CAC1D,YAAW,WAAW;IA4BtB,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;IA9BrC,OAAO,CAAC,SAAS,CAAkB;IAEnC;;OAEG;IACH,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAiC;IAEjE;;;;;;;;;;;;;OAaG;gBAEe,SAAS,EAAE,yBAAyB,EACpC,MAAM,EAAE,mBAAmB,EAC3B,eAAe,EAAE,MAAM,EACvB,uBAAuB,GAAE,OAAe,EACxC,mBAAmB,wCAA8C;IAGnF;;;;;;;;;;;;;;OAcG;IACI,OAAO,CACb,aAAa,EAAE,MAAM,iBAAiB,CAAC,cAAc,EAAE,cAAc,CAAC,EACtE,MAAM,GAAE,MAAW,GACjB,iBAAiB,CAAC,cAAc,EAAE,cAAc,CAAC;IAwCpD,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,oBAAoB;IAkB5B,OAAO,CAAC,iBAAiB;IAmBzB,OAAO,CAAC,WAAW;IAyBZ,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI;CAM/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;AAI7F,OAAO,KAAK,EACX,yBAAyB,EACzB,mBAAmB,EAEnB,MAAM,qBAAqB,CAAC;AA2D7B;;;;GAIG;AACH,MAAM,MAAM,aAAa,CAAC,IAAI,IAAI;KAChC,CAAC,IAAI,MAAM,IAAI,GAAG,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,KAAK;CACpD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC7B,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,iBAAiB,CAAC,cAAc,EAAE,cAAc,IAAI,cAAc,SAAS,IAAI,GACxF,cAAc,GACd,WAAW,CAAC,cAAc,CAAC,GAC3B,CAAC,cAAc,SAAS,IAAI,GACzB,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC,GACrC;IAAE,WAAW,EAAE,cAAc,CAAA;CAAE,CAAC,CAAC;AAEvC;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,sBAAsB,CAClC,cAAc,GAAG,IAAI,EACrB,cAAc,SAAS,aAAa,CAAC,cAAc,CAAC,GAAG,IAAI,CAC1D,YAAW,WAAW;IA4BtB,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;IA9BrC,OAAO,CAAC,SAAS,CAAkB;IAEnC;;OAEG;IACH,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAiC;IAEjE;;;;;;;;;;;;;OAaG;gBAEe,SAAS,EAAE,yBAAyB,EACpC,MAAM,EAAE,mBAAmB,EAC3B,eAAe,EAAE,MAAM,EACvB,uBAAuB,GAAE,OAAe,EACxC,mBAAmB,wCAA8C;IAGnF;;;;;;;;;;;;;;OAcG;IACI,OAAO,CACb,aAAa,EAAE,MAAM,iBAAiB,CAAC,cAAc,EAAE,cAAc,CAAC,EACtE,MAAM,GAAE,MAAW,GACjB,iBAAiB,CAAC,cAAc,EAAE,cAAc,CAAC;IAwCpD,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,oBAAoB;IAkB5B,OAAO,CAAC,iBAAiB;IAmBzB,OAAO,CAAC,WAAW;IAyBZ,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI;CAM/C"}
@@ -1 +1 @@
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 { performanceNow } from \"@fluid-internal/client-utils\";\nimport type { IDisposable, ITelemetryBaseProperties } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\n\nimport { roundToDecimalPlaces } from \"./mathTools.js\";\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\t/**\n\t * Average duration across all the executions since the last event was generated.\n\t */\n\taverageDuration?: number;\n}\n\n/**\n * The data that will be logged in the telemetry event.\n */\ninterface LoggerData {\n\tmeasurements: Measurements;\n\n\t/**\n\t * The sum of the custom data passed into the logger for each key.\n\t * Absence of a given key should be interpreted as 0.\n\t */\n\tdataSums: Record<string, number>;\n\n\t/**\n\t * The max of the custom data passed into the logger for each key.\n\t */\n\tdataMaxes: Record<string, number>;\n}\n\n/**\n * Helper type for an object whose properties are all numbers\n *\n * @internal\n */\nexport type CustomMetrics<TKey> = {\n\t[K in keyof TKey]: K extends string ? number : never;\n};\n\n/**\n * Potentially part of the structure of the return value of the function provided to {@link SampledTelemetryHelper.measure}.\n *\n * @see {@link MeasureReturnType} for more details on how this type is used.\n *\n * @internal\n */\nexport interface ICustomData<T> {\n\tcustomData: CustomMetrics<T>;\n}\n\n/**\n * Encapsulates the type-level logic for {@link SampledTelemetryHelper.measure}, to determine the expected return type\n * for the function that method receives (and by extension, its own return type). In words: {@link SampledTelemetryHelper}\n * is optionally provided with two generic types: one for custom metrics, and one for the actual return value of the\n * code that will be measured.\n *\n * - If no generic type is provided for custom metrics, then this type is simply the generic type provided for the actual\n * return value of the measured code (which could be void!).\n * - If a generic type is provided for custom metrics, then this type has a `customData` property whose type matches that\n * generic. Then if the generic type for the actual return value is not void, this type also has a property `returnValue`\n * whose type matches the generic type for the actual return value; if the generic type for the actual return value is\n * void, then this type _forbids_ a `returnValue` property (technically, it can exist but must be undefined in that case),\n * to try to ensure that the caller doesn't accidentally provide a function that actually returns a value.\n *\n * @internal\n */\nexport type MeasureReturnType<TMeasureReturn, TCustomMetrics> = TCustomMetrics extends void\n\t? TMeasureReturn\n\t: ICustomData<TCustomMetrics> &\n\t\t\t(TMeasureReturn extends void\n\t\t\t\t? { [K in \"returnValue\"]?: never }\n\t\t\t\t: { returnValue: TMeasureReturn });\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 * @remarks\n * The `duration` field in the telemetry event this class generates is the duration of the latest execution (sample)\n * of the specified code block.\n * See the documentation of the `includeAggregateMetrics` parameter for additional details that can be included.\n *\n * @typeParam TMeasurementReturn - The return type (in a vacuum) of the code block that will be measured, ignoring\n * any custom metric data that might be required by this class. E.g., the code might just return a boolean.\n * @typeParam TCustomMetrics - A type that contains the custom properties that will be used by an instance of this class\n * for custom metrics. Each property in this type should be a number.\n *\n * @internal\n */\nexport class SampledTelemetryHelper<\n\tTMeasureReturn = void,\n\tTCustomMetrics extends CustomMetrics<TCustomMetrics> = void,\n> implements IDisposable\n{\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, LoggerData>();\n\n\t/**\n\t * @param eventBase - Custom properties to include in the telemetry performance event when it is written.\n\t * @param logger - The logger to use to write the telemetry performance event.\n\t * @param sampleThreshold - Telemetry performance events will be generated every time we hit this many executions\n\t * of the code block.\n\t * @param includeAggregateMetrics - If set to `true`, the telemetry performance event will include aggregated\n\t * metrics (total duration, min duration, max duration) for all the executions in between generated events.\n\t * @param perBucketProperties - Map of strings that represent different buckets (which can be specified when calling\n\t * the 'measure' method), to properties which should be added to the telemetry event for that bucket.\n\t * If a bucket being measured does not have an entry in this map, no additional properties will be added to its\n\t * telemetry events. The following keys are reserved for use by this class: \"duration\", \"count\", \"totalDuration\",\n\t * \"minDuration\", \"maxDuration\". If any of them is specified as a key in one of the ITelemetryBaseProperties objects\n\t * in this map, that key-value pair will be 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 * When it's been called enough times (the sampleThreshold for the class) then it generates a log message with the\n\t * necessary information.\n\t *\n\t * @remarks It's the responsibility of the caller to ensure that the same same set of custom metric properties is\n\t * provided each time this method is called on a given instance of {@link SampledTelemetryHelper}.\n\t * Otherwise the final measurements in the telemetry event may not be accurate.\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(\n\t\tcodeToMeasure: () => MeasureReturnType<TMeasureReturn, TCustomMetrics>,\n\t\tbucket: string = \"\",\n\t): MeasureReturnType<TMeasureReturn, TCustomMetrics> {\n\t\tconst start = performanceNow();\n\t\tconst returnValue = codeToMeasure();\n\t\tconst duration = performanceNow() - start;\n\n\t\tlet loggerData = this.measurementsMap.get(bucket);\n\t\tif (loggerData === undefined) {\n\t\t\tloggerData = {\n\t\t\t\tmeasurements: { count: 0, duration: -1 },\n\t\t\t\tdataSums: {},\n\t\t\t\tdataMaxes: {},\n\t\t\t};\n\t\t\tthis.measurementsMap.set(bucket, loggerData);\n\t\t}\n\n\t\tconst m = loggerData.measurements;\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 (this.isCustomData(returnValue)) {\n\t\t\tloggerData = this.accumulateCustomData(returnValue.customData, loggerData);\n\t\t}\n\n\t\tif (m.count >= this.sampleThreshold) {\n\t\t\t// Computed separately to avoid multiple division operations.\n\t\t\tif (this.includeAggregateMetrics) {\n\t\t\t\tm.averageDuration = (m.totalDuration ?? 0) / m.count;\n\t\t\t}\n\t\t\tthis.flushBucket(bucket);\n\t\t}\n\n\t\treturn returnValue;\n\t}\n\n\tprivate isCustomData(data: unknown): data is ICustomData<TCustomMetrics> {\n\t\treturn (\n\t\t\ttypeof data === \"object\" &&\n\t\t\tdata !== null &&\n\t\t\t\"customData\" in data &&\n\t\t\ttypeof data.customData === \"object\"\n\t\t);\n\t}\n\n\tprivate accumulateCustomData(\n\t\tcustomData: CustomMetrics<TCustomMetrics>,\n\t\tloggerData: LoggerData,\n\t): LoggerData {\n\t\tfor (const [key, val] of Object.entries(customData)) {\n\t\t\tassert(typeof key === \"string\", 0x9df /* Key should be a string */);\n\t\t\tassert(typeof val === \"number\", 0x9e0 /* Value should be a number */);\n\n\t\t\tloggerData.dataSums[key] = (loggerData.dataSums[key] ?? 0) + val;\n\t\t\tloggerData.dataMaxes[key] = Math.max(\n\t\t\t\tloggerData.dataMaxes[key] ?? Number.NEGATIVE_INFINITY,\n\t\t\t\tval,\n\t\t\t);\n\t\t}\n\n\t\treturn loggerData;\n\t}\n\n\tprivate processCustomData(loggerData: LoggerData, count: number): Record<string, number> {\n\t\tconst processedCustomData: Record<string, number> = {};\n\n\t\tif (loggerData.dataSums === undefined || loggerData.dataMaxes === undefined) {\n\t\t\treturn processedCustomData;\n\t\t}\n\n\t\tconst dataSums = loggerData.dataSums;\n\t\tconst dataMaxes = loggerData.dataMaxes;\n\n\t\tfor (const [key, val] of Object.entries(dataSums)) {\n\t\t\t// implementation of class guarantees the keys between dataMaxes and dataSums align.\n\t\t\tprocessedCustomData[`avg_${key}`] = roundToDecimalPlaces(val / count, 6);\n\t\t\tprocessedCustomData[`max_${key}`] = dataMaxes[key] ?? 0;\n\t\t}\n\n\t\treturn processedCustomData;\n\t}\n\n\tprivate flushBucket(bucket: string): void {\n\t\tconst loggerData = this.measurementsMap.get(bucket);\n\t\tif (loggerData === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst measurements = loggerData.measurements;\n\n\t\tconst processedCustomData = this.processCustomData(loggerData, measurements.count);\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\t...processedCustomData,\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"]}
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 { performanceNow } from \"@fluid-internal/client-utils\";\nimport type { IDisposable, ITelemetryBaseProperties } from \"@fluidframework/core-interfaces\";\nimport { assert } from \"@fluidframework/core-utils/internal\";\n\nimport { roundToDecimalPlaces } from \"./mathTools.js\";\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\t/**\n\t * Average duration across all the executions since the last event was generated.\n\t */\n\taverageDuration?: number;\n}\n\n/**\n * The data that will be logged in the telemetry event.\n */\ninterface LoggerData {\n\tmeasurements: Measurements;\n\n\t/**\n\t * The sum of the custom data passed into the logger for each key.\n\t * Absence of a given key should be interpreted as 0.\n\t */\n\tdataSums: Record<string, number>;\n\n\t/**\n\t * The max of the custom data passed into the logger for each key.\n\t */\n\tdataMaxes: Record<string, number>;\n}\n\n/**\n * Helper type for an object whose properties are all numbers\n *\n * @internal\n */\nexport type CustomMetrics<TKey> = {\n\t[K in keyof TKey]: K extends string ? number : never;\n};\n\n/**\n * Potentially part of the structure of the return value of the function provided to {@link SampledTelemetryHelper.measure}.\n *\n * @see {@link MeasureReturnType} for more details on how this type is used.\n *\n * @internal\n */\nexport interface ICustomData<T> {\n\tcustomData: CustomMetrics<T>;\n}\n\n/**\n * Encapsulates the type-level logic for {@link SampledTelemetryHelper.measure}, to determine the expected return type\n * for the function that method receives (and by extension, its own return type). In words: {@link SampledTelemetryHelper}\n * is optionally provided with two generic types: one for custom metrics, and one for the actual return value of the\n * code that will be measured.\n *\n * - If no generic type is provided for custom metrics, then this type is simply the generic type provided for the actual\n * return value of the measured code (which could be void!).\n * - If a generic type is provided for custom metrics, then this type has a `customData` property whose type matches that\n * generic. Then if the generic type for the actual return value is not void, this type also has a property `returnValue`\n * whose type matches the generic type for the actual return value; if the generic type for the actual return value is\n * void, then this type _forbids_ a `returnValue` property (technically, it can exist but must be undefined in that case),\n * to try to ensure that the caller doesn't accidentally provide a function that actually returns a value.\n *\n * @internal\n */\nexport type MeasureReturnType<TMeasureReturn, TCustomMetrics> = TCustomMetrics extends void\n\t? TMeasureReturn\n\t: ICustomData<TCustomMetrics> &\n\t\t\t(TMeasureReturn extends void\n\t\t\t\t? Partial<Record<\"returnValue\", never>>\n\t\t\t\t: { returnValue: TMeasureReturn });\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 * @remarks\n * The `duration` field in the telemetry event this class generates is the duration of the latest execution (sample)\n * of the specified code block.\n * See the documentation of the `includeAggregateMetrics` parameter for additional details that can be included.\n *\n * @typeParam TMeasurementReturn - The return type (in a vacuum) of the code block that will be measured, ignoring\n * any custom metric data that might be required by this class. E.g., the code might just return a boolean.\n * @typeParam TCustomMetrics - A type that contains the custom properties that will be used by an instance of this class\n * for custom metrics. Each property in this type should be a number.\n *\n * @internal\n */\nexport class SampledTelemetryHelper<\n\tTMeasureReturn = void,\n\tTCustomMetrics extends CustomMetrics<TCustomMetrics> = void,\n> implements IDisposable\n{\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, LoggerData>();\n\n\t/**\n\t * @param eventBase - Custom properties to include in the telemetry performance event when it is written.\n\t * @param logger - The logger to use to write the telemetry performance event.\n\t * @param sampleThreshold - Telemetry performance events will be generated every time we hit this many executions\n\t * of the code block.\n\t * @param includeAggregateMetrics - If set to `true`, the telemetry performance event will include aggregated\n\t * metrics (total duration, min duration, max duration) for all the executions in between generated events.\n\t * @param perBucketProperties - Map of strings that represent different buckets (which can be specified when calling\n\t * the 'measure' method), to properties which should be added to the telemetry event for that bucket.\n\t * If a bucket being measured does not have an entry in this map, no additional properties will be added to its\n\t * telemetry events. The following keys are reserved for use by this class: \"duration\", \"count\", \"totalDuration\",\n\t * \"minDuration\", \"maxDuration\". If any of them is specified as a key in one of the ITelemetryBaseProperties objects\n\t * in this map, that key-value pair will be 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 * When it's been called enough times (the sampleThreshold for the class) then it generates a log message with the\n\t * necessary information.\n\t *\n\t * @remarks It's the responsibility of the caller to ensure that the same same set of custom metric properties is\n\t * provided each time this method is called on a given instance of {@link SampledTelemetryHelper}.\n\t * Otherwise the final measurements in the telemetry event may not be accurate.\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(\n\t\tcodeToMeasure: () => MeasureReturnType<TMeasureReturn, TCustomMetrics>,\n\t\tbucket: string = \"\",\n\t): MeasureReturnType<TMeasureReturn, TCustomMetrics> {\n\t\tconst start = performanceNow();\n\t\tconst returnValue = codeToMeasure();\n\t\tconst duration = performanceNow() - start;\n\n\t\tlet loggerData = this.measurementsMap.get(bucket);\n\t\tif (loggerData === undefined) {\n\t\t\tloggerData = {\n\t\t\t\tmeasurements: { count: 0, duration: -1 },\n\t\t\t\tdataSums: {},\n\t\t\t\tdataMaxes: {},\n\t\t\t};\n\t\t\tthis.measurementsMap.set(bucket, loggerData);\n\t\t}\n\n\t\tconst m = loggerData.measurements;\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 (this.isCustomData(returnValue)) {\n\t\t\tloggerData = this.accumulateCustomData(returnValue.customData, loggerData);\n\t\t}\n\n\t\tif (m.count >= this.sampleThreshold) {\n\t\t\t// Computed separately to avoid multiple division operations.\n\t\t\tif (this.includeAggregateMetrics) {\n\t\t\t\tm.averageDuration = (m.totalDuration ?? 0) / m.count;\n\t\t\t}\n\t\t\tthis.flushBucket(bucket);\n\t\t}\n\n\t\treturn returnValue;\n\t}\n\n\tprivate isCustomData(data: unknown): data is ICustomData<TCustomMetrics> {\n\t\treturn (\n\t\t\ttypeof data === \"object\" &&\n\t\t\tdata !== null &&\n\t\t\t\"customData\" in data &&\n\t\t\ttypeof data.customData === \"object\"\n\t\t);\n\t}\n\n\tprivate accumulateCustomData(\n\t\tcustomData: CustomMetrics<TCustomMetrics>,\n\t\tloggerData: LoggerData,\n\t): LoggerData {\n\t\tfor (const [key, val] of Object.entries(customData)) {\n\t\t\tassert(typeof key === \"string\", 0x9df /* Key should be a string */);\n\t\t\tassert(typeof val === \"number\", 0x9e0 /* Value should be a number */);\n\n\t\t\tloggerData.dataSums[key] = (loggerData.dataSums[key] ?? 0) + val;\n\t\t\tloggerData.dataMaxes[key] = Math.max(\n\t\t\t\tloggerData.dataMaxes[key] ?? Number.NEGATIVE_INFINITY,\n\t\t\t\tval,\n\t\t\t);\n\t\t}\n\n\t\treturn loggerData;\n\t}\n\n\tprivate processCustomData(loggerData: LoggerData, count: number): Record<string, number> {\n\t\tconst processedCustomData: Record<string, number> = {};\n\n\t\tif (loggerData.dataSums === undefined || loggerData.dataMaxes === undefined) {\n\t\t\treturn processedCustomData;\n\t\t}\n\n\t\tconst dataSums = loggerData.dataSums;\n\t\tconst dataMaxes = loggerData.dataMaxes;\n\n\t\tfor (const [key, val] of Object.entries(dataSums)) {\n\t\t\t// implementation of class guarantees the keys between dataMaxes and dataSums align.\n\t\t\tprocessedCustomData[`avg_${key}`] = roundToDecimalPlaces(val / count, 6);\n\t\t\tprocessedCustomData[`max_${key}`] = dataMaxes[key] ?? 0;\n\t\t}\n\n\t\treturn processedCustomData;\n\t}\n\n\tprivate flushBucket(bucket: string): void {\n\t\tconst loggerData = this.measurementsMap.get(bucket);\n\t\tif (loggerData === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst measurements = loggerData.measurements;\n\n\t\tconst processedCustomData = this.processCustomData(loggerData, measurements.count);\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\t...processedCustomData,\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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"telemetryEventBatcher.d.ts","sourceRoot":"","sources":["../src/telemetryEventBatcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,yBAAyB,EACzB,mBAAmB,EAEnB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;GAUG;AACH,qBAAa,qBAAqB,CAAC,QAAQ,SAAS,MAAM;IAiBxD;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM;IAEvB;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS;IA7B3B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAsC;IAEtD;;OAEG;IACH,OAAO,CAAC,SAAS,CAAsC;IAEvD;;OAEG;IACH,OAAO,CAAC,OAAO,CAAK;;IAGnB;;OAEG;IACc,SAAS,EAAE,yBAAyB;IAErD;;OAEG;IACc,MAAM,EAAE,mBAAmB;IAE5C;;OAEG;IACc,SAAS,EAAE,MAAM;IAGnC;;;;OAIG;IACI,gBAAgB,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,IAAI;IAgBnE,OAAO,CAAC,QAAQ;CAsBhB"}
1
+ {"version":3,"file":"telemetryEventBatcher.d.ts","sourceRoot":"","sources":["../src/telemetryEventBatcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACX,yBAAyB,EACzB,mBAAmB,EAEnB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;GAUG;AACH,qBAAa,qBAAqB,CAAC,QAAQ,SAAS,MAAM;IAiBxD;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM;IAEvB;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS;IA7B3B;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAyC;IAEzD;;OAEG;IACH,OAAO,CAAC,SAAS,CAAyC;IAE1D;;OAEG;IACH,OAAO,CAAC,OAAO,CAAK;;IAGnB;;OAEG;IACc,SAAS,EAAE,yBAAyB;IAErD;;OAEG;IACc,MAAM,EAAE,mBAAmB;IAE5C;;OAEG;IACc,SAAS,EAAE,MAAM;IAGnC;;;;OAIG;IACI,gBAAgB,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,IAAI;IAgBnE,OAAO,CAAC,QAAQ;CAsBhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"telemetryEventBatcher.js","sourceRoot":"","sources":["../src/telemetryEventBatcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAOtD;;;;;;;;;;GAUG;AACH,MAAM,OAAO,qBAAqB;IAgBjC;IACC;;OAEG;IACc,SAAoC;IAErD;;OAEG;IACc,MAA2B;IAE5C;;OAEG;IACc,SAAiB;QAVjB,cAAS,GAAT,SAAS,CAA2B;QAKpC,WAAM,GAAN,MAAM,CAAqB;QAK3B,cAAS,GAAT,SAAS,CAAQ;QA7BnC;;WAEG;QACK,aAAQ,GAAmC,EAAE,CAAC;QAEtD;;WAEG;QACK,cAAS,GAAmC,EAAE,CAAC;QAEvD;;WAEG;QACK,YAAO,GAAG,CAAC,CAAC;IAiBjB,CAAC;IAEJ;;;;OAIG;IACI,gBAAgB,CAAC,UAAoC;QAC3D,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAe,EAAE,CAAC;YACzD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;YACjE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAC7B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,iBAAiB,EAC/C,UAAU,CAAC,GAAG,CAAC,CACf,CAAC;QACH,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;QAEf,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjB,CAAC;IACF,CAAC;IAEO,QAAQ;QACf,MAAM,cAAc,GAAkC;YACrD,GAAG,IAAI,CAAC,SAAS;SACjB,CAAC;QAEF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAe,EAAE,CAAC;YAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YACnC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC3B,cAAc,CAAC,OAAO,GAAG,EAAE,CAAC,GAAG,oBAAoB,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAChF,CAAC;YACD,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;gBACvC,cAAc,CAAC,OAAO,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACpD,CAAC;QACF,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC;QAEjD,kCAAkC;QAClC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;IACrB,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { roundToDecimalPlaces } from \"./mathTools.js\";\nimport type {\n\tITelemetryGenericEventExt,\n\tITelemetryLoggerExt,\n\tITelemetryPerformanceEventExt,\n} from \"./telemetryTypes.js\";\n\n/**\n * Telemetry class that accumulates measurements which are eventually logged in a telemetry event through the provided\n * {@link TelemetryEventBatcher.logger | logger} when the number of calls to the function reaches the specified {@link TelemetryEventBatcher.threshold | threshold}.\n *\n * @remarks It is expected to be used for a single event type. If different properties should be logged at different times, a separate `TelemetryEventBatcher` should be created with separate `TMetrics` type.\n * @typeparam TMetrics - The set of keys that should be logged.\n * E.g., `keyof Foo` for logging properties `bar` and `baz` from `type Foo = { bar: number, baz: number }`.\n *\n * @sealed\n * @internal\n */\nexport class TelemetryEventBatcher<TMetrics extends string> {\n\t/**\n\t * Stores the sum of the custom data passed into the logger.\n\t */\n\tprivate dataSums: { [key in TMetrics]?: number } = {};\n\n\t/**\n\t * Stores the maximum value of the custom data passed into the logger.\n\t */\n\tprivate dataMaxes: { [key in TMetrics]?: number } = {};\n\n\t/**\n\t * Counter to keep track of the number of times the log function is called.\n\t */\n\tprivate counter = 0;\n\n\tpublic constructor(\n\t\t/**\n\t\t * Custom properties to include in the telemetry performance event when it is written.\n\t\t */\n\t\tprivate readonly eventBase: ITelemetryGenericEventExt,\n\n\t\t/**\n\t\t * The logger to use to write the telemetry performance event.\n\t\t */\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\n\t\t/**\n\t\t * The number of logs to accumulate before sending the data to the logger.\n\t\t */\n\t\tprivate readonly threshold: number,\n\t) {}\n\n\t/**\n\t * Accumulates the custom data and sends it to the logger every {@link TelemetryEventBatcher.threshold} calls.\n\t *\n\t * @param customData - A record storing the custom data to be accumulated and eventually logged.\n\t */\n\tpublic accumulateAndLog(customData: Record<TMetrics, number>): void {\n\t\tfor (const key of Object.keys(customData) as TMetrics[]) {\n\t\t\tthis.dataSums[key] = (this.dataSums[key] ?? 0) + customData[key];\n\t\t\tthis.dataMaxes[key] = Math.max(\n\t\t\t\tthis.dataMaxes[key] ?? Number.NEGATIVE_INFINITY,\n\t\t\t\tcustomData[key],\n\t\t\t);\n\t\t}\n\n\t\tthis.counter++;\n\n\t\tif (this.counter >= this.threshold) {\n\t\t\tthis.sendData();\n\t\t}\n\t}\n\n\tprivate sendData(): void {\n\t\tconst telemetryEvent: ITelemetryPerformanceEventExt = {\n\t\t\t...this.eventBase,\n\t\t};\n\n\t\tfor (const key of Object.keys(this.dataSums) as TMetrics[]) {\n\t\t\tconst dataSum = this.dataSums[key];\n\t\t\tif (dataSum !== undefined) {\n\t\t\t\ttelemetryEvent[`avg_${key}`] = roundToDecimalPlaces(dataSum / this.counter, 6);\n\t\t\t}\n\t\t\tif (this.dataMaxes[key] !== undefined) {\n\t\t\t\ttelemetryEvent[`max_${key}`] = this.dataMaxes[key];\n\t\t\t}\n\t\t}\n\n\t\tthis.logger.sendPerformanceEvent(telemetryEvent);\n\n\t\t// Reset the counter and the data.\n\t\tthis.counter = 0;\n\t\tthis.dataSums = {};\n\t\tthis.dataMaxes = {};\n\t}\n}\n"]}
1
+ {"version":3,"file":"telemetryEventBatcher.js","sourceRoot":"","sources":["../src/telemetryEventBatcher.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAOtD;;;;;;;;;;GAUG;AACH,MAAM,OAAO,qBAAqB;IAgBjC;IACC;;OAEG;IACc,SAAoC;IAErD;;OAEG;IACc,MAA2B;IAE5C;;OAEG;IACc,SAAiB;QAVjB,cAAS,GAAT,SAAS,CAA2B;QAKpC,WAAM,GAAN,MAAM,CAAqB;QAK3B,cAAS,GAAT,SAAS,CAAQ;QA7BnC;;WAEG;QACK,aAAQ,GAAsC,EAAE,CAAC;QAEzD;;WAEG;QACK,cAAS,GAAsC,EAAE,CAAC;QAE1D;;WAEG;QACK,YAAO,GAAG,CAAC,CAAC;IAiBjB,CAAC;IAEJ;;;;OAIG;IACI,gBAAgB,CAAC,UAAoC;QAC3D,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAe,EAAE,CAAC;YACzD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;YACjE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAC7B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,iBAAiB,EAC/C,UAAU,CAAC,GAAG,CAAC,CACf,CAAC;QACH,CAAC;QAED,IAAI,CAAC,OAAO,EAAE,CAAC;QAEf,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjB,CAAC;IACF,CAAC;IAEO,QAAQ;QACf,MAAM,cAAc,GAAkC;YACrD,GAAG,IAAI,CAAC,SAAS;SACjB,CAAC;QAEF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAe,EAAE,CAAC;YAC5D,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YACnC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC3B,cAAc,CAAC,OAAO,GAAG,EAAE,CAAC,GAAG,oBAAoB,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAChF,CAAC;YACD,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;gBACvC,cAAc,CAAC,OAAO,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YACpD,CAAC;QACF,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC;QAEjD,kCAAkC;QAClC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;IACrB,CAAC;CACD","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { roundToDecimalPlaces } from \"./mathTools.js\";\nimport type {\n\tITelemetryGenericEventExt,\n\tITelemetryLoggerExt,\n\tITelemetryPerformanceEventExt,\n} from \"./telemetryTypes.js\";\n\n/**\n * Telemetry class that accumulates measurements which are eventually logged in a telemetry event through the provided\n * {@link TelemetryEventBatcher.logger | logger} when the number of calls to the function reaches the specified {@link TelemetryEventBatcher.threshold | threshold}.\n *\n * @remarks It is expected to be used for a single event type. If different properties should be logged at different times, a separate `TelemetryEventBatcher` should be created with separate `TMetrics` type.\n * @typeparam TMetrics - The set of keys that should be logged.\n * E.g., `keyof Foo` for logging properties `bar` and `baz` from `type Foo = { bar: number, baz: number }`.\n *\n * @sealed\n * @internal\n */\nexport class TelemetryEventBatcher<TMetrics extends string> {\n\t/**\n\t * Stores the sum of the custom data passed into the logger.\n\t */\n\tprivate dataSums: Partial<Record<TMetrics, number>> = {};\n\n\t/**\n\t * Stores the maximum value of the custom data passed into the logger.\n\t */\n\tprivate dataMaxes: Partial<Record<TMetrics, number>> = {};\n\n\t/**\n\t * Counter to keep track of the number of times the log function is called.\n\t */\n\tprivate counter = 0;\n\n\tpublic constructor(\n\t\t/**\n\t\t * Custom properties to include in the telemetry performance event when it is written.\n\t\t */\n\t\tprivate readonly eventBase: ITelemetryGenericEventExt,\n\n\t\t/**\n\t\t * The logger to use to write the telemetry performance event.\n\t\t */\n\t\tprivate readonly logger: ITelemetryLoggerExt,\n\n\t\t/**\n\t\t * The number of logs to accumulate before sending the data to the logger.\n\t\t */\n\t\tprivate readonly threshold: number,\n\t) {}\n\n\t/**\n\t * Accumulates the custom data and sends it to the logger every {@link TelemetryEventBatcher.threshold} calls.\n\t *\n\t * @param customData - A record storing the custom data to be accumulated and eventually logged.\n\t */\n\tpublic accumulateAndLog(customData: Record<TMetrics, number>): void {\n\t\tfor (const key of Object.keys(customData) as TMetrics[]) {\n\t\t\tthis.dataSums[key] = (this.dataSums[key] ?? 0) + customData[key];\n\t\t\tthis.dataMaxes[key] = Math.max(\n\t\t\t\tthis.dataMaxes[key] ?? Number.NEGATIVE_INFINITY,\n\t\t\t\tcustomData[key],\n\t\t\t);\n\t\t}\n\n\t\tthis.counter++;\n\n\t\tif (this.counter >= this.threshold) {\n\t\t\tthis.sendData();\n\t\t}\n\t}\n\n\tprivate sendData(): void {\n\t\tconst telemetryEvent: ITelemetryPerformanceEventExt = {\n\t\t\t...this.eventBase,\n\t\t};\n\n\t\tfor (const key of Object.keys(this.dataSums) as TMetrics[]) {\n\t\t\tconst dataSum = this.dataSums[key];\n\t\t\tif (dataSum !== undefined) {\n\t\t\t\ttelemetryEvent[`avg_${key}`] = roundToDecimalPlaces(dataSum / this.counter, 6);\n\t\t\t}\n\t\t\tif (this.dataMaxes[key] !== undefined) {\n\t\t\t\ttelemetryEvent[`max_${key}`] = this.dataMaxes[key];\n\t\t\t}\n\t\t}\n\n\t\tthis.logger.sendPerformanceEvent(telemetryEvent);\n\n\t\t// Reset the counter and the data.\n\t\tthis.counter = 0;\n\t\tthis.dataSums = {};\n\t\tthis.dataMaxes = {};\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/telemetry-utils",
3
- "version": "2.72.0",
3
+ "version": "2.74.0-365691",
4
4
  "description": "Collection of telemetry relates utilities for Fluid",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -69,22 +69,22 @@
69
69
  "temp-directory": "nyc/.nyc_output"
70
70
  },
71
71
  "dependencies": {
72
- "@fluid-internal/client-utils": "~2.72.0",
73
- "@fluidframework/core-interfaces": "~2.72.0",
74
- "@fluidframework/core-utils": "~2.72.0",
75
- "@fluidframework/driver-definitions": "~2.72.0",
72
+ "@fluid-internal/client-utils": "2.74.0-365691",
73
+ "@fluidframework/core-interfaces": "2.74.0-365691",
74
+ "@fluidframework/core-utils": "2.74.0-365691",
75
+ "@fluidframework/driver-definitions": "2.74.0-365691",
76
76
  "debug": "^4.3.4",
77
77
  "uuid": "^11.1.0"
78
78
  },
79
79
  "devDependencies": {
80
80
  "@arethetypeswrong/cli": "^0.17.1",
81
81
  "@biomejs/biome": "~1.9.3",
82
- "@fluid-internal/mocha-test-setup": "~2.72.0",
82
+ "@fluid-internal/mocha-test-setup": "2.74.0-365691",
83
83
  "@fluid-tools/build-cli": "^0.60.0",
84
84
  "@fluidframework/build-common": "^2.0.3",
85
85
  "@fluidframework/build-tools": "^0.60.0",
86
- "@fluidframework/eslint-config-fluid": "~2.72.0",
87
- "@fluidframework/telemetry-utils-previous": "npm:@fluidframework/telemetry-utils@2.71.0",
86
+ "@fluidframework/eslint-config-fluid": "2.74.0-365691",
87
+ "@fluidframework/telemetry-utils-previous": "npm:@fluidframework/telemetry-utils@2.73.0",
88
88
  "@microsoft/api-extractor": "7.52.11",
89
89
  "@types/debug": "^4.1.5",
90
90
  "@types/mocha": "^10.0.10",
@@ -111,7 +111,7 @@ export type MeasureReturnType<TMeasureReturn, TCustomMetrics> = TCustomMetrics e
111
111
  ? TMeasureReturn
112
112
  : ICustomData<TCustomMetrics> &
113
113
  (TMeasureReturn extends void
114
- ? { [K in "returnValue"]?: never }
114
+ ? Partial<Record<"returnValue", never>>
115
115
  : { returnValue: TMeasureReturn });
116
116
 
117
117
  /**
@@ -25,12 +25,12 @@ export class TelemetryEventBatcher<TMetrics extends string> {
25
25
  /**
26
26
  * Stores the sum of the custom data passed into the logger.
27
27
  */
28
- private dataSums: { [key in TMetrics]?: number } = {};
28
+ private dataSums: Partial<Record<TMetrics, number>> = {};
29
29
 
30
30
  /**
31
31
  * Stores the maximum value of the custom data passed into the logger.
32
32
  */
33
- private dataMaxes: { [key in TMetrics]?: number } = {};
33
+ private dataMaxes: Partial<Record<TMetrics, number>> = {};
34
34
 
35
35
  /**
36
36
  * Counter to keep track of the number of times the log function is called.