Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/client-telemetry-pipeline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'livekit-client': minor
---

Client telemetry: the SDK can now report its own sessions as OTLP to a collector — `lk.connect` and `lk.reconnect` spans with their checkpoints, `lk.publish` and `lk.subscribe`, `lk.rtc.stats.sample` windows folded from the readings the track monitors already take, `lk.room.disconnected`, and the device state a page can observe. Records are batched write-ahead into a cache and uploaded under a policy that never lets telemetry win over media: one request in flight, holds while connecting, a 429 that keeps its batch, and a per-tick budget for replaying a backlog. Off unless `Telemetry.configure({ endpoint })` is called or the room is on LiveKit Cloud, which derives the route and the token from the connect. See TELEMETRY.md.
5 changes: 4 additions & 1 deletion .size-limit.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ module.exports = [
{
path: 'dist/livekit-client.umd.js',
import: '{ Room }',
limit: '130 kB',
// Telemetry costs +8.95 kB brotli, and UMD cannot shake it out: 130 kB no longer fits.
// Raising it is one of two answers — the other is a separate UMD entry point, as the
// e2ee and frame-metadata workers already have. See TELEMETRY.md.
limit: '135 kB',
},
];
282 changes: 282 additions & 0 deletions TELEMETRY.md

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"dependencies": {
"@livekit/mutex": "1.1.1",
"@livekit/protocol": "1.50.4",
"@opentelemetry/otlp-transformer": "0.222.0",
"events": "^3.3.0",
"jose": "^6.1.0",
"loglevel": "^1.9.2",
Expand All @@ -94,6 +95,7 @@
"@eslint/js": "10.0.1",
"@livekit/changesets-changelog-github": "^0.2.0",
"@livekit/throws-transformer": "^0.1.3",
"@nbilyk/downlevel-dts": "^0.15.2",
"@rollup/plugin-babel": "7.1.0",
"@rollup/plugin-commonjs": "29.0.3",
"@rollup/plugin-json": "6.1.0",
Expand All @@ -111,7 +113,6 @@
"@typescript/native": "catalog:",
"@vitest/browser": "^4.1.10",
"@vitest/browser-playwright": "^4.1.10",
"@nbilyk/downlevel-dts": "^0.15.2",
"eslint": "10.7.0",
"eslint-config-airbnb-extended": "^2.3.2",
"eslint-config-prettier": "10.1.8",
Expand Down
112 changes: 107 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,13 @@ export {
type SerializerOutput,
serializers,
} from './utils/serializer';

export {
Telemetry,
type TelemetryOptions,
// The one seam a platform SDK implements: where batches wait between being made and accepted.
type TelemetryStorage,
type TelemetryScope,
type TelemetrySpan,
type DeviceState as TelemetryDeviceState,
} from './telemetry';
12 changes: 8 additions & 4 deletions src/room/RTCEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit

private reconnectAttempts: number = 0;

/** Why the current reconnect started — the two events below carry it to telemetry. */
private reconnectReason?: ReconnectReason;

private reconnectStart: number = 0;

private clientConfiguration?: ClientConfiguration;
Expand Down Expand Up @@ -1307,6 +1310,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
if (this._isClosed) {
return;
}
this.reconnectReason = reason;
// guard for attempting reconnection multiple times while one attempt is still not finished
if (this.attemptingReconnect) {
this.log.warn('already attempting reconnect, returning early');
Expand Down Expand Up @@ -1404,7 +1408,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
}

this.log.info(`reconnecting, attempt: ${this.reconnectAttempts}`);
this.emit(EngineEvent.Restarting);
this.emit(EngineEvent.Restarting, this.reconnectReason);

if (!this.client.isDisconnected) {
await this.client.sendLeave();
Expand Down Expand Up @@ -1477,7 +1481,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
}

this.log.info(`resuming signal connection, attempt ${this.reconnectAttempts}`);
this.emit(EngineEvent.Resuming);
this.emit(EngineEvent.Resuming, this.reconnectReason);
let res: ReconnectResponse | undefined;
try {
this.setupSignalClientCallbacks();
Expand Down Expand Up @@ -2068,9 +2072,9 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
export type EngineEventCallbacks = {
connected: (joinResp: JoinResponse) => void;
disconnected: (reason?: DisconnectReason) => void;
resuming: () => void;
resuming: (reason?: ReconnectReason) => void;
resumed: () => void;
restarting: () => void;
restarting: (reason?: ReconnectReason) => void;
restarted: () => void;
signalResumed: () => void;
signalRestarted: (joinResp: JoinResponse) => void;
Expand Down
Loading
Loading