diff --git a/src/component/internal/messages.ts b/src/component/internal/messages.ts index 6d6ea193..7dbdbcac 100644 --- a/src/component/internal/messages.ts +++ b/src/component/internal/messages.ts @@ -56,10 +56,14 @@ export class NekoMessages extends EventEmitter { this._connection.websocket.on('message', async (event: string, payload: any) => { // @ts-ignore if (typeof this[event] === 'function') { - // @ts-ignore - this[event](payload) + try { + // @ts-ignore + this[event](payload) + } catch (error: any) { + this._log.error(`error while processing websocket event`, { event, error }) + } } else { - this._log.warn(`unhandled websocket event '${event}':`, payload) + this._log.warn(`unhandled websocket event`, { event, payload }) } }) @@ -74,7 +78,7 @@ export class NekoMessages extends EventEmitter { ///////////////////////////// protected [EVENT.SYSTEM_INIT](conf: message.SystemInit) { - this._log.debug('EVENT.SYSTEM_INIT') + this._log.debug(`EVENT.SYSTEM_INIT`) Vue.set(this._state, 'session_id', conf.session_id) Vue.set(this._state.control, 'implicit_hosting', conf.implicit_hosting) Vue.set(this._state.connection, 'screencast', conf.screencast_enabled) @@ -89,7 +93,7 @@ export class NekoMessages extends EventEmitter { } protected [EVENT.SYSTEM_ADMIN]({ screen_sizes_list, broadcast_status }: message.SystemAdmin) { - this._log.debug('EVENT.SYSTEM_ADMIN') + this._log.debug(`EVENT.SYSTEM_ADMIN`) const list = screen_sizes_list.sort((a, b) => { if (b.width === a.width && b.height == a.height) { @@ -106,7 +110,7 @@ export class NekoMessages extends EventEmitter { } protected [EVENT.SYSTEM_DISCONNECT]({ message }: message.SystemDisconnect) { - this._log.debug('EVENT.SYSTEM_DISCONNECT') + this._log.debug(`EVENT.SYSTEM_DISCONNECT`) this._connection.close(new Error(message)) } @@ -115,7 +119,7 @@ export class NekoMessages extends EventEmitter { ///////////////////////////// protected async [EVENT.SIGNAL_PROVIDE]({ sdp: remoteSdp, video, iceservers }: message.SignalProvide) { - this._log.debug('EVENT.SIGNAL_PROVIDE') + this._log.debug(`EVENT.SIGNAL_PROVIDE`) this.emit('connection.webrtc.sdp', 'remote', remoteSdp) const localSdp = await this._connection.webrtc.connect(remoteSdp, iceservers) @@ -128,7 +132,7 @@ export class NekoMessages extends EventEmitter { } protected async [EVENT.SIGNAL_RESTART]({ sdp }: message.SignalAnswer) { - this._log.debug('EVENT.SIGNAL_RESTART') + this._log.debug(`EVENT.SIGNAL_RESTART`) this.emit('connection.webrtc.sdp', 'remote', sdp) const localSdp = await this._connection.webrtc.offer(sdp) @@ -140,13 +144,13 @@ export class NekoMessages extends EventEmitter { } protected [EVENT.SIGNAL_CANDIDATE](candidate: message.SignalCandidate) { - this._log.debug('EVENT.SIGNAL_CANDIDATE') + this._log.debug(`EVENT.SIGNAL_CANDIDATE`) this._connection.webrtc.setCandidate(candidate) this.emit('connection.webrtc.sdp.candidate', 'remote', candidate) } protected [EVENT.SIGNAL_VIDEO]({ video }: message.SignalVideo) { - this._log.debug('EVENT.SIGNAL_VIDEO') + this._log.debug(`EVENT.SIGNAL_VIDEO`, { video }) Vue.set(this._state.connection.webrtc, 'video', video) } @@ -155,25 +159,25 @@ export class NekoMessages extends EventEmitter { ///////////////////////////// protected [EVENT.SESSION_CREATED]({ id, ...data }: message.SessionData) { - this._log.debug('EVENT.SESSION_CREATED', id) + this._log.debug(`EVENT.SESSION_CREATED`, { id }) Vue.set(this._state.sessions, id, data) this.emit('session.created', id) } protected [EVENT.SESSION_DELETED]({ id }: message.SessionID) { - this._log.debug('EVENT.SESSION_DELETED', id) + this._log.debug(`EVENT.SESSION_DELETED`, { id }) Vue.delete(this._state.sessions, id) this.emit('session.deleted', id) } protected [EVENT.SESSION_PROFILE]({ id, ...profile }: message.MemberProfile) { - this._log.debug('EVENT.SESSION_PROFILE', id) + this._log.debug(`EVENT.SESSION_PROFILE`, { id }) Vue.set(this._state.sessions[id], 'profile', profile) this.emit('session.updated', id) } protected [EVENT.SESSION_STATE]({ id, ...state }: message.SessionState) { - this._log.debug('EVENT.SESSION_STATE', id) + this._log.debug(`EVENT.SESSION_STATE`, { id }) Vue.set(this._state.sessions[id], 'state', state) this.emit('session.updated', id) } @@ -183,7 +187,7 @@ export class NekoMessages extends EventEmitter { ///////////////////////////// protected [EVENT.CONTROL_HOST]({ has_host, host_id }: message.ControlHost) { - this._log.debug('EVENT.CONTROL_HOST') + this._log.debug(`EVENT.CONTROL_HOST`) if (has_host && host_id) { Vue.set(this._state.control, 'host_id', host_id) @@ -199,7 +203,7 @@ export class NekoMessages extends EventEmitter { ///////////////////////////// protected [EVENT.SCREEN_UPDATED]({ width, height, rate }: message.ScreenSize) { - this._log.debug('EVENT.SCREEN_UPDATED') + this._log.debug(`EVENT.SCREEN_UPDATED`) Vue.set(this._state.screen, 'size', { width, height, rate }) this.emit('room.screen.updated', width, height, rate) } @@ -209,7 +213,7 @@ export class NekoMessages extends EventEmitter { ///////////////////////////// protected [EVENT.CLIPBOARD_UPDATED]({ text }: message.ClipboardData) { - this._log.debug('EVENT.CLIPBOARD_UPDATED') + this._log.debug(`EVENT.CLIPBOARD_UPDATED`) Vue.set(this._state.control, 'clipboard', { text }) this.emit('room.clipboard.updated', text) } @@ -219,7 +223,7 @@ export class NekoMessages extends EventEmitter { ///////////////////////////// protected [EVENT.BORADCAST_STATUS]({ url, is_active }: message.BroadcastStatus) { - this._log.debug('EVENT.BORADCAST_STATUS') + this._log.debug(`EVENT.BORADCAST_STATUS`) // TODO: Handle. this.emit('room.broadcast.status', is_active, url) } @@ -229,12 +233,12 @@ export class NekoMessages extends EventEmitter { ///////////////////////////// protected [EVENT.SEND_UNICAST]({ sender, subject, body }: message.SendMessage) { - this._log.debug('EVENT.SEND_UNICAST') + this._log.debug(`EVENT.SEND_UNICAST`) this.emit('receive.unicast', sender, subject, body) } protected [EVENT.SEND_BROADCAST]({ sender, subject, body }: message.SendMessage) { - this._log.debug('EVENT.BORADCAST_STATUS') + this._log.debug(`EVENT.BORADCAST_STATUS`) this.emit('receive.broadcast', sender, subject, body) } @@ -243,7 +247,7 @@ export class NekoMessages extends EventEmitter { ///////////////////////////// protected [EVENT.FILE_CHOOSER_DIALOG_OPENED]({ id }: message.SessionID) { - this._log.debug('EVENT.FILE_CHOOSER_DIALOG_OPENED') + this._log.debug(`EVENT.FILE_CHOOSER_DIALOG_OPENED`) if (id == this._state.session_id) { this.emit('upload.dialog.requested') @@ -253,7 +257,7 @@ export class NekoMessages extends EventEmitter { } protected [EVENT.FILE_CHOOSER_DIALOG_CLOSED]({ id }: message.SessionID) { - this._log.debug('EVENT.FILE_CHOOSER_DIALOG_CLOSED') + this._log.debug(`EVENT.FILE_CHOOSER_DIALOG_CLOSED`) this.emit('upload.dialog.closed') } } diff --git a/src/component/internal/webrtc.ts b/src/component/internal/webrtc.ts index ea005d69..d8fa79a4 100644 --- a/src/component/internal/webrtc.ts +++ b/src/component/internal/webrtc.ts @@ -63,7 +63,7 @@ export class NekoWebRTC extends EventEmitter { } this._peer.addIceCandidate(candidate) - this._log.debug(`adding remote ICE candidate`, candidate) + this._log.debug(`adding remote ICE candidate`, { candidate }) } public async connect(sdp: string, iceServers: ICEServer[]): Promise { @@ -91,12 +91,12 @@ export class NekoWebRTC extends EventEmitter { const init = event.candidate.toJSON() this.emit('candidate', init) - this._log.debug(`sending remote ICE candidate`, init) + this._log.debug(`sending remote ICE candidate`, { init }) } this._peer.onconnectionstatechange = (event) => { const state = this._peer!.connectionState - this._log.debug(`peer connection state changed: ${state}`) + this._log.debug(`peer connection state changed`, { state }) switch (state) { // Chrome sends failed state change only for connectionState and not iceConnectionState, and firefox @@ -110,7 +110,7 @@ export class NekoWebRTC extends EventEmitter { this._peer.oniceconnectionstatechange = (event) => { this._state = this._peer!.iceConnectionState - this._log.debug(`peer ice connection state changed: ${this._peer!.iceConnectionState}`) + this._log.debug(`peer ice connection state changed`, { state: this._state }) switch (this._state) { // We don't watch the disconnected signaling state here as it can indicate temporary issues and may @@ -125,7 +125,7 @@ export class NekoWebRTC extends EventEmitter { this._peer.onsignalingstatechange = (event) => { const state = this._peer!.iceConnectionState - this._log.debug(`peer signaling state changed: ${state}`) + this._log.debug(`peer signaling state changed`, { state }) switch (state) { // The closed signaling state has been deprecated in favor of the closed iceConnectionState. @@ -157,7 +157,7 @@ export class NekoWebRTC extends EventEmitter { this._peer.addIceCandidate(candidate) } - this._log.debug(`added ${this._candidates.length} remote ICE candidates`, this._candidates) + this._log.debug(`added ${this._candidates.length} remote ICE candidates`, { candidates: this._candidates }) this._candidates = [] } @@ -263,7 +263,7 @@ export class NekoWebRTC extends EventEmitter { payload.setUint32(3, data.key) break default: - this._log.warn(`unknown data event: ${event}`) + this._log.warn(`unknown data event`, { event }) return } @@ -271,11 +271,19 @@ export class NekoWebRTC extends EventEmitter { } private onTrack(event: RTCTrackEvent) { - this._log.debug(`received ${event.track.kind} track from peer: ${event.track.id}`, event) - const stream = event.streams[0] + this._log.debug(`received track from peer`, { + id: event.track.id, + label: event.track.label, + kind: event.track.label, + }) + const stream = event.streams[0] if (!stream) { - this._log.warn(`no stream provided for track ${event.track.id}(${event.track.label})`) + this._log.warn(`no stream provided for track`, { + id: event.track.id, + label: event.track.label, + kind: event.track.label, + }) return } @@ -287,7 +295,9 @@ export class NekoWebRTC extends EventEmitter { } private onDataChannel(event: RTCDataChannelEvent) { - this._log.debug(`received data channel from peer: ${event.channel.label}`, event) + this._log.debug(`received data channel from peer`, { + label: event.channel.label, + }) this._channel = event.channel this._channel.binaryType = 'arraybuffer' @@ -328,7 +338,7 @@ export class NekoWebRTC extends EventEmitter { break default: - this._log.warn(`unhandled webrtc event '${event}'.`, payload) + this._log.warn(`unhandled webrtc event`, { event, payload }) } } @@ -347,7 +357,7 @@ export class NekoWebRTC extends EventEmitter { private onDisconnected(reason?: Error) { this.disconnect() - this._log.info(`disconnected:`, reason?.message) + this._log.info(`disconnected`, { message: reason?.message }) this.emit('disconnected', reason) if (this._statsStop && typeof this._statsStop === 'function') { diff --git a/src/component/internal/websocket.ts b/src/component/internal/websocket.ts index e17b22c8..3120f1ef 100644 --- a/src/component/internal/websocket.ts +++ b/src/component/internal/websocket.ts @@ -71,14 +71,14 @@ export class NekoWebSocket extends EventEmitter { return } - this._log.debug(`sending event '${event}' ${payload ? `with payload: ` : ''}`, payload) + this._log.debug(`sending websocket event`, { event, payload }) this._ws!.send(JSON.stringify({ event, payload })) } private onMessage(e: MessageEvent) { const { event, payload } = JSON.parse(e.data) - this._log.debug(`received websocket event ${event} ${payload ? `with payload: ` : ''}`, payload) + this._log.debug(`received websocket event`, { event, payload }) this.emit('message', event, payload) } @@ -95,7 +95,7 @@ export class NekoWebSocket extends EventEmitter { private onDisconnected(reason: string) { this.disconnect() - this._log.info(`connection ${reason}`) + this._log.info(`disconnected`, { reason }) this.emit('disconnected', new Error(`connection ${reason}`)) } } diff --git a/src/component/utils/logger.ts b/src/component/utils/logger.ts index dd931621..6e383dc8 100644 --- a/src/component/utils/logger.ts +++ b/src/component/utils/logger.ts @@ -1,5 +1,5 @@ export class Logger { - private _scope: string = 'main' + protected _scope: string = 'main' constructor(scope?: string) { if (scope) { @@ -7,19 +7,45 @@ export class Logger { } } - public error(error: Error) { - console.error('[%cNEKO%c] [' + this._scope + '] %cERR', 'color: #498ad8;', '', 'color: #d84949;', error) + protected _console(level: string, m: string, fields?: Record) { + let t = '' + const args = [] + for (const name in fields) { + t += ' %c%s=%c%o' + args.push('color:#498ad8;', name, '', fields[name]) + } + + const scope = this._scope + switch (level) { + case 'error': + console.error('[%cNEKO%c] [%s] %cERR%c %s' + t, 'color:#498ad8;', '', scope, 'color:#d84949;', '', m, ...args) + break + case 'warn': + console.warn('[%cNEKO%c] [%s] %cWRN%c %s' + t, 'color:#498ad8;', '', scope, 'color:#eae364;', '', m, ...args) + break + case 'info': + console.info('[%cNEKO%c] [%s] %cINF%c %s' + t, 'color:#498ad8;', '', scope, 'color:#4ac94c;', '', m, ...args) + break + default: + case 'debug': + console.debug('[%cNEKO%c] [%s] %cDBG%c %s' + t, 'color:#498ad8;', '', scope, 'color:#eae364;', '', m, ...args) + break + } } - public warn(...log: any[]) { - console.warn('[%cNEKO%c] [' + this._scope + '] %cWRN', 'color: #498ad8;', '', 'color: #eae364;', ...log) + public error(message: string, fields?: Record) { + this._console('error', message, fields) } - public info(...log: any[]) { - console.info('[%cNEKO%c] [' + this._scope + '] %cINF', 'color: #498ad8;', '', 'color: #4ac94c;', ...log) + public warn(message: string, fields?: Record) { + this._console('warn', message, fields) } - public debug(...log: any[]) { - console.debug('[%cNEKO%c] [' + this._scope + '] %cDBG', 'color: #498ad8;', '', 'color: #eae364;', ...log) + public info(message: string, fields?: Record) { + this._console('info', message, fields) + } + + public debug(message: string, fields?: Record) { + this._console('debug', message, fields) } }