UNPKG

@microsoft/dev-tunnels-ssh

Version:

SSH library for Dev Tunnels

215 lines 8.49 kB
"use strict"; // // Copyright (c) Microsoft Corporation. All rights reserved. // Object.defineProperty(exports, "__esModule", { value: true }); exports.SessionMetrics = void 0; const vscode_jsonrpc_1 = require("vscode-jsonrpc"); const trace_1 = require("../trace"); /** * Collects current and cumulative measurements about a session. */ class SessionMetrics { /* @internal */ constructor() { this.startTime = 0; this.messagesSentCount = 0; this.messagesReceivedCount = 0; this.bytesSentSum = 0; this.bytesReceivedSum = 0; this.reconnectionsCount = 0; this.currentLatency = 0; this.minLatency = 0; this.maxLatency = 0; this.latencySum = 0; this.latencyCount = 0; this.messageSentEmitter = new vscode_jsonrpc_1.Emitter(); this.onMessageSent = this.messageSentEmitter.event; this.messageReceivedEmitter = new vscode_jsonrpc_1.Emitter(); this.onMessageReceived = this.messageReceivedEmitter.event; this.latencyUpdatedEmitter = new vscode_jsonrpc_1.Emitter(); this.onLatencyUpdated = this.latencyUpdatedEmitter.event; this.sessionClosedEmitter = new vscode_jsonrpc_1.Emitter(); this.onSessionClosed = this.sessionClosedEmitter.event; if (typeof performance === 'object' && typeof performance.now === 'function') { Object.defineProperty(this, 'time', { get: this.browserTime }); } else if (typeof process === 'object' && typeof process.hrtime === 'function') { Object.defineProperty(this, 'time', { get: this.nodejsTime }); } this.startTime = this.time; } /** * Gets the current stopwatch value in milliseconds (possibly including fractional milliseconds), * used for measuring latency. */ /* @internal */ get time() { // The SessionMetrics constructor may replace this with either of the below // high-precision implementations, depending on availability of platform APIs. return Date.now() - this.startTime; } browserTime() { // Use the browser high-resolution time API. // Note the precision may be reduced for pricacy depending on browser and page policy. return performance.now() - this.startTime; } nodejsTime() { // Use Node.js high-resolution time API. const [s, ns] = process.hrtime(); return s * 1000 + ns / 1000000 - this.startTime; } /** * Gets the total cumulative number of messages sent for the duration of the session, * including all channels and non-channel protocol messages. */ get messagesSent() { return this.messagesSentCount; } /** * Gets the total cumulative number of messages received for the duration of the session, * including all channels and non-channel protocol messages. */ get messagesReceived() { return this.messagesReceivedCount; } /** * Gets the total cumulative number of bytes sent for the duration of the session, * including all channels and non-channel protocol messages, and including message * framing, padding, and MAC bytes. */ get bytesSent() { return this.bytesSentSum; } /** * Gets the total cumulative number of bytes received for the duration of the session, * including all channels and non-channel protocol messages, and including message * framing, padding, and MAC bytes. */ get bytesReceived() { return this.bytesReceivedSum; } /** * Gets the number of times the session has reconnected. * </summary> * <remarks> * Reconnection requires both sides to support the * <see cref="SshProtocolExtensionNames.SessionReconnect" /> protocol extension. */ get reconnections() { return this.reconnectionsCount; } /** * Gets the average measured round-trip connection latency between client and server * over the duration of the session, in milliseconds. * </summary> * <remarks> * Latency measurement requires both sides to support the * <see cref="SshProtocolExtensionNames.SessionLatency" /> protocol extension. * If not supported, this Sum will be 0. */ get latencyAverageMs() { return this.latencyCount === 0 ? 0 : this.latencySum / this.latencyCount; } /** * Gets the minimum measured round-trip connection latency between client and server * over the duration of the session, in milliseconds. * </summary> * <remarks> * Latency measurement requires both sides to support the * <see cref="SshProtocolExtensionNames.SessionLatency" /> protocol extension. * If not supported, this Sum will be 0. */ get latencyMinMs() { return this.minLatency; } /** * Gets the maximum measured round-trip connection latency between client and server * over the duration of the session, in milliseconds. * </summary> * <remarks> * Latency measurement requires both sides to support the * <see cref="SshProtocolExtensionNames.SessionLatency" /> protocol extension. * If not supported, this Sum will be 0. */ get latencyMaxMs() { return this.maxLatency; } /** * Gets the most recent measurement of round-trip connection latency between client and * server, in milliseconds. * </summary> * <remarks> * Latency measurement requires both sides to support the * <see cref="SshProtocolExtensionNames.SessionLatency" /> protocol extension. * If not supported or the session is not currently connected, this Sum will be 0. */ get latencyCurrentMs() { return this.currentLatency; } /* @internal */ addMessageSent(size) { this.messagesSentCount++; this.bytesSentSum += size; this.messageSentEmitter.fire({ time: this.time, size }); } /* @internal */ addMessageReceived(size) { this.messagesReceivedCount++; this.bytesReceivedSum += size; this.messageReceivedEmitter.fire({ time: this.time, size }); } /* @internal */ addReconnection() { this.reconnectionsCount++; } /* @internal */ updateLatency(latencyMs, trace) { if (latencyMs < 0) { if (trace) { trace(trace_1.TraceLevel.Warning, trace_1.SshTraceEventIds.metricsError, `Measured latency was negative: ${latencyMs} us`); } return; } this.currentLatency = latencyMs; if (latencyMs === 0) { // Disconnected. return; } if (this.minLatency === 0 || latencyMs < this.minLatency) { this.minLatency = latencyMs; } if (this.maxLatency === 0 || latencyMs > this.maxLatency) { this.maxLatency = latencyMs; } // Enable computing the average. this.latencySum += latencyMs; this.latencyCount++; this.latencyUpdatedEmitter.fire({ time: this.time, latency: latencyMs }); } /* @internal */ close() { this.currentLatency = 0; this.sessionClosedEmitter.fire(); } toString() { let s = `Messages S/R: ${this.messagesSent} / ${this.messagesReceived}; ` + `Bytes S/R: ${this.bytesSent} / ${this.bytesReceived}; ` + `Reconnections: ${this.reconnections}; `; // Show extra precision for a low-latency connection. const precision = this.minLatency >= 10 ? 1 : this.minLatency >= 1 ? 10 : 100; if (this.maxLatency > 0) { const min = Math.round(this.minLatency * precision) / precision; const avg = Math.round((this.latencySum / this.latencyCount) * precision) / precision; const max = Math.round(this.maxLatency * precision) / precision; s += `Latency Min-Avg-Max: ${min} - ${avg} - ${max} ms; `; } if (this.currentLatency > 0) { const current = Math.round(this.currentLatency * precision) / precision; s += `Current Latency: ${current} ms; `; } return s; } } exports.SessionMetrics = SessionMetrics; //# sourceMappingURL=sessionMetrics.js.map