audiobookshelf/server/Logger.js
2024-05-19 14:40:46 -05:00

153 lines
3.7 KiB
JavaScript

const date = require('./libs/dateAndTime')
const { LogLevel } = require('./utils/constants')
class Logger {
constructor() {
/** @type {import('./managers/LogManager')} */
this.logManager = null
this.isDev = process.env.NODE_ENV !== 'production'
this.logLevel = !this.isDev ? LogLevel.INFO : LogLevel.TRACE
this.socketListeners = []
}
/**
* @returns {string}
*/
get timestamp() {
return date.format(new Date(), 'YYYY-MM-DD HH:mm:ss.SSS')
}
get levelString() {
for (const key in LogLevel) {
if (LogLevel[key] === this.logLevel) {
return key
}
}
return 'UNKNOWN'
}
/**
* @returns {string}
*/
get source() {
try {
throw new Error()
} catch (error) {
const regex = global.isWin ? /^.*\\([^\\:]*:[0-9]*):[0-9]*\)*/ : /^.*\/([^/:]*:[0-9]*):[0-9]*\)*/
return error.stack.split('\n')[3].replace(regex, '$1')
}
}
getLogLevelString(level) {
for (const key in LogLevel) {
if (LogLevel[key] === level) {
return key
}
}
return 'UNKNOWN'
}
addSocketListener(socket, level) {
var index = this.socketListeners.findIndex((s) => s.id === socket.id)
if (index >= 0) {
this.socketListeners.splice(index, 1, {
id: socket.id,
socket,
level
})
} else {
this.socketListeners.push({
id: socket.id,
socket,
level
})
}
}
removeSocketListener(socketId) {
this.socketListeners = this.socketListeners.filter((s) => s.id !== socketId)
}
/**
*
* @param {number} level
* @param {string[]} args
* @param {string} src
*/
async handleLog(level, args, src) {
const logObj = {
timestamp: this.timestamp,
source: src,
message: args.join(' '),
levelName: this.getLogLevelString(level),
level
}
// Emit log to sockets that are listening to log events
this.socketListeners.forEach((socketListener) => {
if (socketListener.level <= level) {
socketListener.socket.emit('log', logObj)
}
})
// Save log to file
if (level >= this.logLevel) {
await this.logManager?.logToFile(logObj)
}
}
setLogLevel(level) {
this.logLevel = level
this.debug(`Set Log Level to ${this.levelString}`)
}
trace(...args) {
if (this.logLevel > LogLevel.TRACE) return
console.trace(`[${this.timestamp}] TRACE:`, ...args)
this.handleLog(LogLevel.TRACE, args, this.source)
}
debug(...args) {
if (this.logLevel > LogLevel.DEBUG) return
console.debug(`[${this.timestamp}] DEBUG:`, ...args, `(${this.source})`)
this.handleLog(LogLevel.DEBUG, args, this.source)
}
info(...args) {
if (this.logLevel > LogLevel.INFO) return
console.info(`[${this.timestamp}] INFO:`, ...args)
this.handleLog(LogLevel.INFO, args, this.source)
}
warn(...args) {
if (this.logLevel > LogLevel.WARN) return
console.warn(`[${this.timestamp}] WARN:`, ...args, `(${this.source})`)
this.handleLog(LogLevel.WARN, args, this.source)
}
error(...args) {
if (this.logLevel > LogLevel.ERROR) return
console.error(`[${this.timestamp}] ERROR:`, ...args, `(${this.source})`)
this.handleLog(LogLevel.ERROR, args, this.source)
}
/**
* Fatal errors are ones that exit the process
* Fatal logs are saved to crash_logs.txt
*
* @param {...any} args
*/
fatal(...args) {
console.error(`[${this.timestamp}] FATAL:`, ...args, `(${this.source})`)
return this.handleLog(LogLevel.FATAL, args, this.source)
}
note(...args) {
console.log(`[${this.timestamp}] NOTE:`, ...args)
this.handleLog(LogLevel.NOTE, args, this.source)
}
}
module.exports = new Logger()