twilio-video
Version:
Twilio Video JavaScript Library
179 lines (156 loc) • 5.32 kB
JavaScript
'use strict';
const NetworkEvents = require('./events/network');
const GetUserMediaEvents = require('./events/getusermedia');
const QualityEvents = require('./events/quality');
const TrackEvents = require('./events/track');
const ApplicationEvents = require('./events/application');
const SystemEvents = require('./events/system');
const PeerConnectionEvents = require('./events/peerconnection');
const RoomEvents = require('./events/room');
/**
* @typedef {Object} InsightsPublisher
* @property {(group: string, name: string, payload: Record<string, any>) => void} publish
*/
/**
* @typedef {Object} TelemetryEventOptions
* @property {string} group - Event group
* @property {string} name - Event name
* @property {Record<string, any>} [payload] - Optional event payload
*/
/**
* @typedef {Object} TelemetryConfig
* @property {InsightsPublisher} publisher - The insights publisher to register
* @property {import('../util/log')} log - Logger instance
* @property {number} connectTimestamp - Connection timestamp
*/
/**
* Telemetry is a singleton for emitting telemetry events throughout the SDK.
* It decouples event emission from publisher management, allowing different parts of the SDK
* to emit events without direct coupling.
* @internal
*/
class Telemetry {
constructor() {
/** @type {InsightsPublisher | null} */
this._publisher = null;
/** @type {number | null} */
this._connectTimestamp = null;
/** @type {import('../util/log') | null} */
this._log = null;
/** @type {boolean} */
this._isConfigured = false;
/** @type {NetworkEvents} */
this.network = new NetworkEvents(this);
/** @type {GetUserMediaEvents} */
this.getUserMedia = new GetUserMediaEvents(this);
/** @type {QualityEvents} */
this.quality = new QualityEvents(this);
/** @type {TrackEvents} */
this.track = new TrackEvents(this);
/** @type {ApplicationEvents} */
this.application = new ApplicationEvents(this);
/** @type {SystemEvents} */
this.system = new SystemEvents(this);
/** @type {PeerConnectionEvents} */
this.pc = new PeerConnectionEvents(this);
/** @type {RoomEvents} */
this.room = new RoomEvents(this);
}
/**
* Configure telemetry with a publisher.
*
* @param {TelemetryConfig} config - Configuration options
* @returns {Telemetry}
*/
configure({ publisher, log, connectTimestamp }) {
if (!publisher || !log || typeof connectTimestamp !== 'number') {
throw new Error('Telemetry.configure requires publisher, log, and connectTimestamp');
}
this._publisher = publisher;
this._log = log;
this._connectTimestamp = connectTimestamp;
this._isConfigured = true;
this._publisher.on('connected', () => {
this._log.debug('Telemetry publisher connected.');
});
this._publisher.on('reconnecting', () => {
this._log.warn('Telemetry publisher reconnecting...');
});
return this;
}
/**
* Internal method to emit a telemetry event. If no publisher is registered, the event is ignored.
* Used by the public info/warning/error methods.
* @private
* @param {string} group - Event group (e.g., 'get-user-media', 'quality', 'network')
* @param {string} name - Event name (e.g., 'succeeded', 'failed')
* @param {('info'|'warning'|'error'|'debug')} level - Event level
* @param {Record<string, any>} [payload] - Optional event payload
* @returns {void}
*/
_emit(group, name, level, payload) {
if (!this._isConfigured) {
return;
}
const timestamp = Date.now();
const elapsedTime = timestamp - this._connectTimestamp;
const publisherPayload = Object.assign({ elapsedTime, level }, payload || {});
const published = this._publisher.publish(group, name, publisherPayload);
if (!published) {
this._log.warn(`Telemetry event "${group}:${name}" dropped - publisher unavailable.`);
return;
}
const event = Object.assign({
elapsedTime,
group,
level,
name,
timestamp
}, payload ? { payload } : {});
/** @type {'debug' | 'error' | 'info' | 'warn'} */
const logLevel = /** @type {const} */ ({
debug: 'debug',
error: 'error',
info: 'info',
warning: 'warn'
})[level];
this._log[logLevel]('telemetry', event);
}
/**
* Emit an info-level telemetry event.
*
* @param {TelemetryEventOptions} options - Event options
* @returns {void}
*/
info({ group, name, payload }) {
return this._emit(group, name, 'info', payload);
}
/**
* Emit a warning-level telemetry event.
*
* @param {TelemetryEventOptions} options - Event options
* @returns {void}
*/
warning({ group, name, payload }) {
return this._emit(group, name, 'warning', payload);
}
/**
* Emit an error-level telemetry event.
*
* @param {TelemetryEventOptions} options - Event options
* @returns {void}
*/
error({ group, name, payload }) {
return this._emit(group, name, 'error', payload);
}
/**
* Emit a debug-level telemetry event.
*
* @param {TelemetryEventOptions} options - Event options
* @returns {void}
*/
debug({ group, name, payload }) {
return this._emit(group, name, 'debug', payload);
}
}
module.exports = new Telemetry();