@microsoft/compose-language-service
Version:
Language service for Docker Compose documents
138 lines • 6.13 kB
JavaScript
;
/*!--------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.TelemetryAggregator = void 0;
const util = __importStar(require("util"));
const TelemetryEvent_1 = require("../../../common/TelemetryEvent");
const logNormal_1 = require("./logNormal");
// One minute flush interval by default
const FlushIntervalMilliseconds = 60 * 1000;
class TelemetryAggregator {
connection;
interval;
eventBuffer = [];
timer;
constructor(connection, interval = FlushIntervalMilliseconds) {
this.connection = connection;
this.interval = interval;
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) {
const error = err instanceof Error ? err : Error(util.inspect(err));
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 => e.measurements.duration).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