@fluidframework/telemetry-utils
Advanced tools
@@ -41,5 +41,3 @@ /*! | ||
| */ | ||
| export type MeasureReturnType<TMeasureReturn, TCustomMetrics> = TCustomMetrics extends void ? TMeasureReturn : ICustomData<TCustomMetrics> & (TMeasureReturn extends void ? { | ||
| [K in "returnValue"]?: never; | ||
| } : { | ||
| export type MeasureReturnType<TMeasureReturn, TCustomMetrics> = TCustomMetrics extends void ? TMeasureReturn : ICustomData<TCustomMetrics> & (TMeasureReturn extends void ? Partial<Record<"returnValue", never>> : { | ||
| returnValue: TMeasureReturn; | ||
@@ -46,0 +44,0 @@ }); |
@@ -1,1 +0,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"} | ||
| {"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 +0,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"]} | ||
| {"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 +0,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"} | ||
| {"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 +0,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"]} | ||
| {"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"]} |
@@ -41,5 +41,3 @@ /*! | ||
| */ | ||
| export type MeasureReturnType<TMeasureReturn, TCustomMetrics> = TCustomMetrics extends void ? TMeasureReturn : ICustomData<TCustomMetrics> & (TMeasureReturn extends void ? { | ||
| [K in "returnValue"]?: never; | ||
| } : { | ||
| export type MeasureReturnType<TMeasureReturn, TCustomMetrics> = TCustomMetrics extends void ? TMeasureReturn : ICustomData<TCustomMetrics> & (TMeasureReturn extends void ? Partial<Record<"returnValue", never>> : { | ||
| returnValue: TMeasureReturn; | ||
@@ -46,0 +44,0 @@ }); |
@@ -1,1 +0,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"} | ||
| {"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 +0,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"]} | ||
| {"version":3,"file":"sampledTelemetryHelper.js","sourceRoot":"","sources":["../src/sampledTelemetryHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAC;AAE7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AA2GtD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,sBAAsB;IAOlC;;OAEG;IACH,IAAW,QAAQ;QAClB,OAAO,IAAI,CAAC,SAAS,CAAC;IACvB,CAAC;IAID;;;;;;;;;;;;;OAaG;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;QA9B3E,cAAS,GAAY,KAAK,CAAC;QASlB,oBAAe,GAAG,IAAI,GAAG,EAAsB,CAAC;IAsB9D,CAAC;IAEJ;;;;;;;;;;;;;;OAcG;IACI,OAAO,CACb,aAAsE,EACtE,SAAiB,EAAE;QAEnB,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;QAC/B,MAAM,WAAW,GAAG,aAAa,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,cAAc,EAAE,GAAG,KAAK,CAAC;QAE1C,IAAI,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC9B,UAAU,GAAG;gBACZ,YAAY,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE;gBACxC,QAAQ,EAAE,EAAE;gBACZ,SAAS,EAAE,EAAE;aACb,CAAC;YACF,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAC9C,CAAC;QAED,MAAM,CAAC,GAAG,UAAU,CAAC,YAAY,CAAC;QAClC,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,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,CAAC;YACpC,UAAU,GAAG,IAAI,CAAC,oBAAoB,CAAC,WAAW,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAC5E,CAAC;QAED,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACrC,6DAA6D;YAC7D,IAAI,IAAI,CAAC,uBAAuB,EAAE,CAAC;gBAClC,CAAC,CAAC,eAAe,GAAG,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;YACtD,CAAC;YACD,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;QAED,OAAO,WAAW,CAAC;IACpB,CAAC;IAEO,YAAY,CAAC,IAAa;QACjC,OAAO,CACN,OAAO,IAAI,KAAK,QAAQ;YACxB,IAAI,KAAK,IAAI;YACb,YAAY,IAAI,IAAI;YACpB,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,CACnC,CAAC;IACH,CAAC;IAEO,oBAAoB,CAC3B,UAAyC,EACzC,UAAsB;QAEtB,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YACrD,MAAM,CAAC,OAAO,GAAG,KAAK,QAAQ,EAAE,KAAK,CAAC,4BAA4B,CAAC,CAAC;YACpE,MAAM,CAAC,OAAO,GAAG,KAAK,QAAQ,EAAE,KAAK,CAAC,8BAA8B,CAAC,CAAC;YAEtE,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC;YACjE,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CACnC,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,iBAAiB,EACrD,GAAG,CACH,CAAC;QACH,CAAC;QAED,OAAO,UAAU,CAAC;IACnB,CAAC;IAEO,iBAAiB,CAAC,UAAsB,EAAE,KAAa;QAC9D,MAAM,mBAAmB,GAA2B,EAAE,CAAC;QAEvD,IAAI,UAAU,CAAC,QAAQ,KAAK,SAAS,IAAI,UAAU,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YAC7E,OAAO,mBAAmB,CAAC;QAC5B,CAAC;QAED,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC;QACrC,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC;QAEvC,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACnD,oFAAoF;YACpF,mBAAmB,CAAC,OAAO,GAAG,EAAE,CAAC,GAAG,oBAAoB,CAAC,GAAG,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC;YACzE,mBAAmB,CAAC,OAAO,GAAG,EAAE,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzD,CAAC;QAED,OAAO,mBAAmB,CAAC;IAC5B,CAAC;IAEO,WAAW,CAAC,MAAc;QACjC,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO;QACR,CAAC;QAED,MAAM,YAAY,GAAG,UAAU,CAAC,YAAY,CAAC;QAE7C,MAAM,mBAAmB,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QAEnF,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;gBACf,GAAG,mBAAmB;aACtB,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,EAAE,CAAC;YAClD,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACvB,CAAC;CACD","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 +0,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"} | ||
| {"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 +0,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"]} | ||
| {"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"]} |
+8
-8
| { | ||
| "name": "@fluidframework/telemetry-utils", | ||
| "version": "2.73.0", | ||
| "version": "2.74.0-365691", | ||
| "description": "Collection of telemetry relates utilities for Fluid", | ||
@@ -72,6 +72,6 @@ "homepage": "https://fluidframework.com", | ||
| "dependencies": { | ||
| "@fluid-internal/client-utils": "~2.73.0", | ||
| "@fluidframework/core-interfaces": "~2.73.0", | ||
| "@fluidframework/core-utils": "~2.73.0", | ||
| "@fluidframework/driver-definitions": "~2.73.0", | ||
| "@fluid-internal/client-utils": "2.74.0-365691", | ||
| "@fluidframework/core-interfaces": "2.74.0-365691", | ||
| "@fluidframework/core-utils": "2.74.0-365691", | ||
| "@fluidframework/driver-definitions": "2.74.0-365691", | ||
| "debug": "^4.3.4", | ||
@@ -83,8 +83,8 @@ "uuid": "^11.1.0" | ||
| "@biomejs/biome": "~1.9.3", | ||
| "@fluid-internal/mocha-test-setup": "~2.73.0", | ||
| "@fluid-internal/mocha-test-setup": "2.74.0-365691", | ||
| "@fluid-tools/build-cli": "^0.60.0", | ||
| "@fluidframework/build-common": "^2.0.3", | ||
| "@fluidframework/build-tools": "^0.60.0", | ||
| "@fluidframework/eslint-config-fluid": "~2.73.0", | ||
| "@fluidframework/telemetry-utils-previous": "npm:@fluidframework/telemetry-utils@2.71.0", | ||
| "@fluidframework/eslint-config-fluid": "2.74.0-365691", | ||
| "@fluidframework/telemetry-utils-previous": "npm:@fluidframework/telemetry-utils@2.73.0", | ||
| "@microsoft/api-extractor": "7.52.11", | ||
@@ -91,0 +91,0 @@ "@types/debug": "^4.1.5", |
@@ -114,3 +114,3 @@ /*! | ||
| (TMeasureReturn extends void | ||
| ? { [K in "returnValue"]?: never } | ||
| ? Partial<Record<"returnValue", never>> | ||
| : { returnValue: TMeasureReturn }); | ||
@@ -117,0 +117,0 @@ |
@@ -28,3 +28,3 @@ /*! | ||
| */ | ||
| private dataSums: { [key in TMetrics]?: number } = {}; | ||
| private dataSums: Partial<Record<TMetrics, number>> = {}; | ||
@@ -34,3 +34,3 @@ /** | ||
| */ | ||
| private dataMaxes: { [key in TMetrics]?: number } = {}; | ||
| private dataMaxes: Partial<Record<TMetrics, number>> = {}; | ||
@@ -37,0 +37,0 @@ /** |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
942921
0.01%11626
-0.03%1
Infinity%+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed