From 774511aeffc689fc5bb7310dc479d54609b6651f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Birm=C3=A9?= Date: Fri, 28 Jun 2024 21:59:05 +0200 Subject: [PATCH] chore: generic logging --- src/api_productions.ts | 13 +++++ src/connection.ts | 5 +- src/log.ts | 105 ++++++++++++++++++++++++++++++++++++++ src/production_manager.ts | 3 +- src/server.ts | 6 ++- src/smb.ts | 9 ++-- 6 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 src/log.ts diff --git a/src/api_productions.ts b/src/api_productions.ts index e24ec36..e8ac385 100644 --- a/src/api_productions.ts +++ b/src/api_productions.ts @@ -22,6 +22,7 @@ import dotenv from 'dotenv'; import { v4 as uuidv4 } from 'uuid'; import { ConnectionQueue } from './connection_queue'; import { CoreFunctions } from './api_productions_core_functions'; +import { Log } from './log'; dotenv.config(); const productionManager = new ProductionManager(); @@ -81,6 +82,7 @@ const apiProductions: FastifyPluginCallback = ( reply.code(400).send({ message: 'Failed to create production' }); } } catch (err) { + Log().error(err); reply .code(500) .send('Exception thrown when trying to create production: ' + err); @@ -111,6 +113,7 @@ const apiProductions: FastifyPluginCallback = ( })) ); } catch (err) { + Log().error(err); reply .code(500) .send('Exception thrown when trying to get productions: ' + err); @@ -146,6 +149,7 @@ const apiProductions: FastifyPluginCallback = ( }; reply.code(200).send(productionResponse); } catch (err) { + Log().error(err); reply .code(500) .send('Exception thrown when trying to get productions: ' + err); @@ -219,6 +223,7 @@ const apiProductions: FastifyPluginCallback = ( reply.code(200).send(allLinesResponse); } } catch (err) { + Log().error(err); reply .code(500) .send('Unhandled exception thrown when trying to add line: ' + err); @@ -264,6 +269,7 @@ const apiProductions: FastifyPluginCallback = ( reply.code(200).send(lineResponse); } } catch (err) { + Log().error(err); reply .code(500) .send('Exception thrown when trying to get line: ' + err); @@ -329,6 +335,7 @@ const apiProductions: FastifyPluginCallback = ( } } } catch (err) { + Log().error(err); reply .code(500) .send('Exception thrown when trying to get line: ' + err); @@ -377,6 +384,7 @@ const apiProductions: FastifyPluginCallback = ( } } } catch (err) { + Log().error(err); reply .code(500) .send('Exception thrown when trying to get line: ' + err); @@ -453,6 +461,7 @@ const apiProductions: FastifyPluginCallback = ( }); } } catch (err) { + Log().error(err); reply .code(500) .send('Exception thrown when trying to create endpoint: ' + err); @@ -517,6 +526,7 @@ const apiProductions: FastifyPluginCallback = ( ); reply.code(204); } catch (err) { + Log().error(err); reply .code(500) .send('Exception thrown when trying to configure endpoint: ' + err); @@ -550,6 +560,7 @@ const apiProductions: FastifyPluginCallback = ( } reply.code(200).send(`Deleted production ${productionId}`); } catch (err) { + Log().error(err); reply .code(500) .send('Exception thrown when trying to delete production: ' + err); @@ -580,6 +591,7 @@ const apiProductions: FastifyPluginCallback = ( } reply.code(200).send(`Deleted connection ${sessionId}`); } catch (err) { + Log().error(err); reply .code(500) .send('Exception thrown when trying to delete connection: ' + err); @@ -617,6 +629,7 @@ const apiProductions: FastifyPluginCallback = ( await waitForChange; reply.code(200).send(participants); } catch (err) { + Log().error(err); reply .code(500) .send( diff --git a/src/connection.ts b/src/connection.ts index 4198ee9..47546c8 100644 --- a/src/connection.ts +++ b/src/connection.ts @@ -6,6 +6,7 @@ import { SfuEndpointDescription } from './sfu/interface'; import { MediaStreamsInfo } from './media_streams_info'; +import { Log } from './log'; export class Connection { private resourceId: string; @@ -39,11 +40,11 @@ export class Connection { } protected log(...args: string[] | Connection[]) { - console.log(`[connection ${this.connectionId}]`, ...args); + Log().info(`[connection ${this.connectionId}]`, ...args); } protected error(...args: string[] | Connection[]) { - console.error(`[connection ${this.connectionId}]`, ...args); + Log().error(`[connection ${this.connectionId}]`, ...args); } createOffer(): SessionDescription { diff --git a/src/log.ts b/src/log.ts new file mode 100644 index 0000000..2c46dac --- /dev/null +++ b/src/log.ts @@ -0,0 +1,105 @@ +import util from 'util'; + +let logger_: Logger | undefined; + +type LevelCode = 'info' | 'error' | 'warn' | 'debug' | 'fatal'; +type LevelItem = { + text: string; + method: LevelCode; +}; +const LEVELS: { [k in LevelCode]: LevelItem } = { + info: { text: 'info', method: 'info' }, + error: { text: 'error', method: 'error' }, + warn: { text: 'warn', method: 'info' }, + debug: { text: 'debug', method: 'info' }, + fatal: { text: 'fatal', method: 'error' } +}; + +function log(method: LevelCode) { + switch (method) { + case 'info': + return console.info; + case 'error': + return console.error; + default: + throw new Error(`Invalid log method ${method}`); + } +} + +function logfmt(levelCode: LevelCode, ...args: any[]) { + const level = LEVELS[levelCode]; + if (levelCode == 'debug') { + args = args.map((arg) => { + if (typeof arg == 'object') { + return util.inspect(arg, { depth: null }); + } + return arg; + }); + log(level.method)(...args); + } else { + const msg = util.format(...args); + log(level.method)(msg); + } +} + +export class Logger { + private debugMode = false; + + constructor() { + return this; + } + + info(...args: any[]) { + logfmt('info', ...args); + return this; + } + + warn(...args: any[]) { + logfmt('warn', ...args); + return this; + } + + error(...args: any[]) { + logfmt('error', ...args); + return this; + } + + debug(...args: any[]) { + if (this.debugMode) logfmt('debug', ...args); + return this; + } + + fatal(...args: any[]) { + logfmt('fatal', ...args); + return this; + } + + get level(): 'debug' | 'info' { + return this.debugMode ? 'debug' : 'info'; + } + + set level(value: 'debug' | 'info') { + if (value == 'debug') { + this.debugMode = true; + } else if (value == 'info') { + this.debugMode = false; + } else { + this.warn('level', value, 'not supported'); + } + } +} + +export function Log(): Logger { + if (logger_) { + return logger_; + } + + logger_ = new Logger(); + logger_.level = 'info'; + + if (process.env.DEBUG) { + logger_.level = 'debug'; + } + + return logger_; +} diff --git a/src/production_manager.ts b/src/production_manager.ts index 99f529a..2a949e7 100644 --- a/src/production_manager.ts +++ b/src/production_manager.ts @@ -10,6 +10,7 @@ import { } from './models'; import { assert } from './utils'; import dbManager from './db_manager'; +import { Log } from './log'; const SESSION_INACTIVE_THRESHOLD = 60_000; const SESSION_EXPIRED_THRESHOLD = 120_000; @@ -173,7 +174,7 @@ export class ProductionManager extends EventEmitter { isActive: true, isExpired: false }; - console.log(`Created user session: "${name}": ${sessionId}`); + Log().info(`Created user session: "${name}": ${sessionId}`); this.emit('users:change'); } diff --git a/src/server.ts b/src/server.ts index 9104a3d..fc05efa 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,5 +1,6 @@ import api from './api'; import { checkUserStatus } from './api_productions'; +import { Log } from './log'; const SMB_ADDRESS: string = process.env.SMB_ADDRESS ?? 'http://localhost:8080'; @@ -26,6 +27,9 @@ const PORT = process.env.PORT ? Number(process.env.PORT) : 8000; if (err) { throw err; } - console.log(`Server listening on ${address}`); + Log().info(`Manager listening on ${address}`); + Log().info( + `Media Bridge at ${SMB_ADDRESS} (${ENDPOINT_IDLE_TIMEOUT_S}s idle timeout)` + ); }); })(); diff --git a/src/smb.ts b/src/smb.ts index 015bedf..405df35 100644 --- a/src/smb.ts +++ b/src/smb.ts @@ -1,3 +1,4 @@ +import { Log } from './log'; import { SmbEndpointDescription, DetailedConference } from './models'; interface AllocateConferenceResponse { @@ -69,10 +70,10 @@ export class SmbProtocol { if (idleTimeout) { request['idleTimeout'] = idleTimeout; } - console.log(request); + Log().debug(request); const url = smbUrl + conferenceId + '/' + endpointId; - console.log(url); + Log().debug(url); const response = await fetch(url, { method: 'POST', headers: { @@ -113,10 +114,10 @@ export class SmbProtocol { }, body: JSON.stringify(request) }); - console.log(request); + Log().debug(request); if (!response.ok) { - console.log(JSON.stringify(request)); + Log().debug(JSON.stringify(request)); const contentType = response.headers.get('content-type');