adapt-authoring-logger 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/releases.yml +1 -1
- package/.github/workflows/standardjs.yml +1 -1
- package/.github/workflows/tests.yml +1 -1
- package/lib/LoggerModule.js +15 -84
- package/lib/utils/colourise.js +12 -0
- package/lib/utils/getDateStamp.js +27 -0
- package/lib/utils/getModuleOverrides.js +15 -0
- package/lib/utils/isLevelEnabled.js +10 -0
- package/lib/utils/isLoggingEnabled.js +14 -0
- package/lib/utils.js +5 -0
- package/package.json +2 -2
- package/tests/LoggerModule.spec.js +60 -89
- package/tests/utils-colourise.spec.js +36 -0
- package/tests/utils-getDateStamp.spec.js +34 -0
- package/tests/utils-getModuleOverrides.spec.js +39 -0
- package/tests/utils-isLevelEnabled.spec.js +33 -0
- package/tests/utils-isLoggingEnabled.spec.js +50 -0
package/lib/LoggerModule.js
CHANGED
|
@@ -1,45 +1,12 @@
|
|
|
1
1
|
import { AbstractModule, Hook } from 'adapt-authoring-core'
|
|
2
2
|
import chalk from 'chalk'
|
|
3
|
+
import { colourise, getDateStamp, getModuleOverrides, isLevelEnabled, isLoggingEnabled } from './utils.js'
|
|
3
4
|
/**
|
|
4
5
|
* Module for logging message to the console
|
|
5
6
|
* @memberof logger
|
|
6
7
|
* @extends {AbstractModule}
|
|
7
8
|
*/
|
|
8
9
|
class LoggerModule extends AbstractModule {
|
|
9
|
-
/**
|
|
10
|
-
* Colours an input string
|
|
11
|
-
* @param {String} str
|
|
12
|
-
* @param {String} colour
|
|
13
|
-
* @return {String}
|
|
14
|
-
*/
|
|
15
|
-
static colourise (str, colourFunc) {
|
|
16
|
-
if (typeof colourFunc === 'string') colourFunc = chalk[colourFunc]
|
|
17
|
-
return colourFunc ? colourFunc(str) : str
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Returns a formatted date stamp
|
|
22
|
-
* @param {Object} config
|
|
23
|
-
* @return {String}
|
|
24
|
-
*/
|
|
25
|
-
static getDateStamp (config) {
|
|
26
|
-
if (!config.timestamp) {
|
|
27
|
-
return ''
|
|
28
|
-
}
|
|
29
|
-
let str
|
|
30
|
-
if (config.dateFormat === 'iso') {
|
|
31
|
-
str = new Date().toISOString()
|
|
32
|
-
} else if (config.dateFormat === 'short') {
|
|
33
|
-
const d = new Date()
|
|
34
|
-
const m = d.getMonth() + 1
|
|
35
|
-
const s = d.getSeconds()
|
|
36
|
-
const date = `${d.getDate()}/${m < 10 ? `0${m}` : m}/${d.getFullYear().toString().slice(2)}`
|
|
37
|
-
const time = `${d.getHours()}:${d.getMinutes()}:${s < 10 ? `0${s}` : s}`
|
|
38
|
-
str = `${date}-${time}`
|
|
39
|
-
}
|
|
40
|
-
return LoggerModule.colourise(`${str} `, chalk.dim)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
10
|
/** @override */
|
|
44
11
|
async init () {
|
|
45
12
|
await this.app.waitForModule('config')
|
|
@@ -60,33 +27,33 @@ class LoggerModule extends AbstractModule {
|
|
|
60
27
|
this.config = {
|
|
61
28
|
levels: {
|
|
62
29
|
error: {
|
|
63
|
-
enable: this.
|
|
64
|
-
moduleOverrides: this.
|
|
30
|
+
enable: isLevelEnabled(this.levelsConfig, 'error'),
|
|
31
|
+
moduleOverrides: getModuleOverrides(this.levelsConfig, 'error'),
|
|
65
32
|
colour: chalk.red
|
|
66
33
|
},
|
|
67
34
|
warn: {
|
|
68
|
-
enable: this.
|
|
69
|
-
moduleOverrides: this.
|
|
35
|
+
enable: isLevelEnabled(this.levelsConfig, 'warn'),
|
|
36
|
+
moduleOverrides: getModuleOverrides(this.levelsConfig, 'warn'),
|
|
70
37
|
colour: chalk.yellow
|
|
71
38
|
},
|
|
72
39
|
success: {
|
|
73
|
-
enable: this.
|
|
74
|
-
moduleOverrides: this.
|
|
40
|
+
enable: isLevelEnabled(this.levelsConfig, 'success'),
|
|
41
|
+
moduleOverrides: getModuleOverrides(this.levelsConfig, 'success'),
|
|
75
42
|
colour: chalk.green
|
|
76
43
|
},
|
|
77
44
|
info: {
|
|
78
|
-
enable: this.
|
|
79
|
-
moduleOverrides: this.
|
|
45
|
+
enable: isLevelEnabled(this.levelsConfig, 'info'),
|
|
46
|
+
moduleOverrides: getModuleOverrides(this.levelsConfig, 'info'),
|
|
80
47
|
colour: chalk.cyan
|
|
81
48
|
},
|
|
82
49
|
debug: {
|
|
83
|
-
enable: this.
|
|
84
|
-
moduleOverrides: this.
|
|
50
|
+
enable: isLevelEnabled(this.levelsConfig, 'debug'),
|
|
51
|
+
moduleOverrides: getModuleOverrides(this.levelsConfig, 'debug'),
|
|
85
52
|
colour: chalk.dim
|
|
86
53
|
},
|
|
87
54
|
verbose: {
|
|
88
|
-
enable: this.
|
|
89
|
-
moduleOverrides: this.
|
|
55
|
+
enable: isLevelEnabled(this.levelsConfig, 'verbose'),
|
|
56
|
+
moduleOverrides: getModuleOverrides(this.levelsConfig, 'verbose'),
|
|
90
57
|
colour: chalk.grey.italic
|
|
91
58
|
}
|
|
92
59
|
},
|
|
@@ -100,42 +67,6 @@ class LoggerModule extends AbstractModule {
|
|
|
100
67
|
this.app.logger = this
|
|
101
68
|
}
|
|
102
69
|
|
|
103
|
-
/**
|
|
104
|
-
* Determines whether a specific log level is enabled
|
|
105
|
-
* @param {String} level
|
|
106
|
-
* @return {Boolean}
|
|
107
|
-
*/
|
|
108
|
-
isLevelEnabled (level) { // note explicit disable takes preference
|
|
109
|
-
return !this.levelsConfig.includes(`!${level}`) && this.levelsConfig.includes(level)
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Returns a list of log levels with overrides, either inclusive or exclusive
|
|
114
|
-
* @param {String} level
|
|
115
|
-
* @return {Array}
|
|
116
|
-
*/
|
|
117
|
-
getModuleOverrides (level) {
|
|
118
|
-
const levels = []
|
|
119
|
-
this.levelsConfig.forEach(l => {
|
|
120
|
-
const s = `${level}.`; const notS = `!${level}.`
|
|
121
|
-
if (l.indexOf(s) === 0 || l.indexOf(notS) === 0) levels.push(l)
|
|
122
|
-
})
|
|
123
|
-
return levels
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Returns whether a message should be logged (i.e. not disabled in the config)
|
|
128
|
-
* @param {string} level Logging level
|
|
129
|
-
* @param {string} id Id of log caller
|
|
130
|
-
* @returns {boolean}
|
|
131
|
-
*/
|
|
132
|
-
isLoggingEnabled (level, id) {
|
|
133
|
-
const { enable, moduleOverrides = [] } = this?.config?.levels[level] || {}
|
|
134
|
-
const isEnabled = enable || moduleOverrides.includes(`${level}.${id}`)
|
|
135
|
-
const disableOverride = moduleOverrides.includes(`!${level}.${id}`)
|
|
136
|
-
return isEnabled && !disableOverride
|
|
137
|
-
}
|
|
138
|
-
|
|
139
70
|
/**
|
|
140
71
|
* Logs a message to the console
|
|
141
72
|
* @param {String} level Severity of the message
|
|
@@ -150,12 +81,12 @@ class LoggerModule extends AbstractModule {
|
|
|
150
81
|
id = this.name.split('-').pop()
|
|
151
82
|
args = [AbstractModule.MODULE_READY, ...args]
|
|
152
83
|
}
|
|
153
|
-
if (!this.
|
|
84
|
+
if (!isLoggingEnabled(this.config?.levels, level, id)) {
|
|
154
85
|
return
|
|
155
86
|
}
|
|
156
87
|
const colour = this?.config?.levels[level]?.colour
|
|
157
88
|
const logFunc = console[level] ?? console.log
|
|
158
|
-
logFunc(`${
|
|
89
|
+
logFunc(`${getDateStamp(this.config)}${colourise(level, colour)} ${colourise(id, chalk.magenta)}`, ...args)
|
|
159
90
|
this.logHook.invoke(new Date(), level, id, ...args)
|
|
160
91
|
}
|
|
161
92
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
/**
|
|
3
|
+
* Colours an input string using a chalk function or colour name
|
|
4
|
+
* @param {String} str The string to colourise
|
|
5
|
+
* @param {String|Function} colourFunc A chalk colour function or string name of a chalk colour
|
|
6
|
+
* @return {String} The colourised string
|
|
7
|
+
* @memberof logger
|
|
8
|
+
*/
|
|
9
|
+
export function colourise (str, colourFunc) {
|
|
10
|
+
if (typeof colourFunc === 'string') colourFunc = chalk[colourFunc]
|
|
11
|
+
return colourFunc ? colourFunc(str) : str
|
|
12
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
import { colourise } from './colourise.js'
|
|
3
|
+
/**
|
|
4
|
+
* Returns a formatted date stamp string based on config
|
|
5
|
+
* @param {Object} config Logger configuration object
|
|
6
|
+
* @param {Boolean} config.timestamp Whether to include a timestamp
|
|
7
|
+
* @param {String} config.dateFormat Date format ('iso' or 'short')
|
|
8
|
+
* @return {String} The formatted date stamp (empty string if timestamps disabled)
|
|
9
|
+
* @memberof logger
|
|
10
|
+
*/
|
|
11
|
+
export function getDateStamp (config) {
|
|
12
|
+
if (!config.timestamp) {
|
|
13
|
+
return ''
|
|
14
|
+
}
|
|
15
|
+
let str
|
|
16
|
+
if (config.dateFormat === 'iso') {
|
|
17
|
+
str = new Date().toISOString()
|
|
18
|
+
} else if (config.dateFormat === 'short') {
|
|
19
|
+
const d = new Date()
|
|
20
|
+
const m = d.getMonth() + 1
|
|
21
|
+
const s = d.getSeconds()
|
|
22
|
+
const date = `${d.getDate()}/${m < 10 ? `0${m}` : m}/${d.getFullYear().toString().slice(2)}`
|
|
23
|
+
const time = `${d.getHours()}:${d.getMinutes()}:${s < 10 ? `0${s}` : s}`
|
|
24
|
+
str = `${date}-${time}`
|
|
25
|
+
}
|
|
26
|
+
return colourise(`${str} `, chalk.dim)
|
|
27
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a list of module-specific log level overrides from the levels config
|
|
3
|
+
* @param {Array<String>} levelsConfig Array of level configuration strings
|
|
4
|
+
* @param {String} level The log level to find overrides for
|
|
5
|
+
* @return {Array<String>} Array of override strings (e.g. ['debug.mymod', '!debug.other'])
|
|
6
|
+
* @memberof logger
|
|
7
|
+
*/
|
|
8
|
+
export function getModuleOverrides (levelsConfig, level) {
|
|
9
|
+
const levels = []
|
|
10
|
+
levelsConfig.forEach(l => {
|
|
11
|
+
const s = `${level}.`; const notS = `!${level}.`
|
|
12
|
+
if (l.indexOf(s) === 0 || l.indexOf(notS) === 0) levels.push(l)
|
|
13
|
+
})
|
|
14
|
+
return levels
|
|
15
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Determines whether a specific log level is enabled in the levels config
|
|
3
|
+
* @param {Array<String>} levelsConfig Array of level configuration strings
|
|
4
|
+
* @param {String} level The log level to check (e.g. 'error', 'warn', 'debug')
|
|
5
|
+
* @return {Boolean} Whether the level is enabled
|
|
6
|
+
* @memberof logger
|
|
7
|
+
*/
|
|
8
|
+
export function isLevelEnabled (levelsConfig, level) {
|
|
9
|
+
return !levelsConfig.includes(`!${level}`) && levelsConfig.includes(level)
|
|
10
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns whether a message should be logged based on the resolved config
|
|
3
|
+
* @param {Object} configLevels The resolved levels config object (e.g. { error: { enable, moduleOverrides }, ... })
|
|
4
|
+
* @param {String} level Logging level (e.g. 'error', 'warn', 'debug')
|
|
5
|
+
* @param {String} id Id of log caller (module name)
|
|
6
|
+
* @returns {Boolean} Whether logging is enabled for this level and caller
|
|
7
|
+
* @memberof logger
|
|
8
|
+
*/
|
|
9
|
+
export function isLoggingEnabled (configLevels, level, id) {
|
|
10
|
+
const { enable, moduleOverrides = [] } = configLevels?.[level] || {}
|
|
11
|
+
const isEnabled = enable || moduleOverrides.includes(`${level}.${id}`)
|
|
12
|
+
const disableOverride = moduleOverrides.includes(`!${level}.${id}`)
|
|
13
|
+
return isEnabled && !disableOverride
|
|
14
|
+
}
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { colourise } from './utils/colourise.js'
|
|
2
|
+
export { getDateStamp } from './utils/getDateStamp.js'
|
|
3
|
+
export { getModuleOverrides } from './utils/getModuleOverrides.js'
|
|
4
|
+
export { isLevelEnabled } from './utils/isLevelEnabled.js'
|
|
5
|
+
export { isLoggingEnabled } from './utils/isLoggingEnabled.js'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adapt-authoring-logger",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Basic logger for the Adapt authoring tool",
|
|
5
5
|
"homepage": "https://github.com/adapt-security/adapt-authoring-logger",
|
|
6
6
|
"license": "GPL-3.0",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"main": "index.js",
|
|
9
9
|
"repository": "adapt-security/adapt-authoring-logger",
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"adapt-authoring-core": "^
|
|
11
|
+
"adapt-authoring-core": "^2.0.0",
|
|
12
12
|
"chalk": "^5.3.0"
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
@@ -3,220 +3,191 @@ import assert from 'node:assert/strict'
|
|
|
3
3
|
import chalk from 'chalk'
|
|
4
4
|
import { AbstractModule } from 'adapt-authoring-core'
|
|
5
5
|
import LoggerModule from '../lib/LoggerModule.js'
|
|
6
|
+
import { colourise, getDateStamp, isLevelEnabled, getModuleOverrides, isLoggingEnabled } from '../lib/utils.js'
|
|
6
7
|
|
|
7
8
|
describe('LoggerModule', () => {
|
|
8
|
-
describe('
|
|
9
|
+
describe('colourise()', () => {
|
|
9
10
|
it('should return string with colour function applied', () => {
|
|
10
|
-
const result =
|
|
11
|
+
const result = colourise('test', chalk.red)
|
|
11
12
|
assert.ok(result.includes('test'))
|
|
12
13
|
})
|
|
13
14
|
|
|
14
15
|
it('should accept colour name as string', () => {
|
|
15
|
-
const result =
|
|
16
|
+
const result = colourise('test', 'green')
|
|
16
17
|
assert.ok(result.includes('test'))
|
|
17
18
|
})
|
|
18
19
|
|
|
19
20
|
it('should return uncoloured string if no colour function provided', () => {
|
|
20
|
-
const result =
|
|
21
|
+
const result = colourise('test', null)
|
|
21
22
|
assert.equal(result, 'test')
|
|
22
23
|
})
|
|
23
24
|
|
|
24
25
|
it('should handle undefined colour function', () => {
|
|
25
|
-
const result =
|
|
26
|
+
const result = colourise('test', undefined)
|
|
26
27
|
assert.equal(result, 'test')
|
|
27
28
|
})
|
|
28
29
|
|
|
29
30
|
it('should return empty string unchanged when no colour', () => {
|
|
30
|
-
const result =
|
|
31
|
+
const result = colourise('', null)
|
|
31
32
|
assert.equal(result, '')
|
|
32
33
|
})
|
|
33
34
|
|
|
34
35
|
it('should apply colour function to empty string', () => {
|
|
35
|
-
const result =
|
|
36
|
+
const result = colourise('', chalk.red)
|
|
36
37
|
assert.equal(typeof result, 'string')
|
|
37
38
|
})
|
|
38
39
|
})
|
|
39
40
|
|
|
40
|
-
describe('
|
|
41
|
+
describe('getDateStamp()', () => {
|
|
41
42
|
it('should return empty string when timestamp is disabled', () => {
|
|
42
43
|
const config = { timestamp: false }
|
|
43
|
-
const result =
|
|
44
|
+
const result = getDateStamp(config)
|
|
44
45
|
assert.equal(result, '')
|
|
45
46
|
})
|
|
46
47
|
|
|
47
48
|
it('should return ISO format date when dateFormat is "iso"', () => {
|
|
48
49
|
const config = { timestamp: true, dateFormat: 'iso' }
|
|
49
|
-
const result =
|
|
50
|
+
const result = getDateStamp(config)
|
|
50
51
|
assert.ok(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(result))
|
|
51
52
|
})
|
|
52
53
|
|
|
53
54
|
it('should return short format date when dateFormat is "short"', () => {
|
|
54
55
|
const config = { timestamp: true, dateFormat: 'short' }
|
|
55
|
-
const result =
|
|
56
|
+
const result = getDateStamp(config)
|
|
56
57
|
assert.ok(/\d{1,2}\/\d{2}\/\d{2}-\d{1,2}:\d{1,2}:\d{2}/.test(result))
|
|
57
58
|
})
|
|
58
59
|
|
|
59
60
|
it('should return undefined-based string for unrecognised dateFormat', () => {
|
|
60
61
|
const config = { timestamp: true, dateFormat: 'unknown' }
|
|
61
|
-
const result =
|
|
62
|
+
const result = getDateStamp(config)
|
|
62
63
|
assert.ok(result.includes('undefined'))
|
|
63
64
|
})
|
|
64
65
|
|
|
65
66
|
it('should include trailing space in formatted timestamp', () => {
|
|
66
67
|
const config = { timestamp: true, dateFormat: 'iso' }
|
|
67
|
-
const result =
|
|
68
|
+
const result = getDateStamp(config)
|
|
68
69
|
assert.ok(result.includes(' '))
|
|
69
70
|
})
|
|
70
71
|
})
|
|
71
72
|
|
|
72
|
-
describe('
|
|
73
|
-
let logger
|
|
74
|
-
|
|
75
|
-
beforeEach(() => {
|
|
76
|
-
logger = new LoggerModule('test-logger')
|
|
77
|
-
logger.levelsConfig = ['error', 'warn', 'info']
|
|
78
|
-
})
|
|
79
|
-
|
|
73
|
+
describe('isLevelEnabled()', () => {
|
|
80
74
|
it('should return true for enabled levels', () => {
|
|
81
|
-
|
|
82
|
-
assert.equal(
|
|
83
|
-
assert.equal(
|
|
75
|
+
const levelsConfig = ['error', 'warn', 'info']
|
|
76
|
+
assert.equal(isLevelEnabled(levelsConfig, 'error'), true)
|
|
77
|
+
assert.equal(isLevelEnabled(levelsConfig, 'warn'), true)
|
|
78
|
+
assert.equal(isLevelEnabled(levelsConfig, 'info'), true)
|
|
84
79
|
})
|
|
85
80
|
|
|
86
81
|
it('should return false for disabled levels', () => {
|
|
87
|
-
|
|
88
|
-
assert.equal(
|
|
82
|
+
const levelsConfig = ['error', 'warn', 'info']
|
|
83
|
+
assert.equal(isLevelEnabled(levelsConfig, 'debug'), false)
|
|
84
|
+
assert.equal(isLevelEnabled(levelsConfig, 'verbose'), false)
|
|
89
85
|
})
|
|
90
86
|
|
|
91
87
|
it('should return false when level is explicitly disabled', () => {
|
|
92
|
-
|
|
93
|
-
assert.equal(
|
|
88
|
+
const levelsConfig = ['error', '!warn', 'info']
|
|
89
|
+
assert.equal(isLevelEnabled(levelsConfig, 'warn'), false)
|
|
94
90
|
})
|
|
95
91
|
|
|
96
92
|
it('should give preference to explicit disable', () => {
|
|
97
|
-
|
|
98
|
-
assert.equal(
|
|
93
|
+
const levelsConfig = ['warn', '!warn']
|
|
94
|
+
assert.equal(isLevelEnabled(levelsConfig, 'warn'), false)
|
|
99
95
|
})
|
|
100
96
|
|
|
101
97
|
it('should return false for empty levelsConfig', () => {
|
|
102
|
-
|
|
103
|
-
assert.equal(logger.isLevelEnabled('error'), false)
|
|
98
|
+
assert.equal(isLevelEnabled([], 'error'), false)
|
|
104
99
|
})
|
|
105
100
|
|
|
106
101
|
it('should not match partial level names', () => {
|
|
107
|
-
|
|
108
|
-
assert.equal(
|
|
109
|
-
assert.equal(
|
|
102
|
+
const levelsConfig = ['info']
|
|
103
|
+
assert.equal(isLevelEnabled(levelsConfig, 'inf'), false)
|
|
104
|
+
assert.equal(isLevelEnabled(levelsConfig, 'information'), false)
|
|
110
105
|
})
|
|
111
106
|
})
|
|
112
107
|
|
|
113
|
-
describe('
|
|
114
|
-
let logger
|
|
115
|
-
|
|
116
|
-
beforeEach(() => {
|
|
117
|
-
logger = new LoggerModule('test-logger')
|
|
118
|
-
})
|
|
119
|
-
|
|
108
|
+
describe('getModuleOverrides()', () => {
|
|
120
109
|
it('should return module-specific overrides for a level', () => {
|
|
121
|
-
|
|
122
|
-
const result =
|
|
110
|
+
const levelsConfig = ['error', 'error.myModule', 'error.anotherModule', 'warn']
|
|
111
|
+
const result = getModuleOverrides(levelsConfig, 'error')
|
|
123
112
|
assert.ok(result.includes('error.myModule'))
|
|
124
113
|
assert.ok(result.includes('error.anotherModule'))
|
|
125
114
|
assert.equal(result.length, 2)
|
|
126
115
|
})
|
|
127
116
|
|
|
128
117
|
it('should include negative overrides', () => {
|
|
129
|
-
|
|
130
|
-
const result =
|
|
118
|
+
const levelsConfig = ['error', '!error.myModule']
|
|
119
|
+
const result = getModuleOverrides(levelsConfig, 'error')
|
|
131
120
|
assert.ok(result.includes('!error.myModule'))
|
|
132
121
|
})
|
|
133
122
|
|
|
134
123
|
it('should return empty array when no overrides exist', () => {
|
|
135
|
-
|
|
136
|
-
const result =
|
|
124
|
+
const levelsConfig = ['error', 'warn']
|
|
125
|
+
const result = getModuleOverrides(levelsConfig, 'info')
|
|
137
126
|
assert.equal(result.length, 0)
|
|
138
127
|
})
|
|
139
128
|
|
|
140
129
|
it('should not include overrides for other levels', () => {
|
|
141
|
-
|
|
142
|
-
const result =
|
|
130
|
+
const levelsConfig = ['error', 'error.moduleA', 'warn.moduleB']
|
|
131
|
+
const result = getModuleOverrides(levelsConfig, 'error')
|
|
143
132
|
assert.ok(!result.includes('warn.moduleB'))
|
|
144
133
|
})
|
|
145
134
|
|
|
146
135
|
it('should return both positive and negative overrides together', () => {
|
|
147
|
-
|
|
148
|
-
const result =
|
|
136
|
+
const levelsConfig = ['error', 'error.modA', '!error.modB']
|
|
137
|
+
const result = getModuleOverrides(levelsConfig, 'error')
|
|
149
138
|
assert.equal(result.length, 2)
|
|
150
139
|
assert.ok(result.includes('error.modA'))
|
|
151
140
|
assert.ok(result.includes('!error.modB'))
|
|
152
141
|
})
|
|
153
142
|
|
|
154
143
|
it('should return empty array for empty levelsConfig', () => {
|
|
155
|
-
|
|
156
|
-
const result = logger.getModuleOverrides('error')
|
|
157
|
-
assert.deepEqual(result, [])
|
|
144
|
+
assert.deepEqual(getModuleOverrides([], 'error'), [])
|
|
158
145
|
})
|
|
159
146
|
})
|
|
160
147
|
|
|
161
|
-
describe('
|
|
162
|
-
let logger
|
|
163
|
-
|
|
164
|
-
beforeEach(() => {
|
|
165
|
-
logger = new LoggerModule('test-logger')
|
|
166
|
-
logger.config = {
|
|
167
|
-
levels: {
|
|
168
|
-
error: { enable: true, moduleOverrides: [] },
|
|
169
|
-
warn: { enable: false, moduleOverrides: ['warn.specific'] },
|
|
170
|
-
info: { enable: true, moduleOverrides: ['!info.blocked'] }
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
})
|
|
174
|
-
|
|
148
|
+
describe('isLoggingEnabled()', () => {
|
|
175
149
|
it('should return true for enabled levels', () => {
|
|
176
|
-
|
|
150
|
+
const levels = { error: { enable: true, moduleOverrides: [] } }
|
|
151
|
+
assert.equal(isLoggingEnabled(levels, 'error', 'anyId'), true)
|
|
177
152
|
})
|
|
178
153
|
|
|
179
154
|
it('should return false for disabled levels without overrides', () => {
|
|
180
|
-
|
|
155
|
+
const levels = { warn: { enable: false, moduleOverrides: ['warn.specific'] } }
|
|
156
|
+
assert.equal(isLoggingEnabled(levels, 'warn', 'generic'), false)
|
|
181
157
|
})
|
|
182
158
|
|
|
183
159
|
it('should return true for disabled level with positive override', () => {
|
|
184
|
-
|
|
160
|
+
const levels = { warn: { enable: false, moduleOverrides: ['warn.specific'] } }
|
|
161
|
+
assert.equal(isLoggingEnabled(levels, 'warn', 'specific'), true)
|
|
185
162
|
})
|
|
186
163
|
|
|
187
164
|
it('should return false for enabled level with negative override', () => {
|
|
188
|
-
|
|
165
|
+
const levels = { info: { enable: true, moduleOverrides: ['!info.blocked'] } }
|
|
166
|
+
assert.equal(isLoggingEnabled(levels, 'info', 'blocked'), false)
|
|
189
167
|
})
|
|
190
168
|
|
|
191
169
|
it('should return true for enabled level without override', () => {
|
|
192
|
-
|
|
170
|
+
const levels = { info: { enable: true, moduleOverrides: ['!info.blocked'] } }
|
|
171
|
+
assert.equal(isLoggingEnabled(levels, 'info', 'allowed'), true)
|
|
193
172
|
})
|
|
194
173
|
|
|
195
174
|
it('should handle missing level config gracefully', () => {
|
|
196
|
-
|
|
175
|
+
const levels = { error: { enable: true, moduleOverrides: [] } }
|
|
176
|
+
assert.equal(isLoggingEnabled(levels, 'nonexistent', 'id'), false)
|
|
197
177
|
})
|
|
198
178
|
|
|
199
179
|
it('should default moduleOverrides to empty array when undefined', () => {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
error: { enable: true }
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
assert.equal(logger.isLoggingEnabled('error', 'anyId'), true)
|
|
180
|
+
const levels = { error: { enable: true } }
|
|
181
|
+
assert.equal(isLoggingEnabled(levels, 'error', 'anyId'), true)
|
|
206
182
|
})
|
|
207
183
|
|
|
208
184
|
it('should return false when both enable is false and no matching override', () => {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
debug: { enable: false, moduleOverrides: ['debug.other'] }
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
assert.equal(logger.isLoggingEnabled('debug', 'notOther'), false)
|
|
185
|
+
const levels = { debug: { enable: false, moduleOverrides: ['debug.other'] } }
|
|
186
|
+
assert.equal(isLoggingEnabled(levels, 'debug', 'notOther'), false)
|
|
215
187
|
})
|
|
216
188
|
|
|
217
189
|
it('should handle config being undefined gracefully', () => {
|
|
218
|
-
|
|
219
|
-
assert.equal(logger.isLoggingEnabled('error', 'id'), false)
|
|
190
|
+
assert.equal(isLoggingEnabled(undefined, 'error', 'id'), false)
|
|
220
191
|
})
|
|
221
192
|
})
|
|
222
193
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { describe, it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { colourise } from '../lib/utils/colourise.js'
|
|
4
|
+
|
|
5
|
+
describe('colourise()', () => {
|
|
6
|
+
it('should return string unchanged when colourFunc is undefined', () => {
|
|
7
|
+
assert.equal(colourise('hello', undefined), 'hello')
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it('should return string unchanged when colourFunc is null', () => {
|
|
11
|
+
assert.equal(colourise('hello', null), 'hello')
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('should apply a function colour', () => {
|
|
15
|
+
const mockColour = (s) => `[coloured]${s}[/coloured]`
|
|
16
|
+
assert.equal(colourise('hello', mockColour), '[coloured]hello[/coloured]')
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('should resolve string colour names via chalk', () => {
|
|
20
|
+
// chalk resolves 'red' to chalk.red and applies it
|
|
21
|
+
const result = colourise('hello', 'red')
|
|
22
|
+
assert.ok(result.includes('hello'))
|
|
23
|
+
// chalk.red is a function, so the result should be the return value of that function
|
|
24
|
+
// In non-TTY environments chalk may strip ANSI codes, so just verify it resolved and ran
|
|
25
|
+
assert.equal(typeof result, 'string')
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('should return string unchanged for invalid chalk colour name', () => {
|
|
29
|
+
assert.equal(colourise('hello', 'notARealColour'), 'hello')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('should handle empty string input', () => {
|
|
33
|
+
const mockColour = (s) => `[c]${s}[/c]`
|
|
34
|
+
assert.equal(colourise('', mockColour), '[c][/c]')
|
|
35
|
+
})
|
|
36
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { getDateStamp } from '../lib/utils/getDateStamp.js'
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line no-control-regex
|
|
6
|
+
const ANSI_REGEX = /\u001b\[\d+m/g
|
|
7
|
+
|
|
8
|
+
describe('getDateStamp()', () => {
|
|
9
|
+
it('should return empty string when timestamp is falsy', () => {
|
|
10
|
+
assert.equal(getDateStamp({ timestamp: false, dateFormat: 'iso' }), '')
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it('should return empty string when timestamp is undefined', () => {
|
|
14
|
+
assert.equal(getDateStamp({ dateFormat: 'iso' }), '')
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('should return an ISO date string when dateFormat is "iso"', () => {
|
|
18
|
+
const result = getDateStamp({ timestamp: true, dateFormat: 'iso' })
|
|
19
|
+
const stripped = result.replace(ANSI_REGEX, '')
|
|
20
|
+
assert.ok(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z /.test(stripped))
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('should return a short date string when dateFormat is "short"', () => {
|
|
24
|
+
const result = getDateStamp({ timestamp: true, dateFormat: 'short' })
|
|
25
|
+
const stripped = result.replace(ANSI_REGEX, '')
|
|
26
|
+
assert.ok(/^\d{1,2}\/\d{2}\/\d{2}-\d{1,2}:\d{1,2}:\d{1,2} /.test(stripped))
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('should handle unknown dateFormat by returning "undefined " (colourised)', () => {
|
|
30
|
+
const result = getDateStamp({ timestamp: true, dateFormat: 'unknown' })
|
|
31
|
+
const stripped = result.replace(ANSI_REGEX, '')
|
|
32
|
+
assert.equal(stripped, 'undefined ')
|
|
33
|
+
})
|
|
34
|
+
})
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { describe, it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { getModuleOverrides } from '../lib/utils/getModuleOverrides.js'
|
|
4
|
+
|
|
5
|
+
describe('getModuleOverrides()', () => {
|
|
6
|
+
it('should return empty array when no overrides exist', () => {
|
|
7
|
+
assert.deepEqual(getModuleOverrides(['error', 'warn', 'info'], 'debug'), [])
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it('should return module-specific includes', () => {
|
|
11
|
+
const config = ['error', 'debug.mymod', 'debug.other']
|
|
12
|
+
assert.deepEqual(getModuleOverrides(config, 'debug'), ['debug.mymod', 'debug.other'])
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('should return module-specific excludes', () => {
|
|
16
|
+
const config = ['error', '!debug.mymod']
|
|
17
|
+
assert.deepEqual(getModuleOverrides(config, 'debug'), ['!debug.mymod'])
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('should return both includes and excludes', () => {
|
|
21
|
+
const config = ['error', 'debug.mymod', '!debug.other', 'debug.third']
|
|
22
|
+
const result = getModuleOverrides(config, 'debug')
|
|
23
|
+
assert.deepEqual(result, ['debug.mymod', '!debug.other', 'debug.third'])
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('should not include plain level entries', () => {
|
|
27
|
+
const config = ['debug', 'debug.mymod']
|
|
28
|
+
assert.deepEqual(getModuleOverrides(config, 'debug'), ['debug.mymod'])
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('should not match other levels with similar prefixes', () => {
|
|
32
|
+
const config = ['error.mymod', 'warn.mymod']
|
|
33
|
+
assert.deepEqual(getModuleOverrides(config, 'error'), ['error.mymod'])
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('should handle empty config', () => {
|
|
37
|
+
assert.deepEqual(getModuleOverrides([], 'error'), [])
|
|
38
|
+
})
|
|
39
|
+
})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { isLevelEnabled } from '../lib/utils/isLevelEnabled.js'
|
|
4
|
+
|
|
5
|
+
describe('isLevelEnabled()', () => {
|
|
6
|
+
it('should return true when level is in config', () => {
|
|
7
|
+
assert.equal(isLevelEnabled(['error', 'warn', 'info'], 'error'), true)
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it('should return false when level is not in config', () => {
|
|
11
|
+
assert.equal(isLevelEnabled(['error', 'warn'], 'debug'), false)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('should return false when level is explicitly disabled', () => {
|
|
15
|
+
assert.equal(isLevelEnabled(['error', '!warn', 'warn'], 'warn'), false)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('should return true when level is present and not explicitly disabled', () => {
|
|
19
|
+
assert.equal(isLevelEnabled(['error', 'warn', '!debug'], 'warn'), true)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('should return false for empty config', () => {
|
|
23
|
+
assert.equal(isLevelEnabled([], 'error'), false)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('should not match partial level names', () => {
|
|
27
|
+
assert.equal(isLevelEnabled(['error.mymod'], 'error'), false)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('should handle explicit disable taking precedence even when level is included', () => {
|
|
31
|
+
assert.equal(isLevelEnabled(['debug', '!debug'], 'debug'), false)
|
|
32
|
+
})
|
|
33
|
+
})
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { describe, it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { isLoggingEnabled } from '../lib/utils/isLoggingEnabled.js'
|
|
4
|
+
|
|
5
|
+
describe('isLoggingEnabled()', () => {
|
|
6
|
+
it('should return true when level is globally enabled', () => {
|
|
7
|
+
const levels = { error: { enable: true, moduleOverrides: [] } }
|
|
8
|
+
assert.equal(isLoggingEnabled(levels, 'error', 'mymod'), true)
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('should return false when level is globally disabled and no override', () => {
|
|
12
|
+
const levels = { error: { enable: false, moduleOverrides: [] } }
|
|
13
|
+
assert.equal(isLoggingEnabled(levels, 'error', 'mymod'), false)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('should return true when module has an include override', () => {
|
|
17
|
+
const levels = { debug: { enable: false, moduleOverrides: ['debug.mymod'] } }
|
|
18
|
+
assert.equal(isLoggingEnabled(levels, 'debug', 'mymod'), true)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('should return false when module has a disable override', () => {
|
|
22
|
+
const levels = { error: { enable: true, moduleOverrides: ['!error.mymod'] } }
|
|
23
|
+
assert.equal(isLoggingEnabled(levels, 'error', 'mymod'), false)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('should return false when both include and disable override exist', () => {
|
|
27
|
+
const levels = { debug: { enable: false, moduleOverrides: ['debug.mymod', '!debug.mymod'] } }
|
|
28
|
+
assert.equal(isLoggingEnabled(levels, 'debug', 'mymod'), false)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('should return false when level is not in config', () => {
|
|
32
|
+
const levels = { error: { enable: true, moduleOverrides: [] } }
|
|
33
|
+
assert.equal(isLoggingEnabled(levels, 'debug', 'mymod'), false)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('should handle null/undefined configLevels gracefully', () => {
|
|
37
|
+
assert.equal(isLoggingEnabled(null, 'error', 'mymod'), false)
|
|
38
|
+
assert.equal(isLoggingEnabled(undefined, 'error', 'mymod'), false)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('should default moduleOverrides to empty array when missing', () => {
|
|
42
|
+
const levels = { error: { enable: true } }
|
|
43
|
+
assert.equal(isLoggingEnabled(levels, 'error', 'mymod'), true)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('should not match overrides for different modules', () => {
|
|
47
|
+
const levels = { debug: { enable: false, moduleOverrides: ['debug.other'] } }
|
|
48
|
+
assert.equal(isLoggingEnabled(levels, 'debug', 'mymod'), false)
|
|
49
|
+
})
|
|
50
|
+
})
|