@microsoft/compose-language-service
Version:
Language service for Docker Compose documents
102 lines • 4.84 kB
JavaScript
;
/*!--------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.TelemetryAggregator = void 0;
const TelemetryEvent_1 = require("../../../client/TelemetryEvent");
const logNormal_1 = require("./logNormal");
// One minute flush interval by default
const FlushIntervalMilliseconds = 60 * 1000;
class TelemetryAggregator {
constructor(connection, interval = FlushIntervalMilliseconds) {
this.connection = connection;
this.interval = interval;
this.eventBuffer = [];
this.timer = setInterval(() => this.flush(), this.interval);
}
dispose() {
clearInterval(this.timer);
// Flush one last time
this.flush();
}
logEvent(event) {
if (event.suppressAll) {
// Do nothing, this event is suppressed
}
else if (event.properties.result === 'Succeeded' && event.suppressIfSuccessful) {
// Do nothing, the event succeeded and has suppressIfSuccessful === true
}
else if (event.properties.result === 'Failed') {
// Event is an error, send immediately rather than buffering
this.connection.telemetry.logEvent(event);
}
else {
// Add it to the event buffer to be flushed on the interval
this.eventBuffer.push(event);
}
}
flush() {
try {
for (const evt of this.getAggregatedEvents()) {
this.connection.telemetry.logEvent(evt);
}
}
catch (err) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const error = err instanceof Error ? err : Error(err.toString());
const telemetryFailedEvent = (0, TelemetryEvent_1.initEvent)('telemetryaggregatorfailure');
telemetryFailedEvent.properties.result = 'Failed';
telemetryFailedEvent.properties.error = error.name;
telemetryFailedEvent.properties.errorMessage = error.message;
telemetryFailedEvent.properties.stack = error.stack;
this.connection.telemetry.logEvent(telemetryFailedEvent);
}
finally {
// Finally, clear out the buffer
this.eventBuffer = [];
}
}
getAggregatedEvents() {
const aggregated = [];
const eventGroups = new Map();
// Group events according to their grouping strategy
for (const evt of this.eventBuffer) {
let key;
switch (evt.groupingStrategy) {
case 'eventNameAndProperties':
key = evt.eventName + JSON.stringify(evt.properties);
break;
case 'eventName':
default:
key = evt.eventName;
break;
}
if (!eventGroups.has(key)) {
eventGroups.set(key, []);
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
eventGroups.get(key).push(evt);
}
// For each group, aggregate properties and add performance statistics, to get one aggregated event per group
for (const events of eventGroups.values()) {
const eventName = events[0].eventName;
const aggregatedEvent = (0, TelemetryEvent_1.initEvent)(eventName);
// Aggregate the performance statistics
const durations = events.map(e => { var _a; return (_a = e.measurements.duration) !== null && _a !== void 0 ? _a : undefined; }).filter(d => d !== undefined) || [];
const stats = (0, logNormal_1.logNormal)(durations);
aggregatedEvent.measurements.count = events.length;
aggregatedEvent.measurements.durationMu = stats.mu;
aggregatedEvent.measurements.durationSigma = stats.sigma;
aggregatedEvent.measurements.durationMedian = stats.median;
// Aggregate the properties--this will apply all properties from all events, with the recent events overriding prior events if there is a conflict
// If the grouping strategy is 'eventNameAndProperties', there will inherently never be conflicts, since their values must be identical
events.forEach(evt => Object.assign(aggregatedEvent.properties, evt.properties));
aggregated.push(aggregatedEvent);
}
return aggregated;
}
}
exports.TelemetryAggregator = TelemetryAggregator;
//# sourceMappingURL=TelemetryAggregator.js.map