audiobookshelf/server/objects/DailyLog.js

135 lines
3.2 KiB
JavaScript

const Path = require('path')
const date = require('../libs/dateAndTime')
const fs = require('../libs/fsExtra')
const fileUtils = require('../utils/fileUtils')
const Logger = require('../Logger')
class DailyLog {
/**
*
* @param {string} dailyLogDirPath Path to daily logs /metadata/logs/daily
*/
constructor(dailyLogDirPath) {
this.id = date.format(new Date(), 'YYYY-MM-DD')
this.dailyLogDirPath = dailyLogDirPath
this.filename = this.id + '.txt'
this.fullPath = Path.join(this.dailyLogDirPath, this.filename)
this.createdAt = Date.now()
/** @type {import('../managers/LogManager').LogObject[]} */
this.logs = []
/** @type {string[]} */
this.bufferedLogLines = []
this.locked = false
}
static getCurrentDailyLogFilename() {
return date.format(new Date(), 'YYYY-MM-DD') + '.txt'
}
static getCurrentDateString() {
return date.format(new Date(), 'YYYY-MM-DD')
}
toJSON() {
return {
id: this.id,
dailyLogDirPath: this.dailyLogDirPath,
fullPath: this.fullPath,
filename: this.filename,
createdAt: this.createdAt
}
}
/**
* Append all buffered lines to daily log file
*/
appendBufferedLogs() {
let buffered = [...this.bufferedLogLines]
this.bufferedLogLines = []
let oneBigLog = ''
buffered.forEach((logLine) => {
oneBigLog += logLine
})
return this.appendLogLine(oneBigLog)
}
/**
*
* @param {import('../managers/LogManager').LogObject} logObj
*/
appendLog(logObj) {
this.logs.push(logObj)
return this.appendLogLine(JSON.stringify(logObj) + '\n')
}
/**
* Append log to daily log file
*
* @param {string} line
*/
async appendLogLine(line) {
if (this.locked) {
this.bufferedLogLines.push(line)
return
}
this.locked = true
await fs.writeFile(this.fullPath, line, { flag: "a+" }).catch((error) => {
console.log('[DailyLog] Append log failed', error)
})
this.locked = false
if (this.bufferedLogLines.length) {
await this.appendBufferedLogs()
}
}
/**
* Load all logs from file
* Parses lines and re-saves the file if bad lines are removed
*/
async loadLogs() {
if (!await fs.pathExists(this.fullPath)) {
console.error('Daily log does not exist')
return
}
const text = await fileUtils.readTextFile(this.fullPath)
let hasFailures = false
let logLines = text.split(/\r?\n/)
// remove last log if empty
if (logLines.length && !logLines[logLines.length - 1]) logLines = logLines.slice(0, -1)
// JSON parse log lines
this.logs = logLines.map(t => {
if (!t) {
hasFailures = true
return null
}
try {
return JSON.parse(t)
} catch (err) {
console.error('Failed to parse log line', t, err)
hasFailures = true
return null
}
}).filter(l => !!l)
// Rewrite log file to remove errors
if (hasFailures) {
const newLogLines = this.logs.map(l => JSON.stringify(l)).join('\n') + '\n'
await fs.writeFile(this.fullPath, newLogLines)
console.log('Re-Saved log file to remove bad lines')
}
Logger.debug(`[DailyLog] ${this.id}: Loaded ${this.logs.length} Logs`)
}
}
module.exports = DailyLog