aboutsummaryrefslogtreecommitdiff
path: root/src/lib/logger.js
blob: b71020c0ea0715774c277ad4eea5c2c461e2088c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
const log4js = require('log4js')
const fs = require('fs/promises')
const fsConstants = require('fs').constants
const util = require('./util')

const ALLOWED_LEVELS = ['trace', 'debug', 'info', 'warn', 'error']

module.exports = {
    /**
     * @param {string} file
     * @param {string} levelFile
     * @param {string} levelConsole
     * @param {boolean} disableTimestamps
     */
    async init({file, levelFile, levelConsole, disableTimestamps=false}) {
        const categories = {
            default: {
                appenders: ['stdout-filter'],
                level: 'trace'
            }
        }

        if (!ALLOWED_LEVELS.includes(levelConsole))
            throw new Error(`Level ${levelConsole} is not allowed.`)

        const appenders = {
            stdout: {
                type: 'stdout',
                level: 'trace',
            },
            'stdout-filter': {
                type: 'logLevelFilter',
                appender: 'stdout',
                level: levelConsole,
            }
        }
        if (disableTimestamps)
            appenders.stdout.layout = {
                type: 'pattern',
                pattern: '%[%p [%c]%] %m',
            }

        if (file) {
            if (!ALLOWED_LEVELS.includes(levelFile))
                throw new Error(`Level ${levelFile} is not allowed.`)

            let exists
            try {
                await fs.stat(file)
                exists = true
            } catch (error) {
                exists = false
            }

            // if file exists
            if (exists) {
                // see if it's writable
                try {
                    // this promise fullfills with undefined upon success
                    await fs.access(file, fsConstants.W_OK)
                } catch (error) {
                    throw new Error(`file '${file}' is not writable:` + error.message)
                }
            } else {
                // try to create an empty file
                let fd
                try {
                    fd = await fs.open(file, 'wx')
                } catch (error) {
                    throw new Error(`failed to create file '${file}': ` + error.message)
                } finally {
                    await fd?.close()
                }
            }

            categories.default.appenders.push('file-filter')
            appenders.file = {
                type: 'file',
                filename: file,
                maxLogSize: 1024 * 1024 * 50,
                debug: 'debug'
            }
            appenders['file-filter'] = {
                type: 'logLevelFilter',
                appender: 'file',
                level: levelFile
            }
        }

        log4js.configure({
            appenders,
            categories
        })
    },

    /**
     * @return {Logger}
     */
    getLogger(...args) {
        return log4js.getLogger(...args)
    },

    /**
     * @return {Promise}
     */
    shutdown() {
        return new Promise((resolve, reject) => {
            log4js.shutdown(resolve)
        })
    },

    Logger: log4js.Logger,
}