@athenna/logger 1.2.6 → 1.2.9

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.
@@ -9,17 +9,16 @@
9
9
 
10
10
  import { Config } from '@secjs/utils'
11
11
 
12
+ import { FactoryHelper } from '#src/index'
12
13
  import { FileDriver } from '#src/Drivers/FileDriver'
13
14
  import { NullDriver } from '#src/Drivers/NullDriver'
14
- import { PinoDriver } from '#src/Drivers/PinoDriver'
15
- import { DebugDriver } from '#src/Drivers/DebugDriver'
16
15
  import { SlackDriver } from '#src/Drivers/SlackDriver'
17
16
  import { ConsoleDriver } from '#src/Drivers/ConsoleDriver'
18
17
  import { DiscordDriver } from '#src/Drivers/DiscordDriver'
19
18
  import { TelegramDriver } from '#src/Drivers/TelegramDriver'
20
19
  import { DriverExistException } from '#src/Exceptions/DriverExistException'
21
20
  import { NotFoundDriverException } from '#src/Exceptions/NotFoundDriverException'
22
- import { NotFoundChannelException } from '#src/Exceptions/NotFoundChannelException'
21
+ import { NotImplementedConfigException } from '#src/Exceptions/NotImplementedConfigException'
23
22
 
24
23
  export class DriverFactory {
25
24
  /**
@@ -27,12 +26,10 @@ export class DriverFactory {
27
26
  *
28
27
  * @type {Map<string, { Driver: any }>}
29
28
  */
30
- static drivers = new Map()
29
+ static #drivers = new Map()
31
30
  .set('file', { Driver: FileDriver })
32
31
  .set('null', { Driver: NullDriver })
33
- .set('pino', { Driver: PinoDriver })
34
32
  .set('slack', { Driver: SlackDriver })
35
- .set('debug', { Driver: DebugDriver })
36
33
  .set('console', { Driver: ConsoleDriver })
37
34
  .set('discord', { Driver: DiscordDriver })
38
35
  .set('telegram', { Driver: TelegramDriver })
@@ -45,7 +42,7 @@ export class DriverFactory {
45
42
  static availableDrivers() {
46
43
  const availableDrivers = []
47
44
 
48
- for (const [key] of this.drivers.entries()) {
45
+ for (const key of this.#drivers.keys()) {
49
46
  availableDrivers.push(key)
50
47
  }
51
48
 
@@ -61,18 +58,13 @@ export class DriverFactory {
61
58
  * @return {any}
62
59
  */
63
60
  static fabricate(channelName, runtimeConfig = {}) {
64
- if (channelName === 'default') {
65
- channelName = Config.get('logging.default')
66
- }
67
-
68
61
  const channelConfig = this.#getChannelConfig(channelName)
69
- const driverObject = this.drivers.get(channelConfig.driver)
70
62
 
71
- if (!driverObject) {
72
- throw new NotFoundDriverException(channelConfig.driver)
73
- }
63
+ const { Driver } = this.#drivers.get(channelConfig.driver)
74
64
 
75
- return new driverObject.Driver(channelName, runtimeConfig)
65
+ const configs = FactoryHelper.groupConfigs(runtimeConfig, channelConfig)
66
+
67
+ return new Driver(configs)
76
68
  }
77
69
 
78
70
  /**
@@ -82,11 +74,11 @@ export class DriverFactory {
82
74
  * @param {(channel: string, configs?: any) => any} driver
83
75
  */
84
76
  static createDriver(name, driver) {
85
- if (this.drivers.has(name)) {
77
+ if (this.#drivers.has(name)) {
86
78
  throw new DriverExistException(name)
87
79
  }
88
80
 
89
- this.drivers.set(name, { Driver: driver })
81
+ this.#drivers.set(name, { Driver: driver })
90
82
  }
91
83
 
92
84
  /**
@@ -96,13 +88,17 @@ export class DriverFactory {
96
88
  * @return {any}
97
89
  */
98
90
  static #getChannelConfig(channelName) {
91
+ if (channelName === 'default') {
92
+ channelName = Config.get('logging.default')
93
+ }
94
+
99
95
  const channelConfig = Config.get(`logging.channels.${channelName}`)
100
96
 
101
97
  if (!channelConfig) {
102
- throw new NotFoundChannelException(channelName)
98
+ throw new NotImplementedConfigException(channelName)
103
99
  }
104
100
 
105
- if (!this.drivers.has(channelConfig.driver)) {
101
+ if (!this.#drivers.has(channelConfig.driver)) {
106
102
  throw new NotFoundDriverException(channelConfig.driver)
107
103
  }
108
104
 
@@ -8,7 +8,6 @@
8
8
  */
9
9
 
10
10
  import { CliFormatter } from '#src/Formatters/CliFormatter'
11
- import { NestFormatter } from '#src/Formatters/NestFormatter'
12
11
  import { JsonFormatter } from '#src/Formatters/JsonFormatter'
13
12
  import { NoneFormatter } from '#src/Formatters/NoneFormatter'
14
13
  import { SimpleFormatter } from '#src/Formatters/SimpleFormatter'
@@ -25,7 +24,6 @@ export class FormatterFactory {
25
24
  */
26
25
  static formatters = new Map()
27
26
  .set('cli', { Formatter: CliFormatter })
28
- .set('nest', { Formatter: NestFormatter })
29
27
  .set('json', { Formatter: JsonFormatter })
30
28
  .set('none', { Formatter: NoneFormatter })
31
29
  .set('simple', { Formatter: SimpleFormatter })
@@ -7,24 +7,18 @@
7
7
  * file that was distributed with this source code.
8
8
  */
9
9
 
10
- import { FactoryHelper } from '#src/index'
10
+ import { Formatter } from '#src/Formatters/Formatter'
11
11
 
12
- export class CliFormatter {
12
+ export class CliFormatter extends Formatter {
13
13
  /**
14
14
  * Format the message.
15
15
  *
16
16
  * @param {string} message
17
- * @param {{ level: 'info'|'INFO'|'debug'|'DEBUG'|'warn'|'WARN'|'error'|'ERROR'|'success'|'SUCCESS', chalk: import('chalk').ChalkInstance }} options
18
17
  * @return {string}
19
18
  */
20
- format(message, options) {
21
- options.level = options.level.toLowerCase()
19
+ format(message) {
20
+ const level = this.cliLevel()
22
21
 
23
- const level = FactoryHelper.paintByLevel(
24
- options.level,
25
- `[ ${options.level} ]`,
26
- )
27
-
28
- return `${level} ${message}`
22
+ return this.clean(`${level} ${this.toString(message)}`)
29
23
  }
30
24
  }
@@ -0,0 +1,245 @@
1
+ /**
2
+ * @athenna/logger
3
+ *
4
+ * (c) João Lenon <lenon@athenna.io>
5
+ *
6
+ * For the full copyright and license information, please view the LICENSE
7
+ * file that was distributed with this source code.
8
+ */
9
+
10
+ import { hostname } from 'node:os'
11
+
12
+ import { Is } from '@secjs/utils'
13
+
14
+ import { ColorHelper } from '#src/Helpers/ColorHelper'
15
+
16
+ export class Formatter {
17
+ /**
18
+ * Holds the configuration object of formatter.
19
+ */
20
+ configs = {}
21
+
22
+ /**
23
+ * Creates a new instance of Formatter.
24
+ *
25
+ * @param {any} configs
26
+ * @return {Formatter}
27
+ */
28
+ config(configs) {
29
+ this.configs = configs
30
+
31
+ return this
32
+ }
33
+
34
+ /**
35
+ * Format the message.
36
+ *
37
+ * @param {string} message
38
+ * @return {string}
39
+ */
40
+ format(message) {}
41
+
42
+ /**
43
+ * Create the PID for formatter.
44
+ *
45
+ * @return {string}
46
+ */
47
+ pid() {
48
+ return process.pid.toString()
49
+ }
50
+
51
+ /**
52
+ * Create the hostname for formatter.
53
+ *
54
+ * @return {string}
55
+ */
56
+ hostname() {
57
+ return hostname()
58
+ }
59
+
60
+ /**
61
+ * Create the timestamp for formatter.
62
+ *
63
+ * @return {string}
64
+ */
65
+ timestamp() {
66
+ const localeStringOptions = {
67
+ year: 'numeric',
68
+ hour: 'numeric',
69
+ minute: 'numeric',
70
+ second: 'numeric',
71
+ day: '2-digit',
72
+ month: '2-digit',
73
+ }
74
+
75
+ return new Date(Date.now()).toLocaleString(undefined, localeStringOptions)
76
+ }
77
+
78
+ /**
79
+ * Transform the message to string.
80
+ *
81
+ * @param message {string}
82
+ * @return {string}
83
+ */
84
+ toString(message) {
85
+ if (Is.String(message)) {
86
+ return message
87
+ }
88
+
89
+ if (Is.Object(message)) {
90
+ message = JSON.stringify(message)
91
+ }
92
+
93
+ return `${message}`
94
+ }
95
+
96
+ /**
97
+ * Clean the message removing colors if clean
98
+ * option is true.
99
+ *
100
+ * @param message {string}
101
+ * @return {string}
102
+ */
103
+ clean(message) {
104
+ if (this.configs.clean) {
105
+ return ColorHelper.removeColors(message)
106
+ }
107
+
108
+ return message
109
+ }
110
+
111
+ /**
112
+ * Apply all colors necessary to message.
113
+ *
114
+ * @param message {string}
115
+ * @return {string}
116
+ */
117
+ applyColors(message) {
118
+ message = this.toString(message)
119
+
120
+ return this.applyColorsByChalk(this.applyColorsByLevel(message))
121
+ }
122
+
123
+ /**
124
+ * Apply colors in message.
125
+ *
126
+ * @param message {string}
127
+ * @return {string}
128
+ */
129
+ applyColorsByChalk(message) {
130
+ if (!this.configs.chalk) {
131
+ return message
132
+ }
133
+
134
+ return this.configs.chalk(message)
135
+ }
136
+
137
+ /**
138
+ * Apply colors in message by level.
139
+ *
140
+ * @param message {string}
141
+ * @return {string}
142
+ */
143
+ applyColorsByLevel(message) {
144
+ const level = this.configs.level
145
+
146
+ return this.paintMessageByLevel(level, message)
147
+ }
148
+
149
+ /**
150
+ * Create the cli level string.
151
+ *
152
+ * @return {string}
153
+ */
154
+ cliLevel() {
155
+ const level = this.configs.level
156
+
157
+ if (!ColorHelper[level]) {
158
+ return level
159
+ }
160
+
161
+ return ColorHelper[level].bold(`[ ${level} ]`)
162
+ }
163
+
164
+ /**
165
+ * Create the simple level string.
166
+ *
167
+ * @return {string}
168
+ */
169
+ simpleLevel() {
170
+ const level = this.configs.level
171
+
172
+ if (!ColorHelper[level]) {
173
+ return level
174
+ }
175
+
176
+ return ColorHelper[level].bold(`[${level.toUpperCase()}]`)
177
+ }
178
+
179
+ /**
180
+ * Create the message level emoji string.
181
+ *
182
+ * @return {string}
183
+ */
184
+ messageLevel() {
185
+ const level = this.configs.level
186
+
187
+ return this.getEmojiByLevel(level, this.configs.customEmoji)
188
+ }
189
+
190
+ /**
191
+ * Get the emoji by level.
192
+ *
193
+ * @param {string} level
194
+ * @param {string} [customEmoji]
195
+ * @return {string}
196
+ */
197
+ getEmojiByLevel(level, customEmoji) {
198
+ if (customEmoji) {
199
+ return customEmoji
200
+ }
201
+
202
+ const levelEmojis = {
203
+ trace: '\u{1F43E}',
204
+ debug: '\u{1F50E}',
205
+ info: '\u{2139}',
206
+ success: '\u{2705}',
207
+ warn: '\u{26A0}',
208
+ error: '\u{274C}',
209
+ fatal: '\u{1F6D1}',
210
+ }
211
+
212
+ if (!levelEmojis[level.toLowerCase()]) {
213
+ return ''
214
+ }
215
+
216
+ return levelEmojis[level.toLowerCase()]
217
+ }
218
+
219
+ /**
220
+ * Paint the message by level.
221
+ *
222
+ * @param {string} level
223
+ * @param {string} message
224
+ * @return {string}
225
+ */
226
+ paintMessageByLevel(level, message) {
227
+ const levelLower = level.toLowerCase()
228
+
229
+ const levelColors = {
230
+ trace: ColorHelper.trace,
231
+ debug: ColorHelper.debug,
232
+ info: ColorHelper.info,
233
+ success: ColorHelper.success,
234
+ warn: ColorHelper.warn,
235
+ error: ColorHelper.error,
236
+ fatal: ColorHelper.fatal,
237
+ }
238
+
239
+ if (!levelColors[levelLower]) {
240
+ return message
241
+ }
242
+
243
+ return levelColors[levelLower](message)
244
+ }
245
+ }
@@ -7,18 +7,30 @@
7
7
  * file that was distributed with this source code.
8
8
  */
9
9
 
10
- import { ColorHelper } from '#src/index'
10
+ import { Is } from '@secjs/utils'
11
+ import { Formatter } from '#src/Formatters/Formatter'
11
12
 
12
- export class JsonFormatter {
13
+ export class JsonFormatter extends Formatter {
13
14
  /**
15
+ * Format the message.
14
16
  *
15
- * @param {Record<any, any>} message
16
- * @param {{ chalk: import('chalk').ChalkInstance }} options
17
+ * @param {any} message
17
18
  * @return {string}
18
19
  */
19
- format(message, options) {
20
- const jsonSpaced = JSON.stringify(message, null, 2)
20
+ format(message) {
21
+ const base = {
22
+ level: this.configs.level,
23
+ time: Date.now(),
24
+ pid: this.pid(),
25
+ hostname: this.hostname(),
26
+ }
21
27
 
22
- return `${ColorHelper.bold('JSON:')} ${options.chalk(jsonSpaced)}`
28
+ if (Is.String(message)) {
29
+ base.msg = message
30
+
31
+ return JSON.stringify(base)
32
+ }
33
+
34
+ return JSON.stringify({ ...base, ...message })
23
35
  }
24
36
  }
@@ -1,4 +1,3 @@
1
- /* eslint-disable prettier/prettier */
2
1
  /**
3
2
  * @athenna/logger
4
3
  *
@@ -8,33 +7,20 @@
8
7
  * file that was distributed with this source code.
9
8
  */
10
9
 
11
- import { FactoryHelper } from '#src/index'
12
-
13
- export class MessageFormatter {
14
- /**
15
- * The last timestamp.
16
- *
17
- * @type {number}
18
- */
19
- #lastTimestamp
10
+ import { Formatter } from '#src/Formatters/Formatter'
20
11
 
12
+ export class MessageFormatter extends Formatter {
21
13
  /**
22
14
  * Format the message.
23
15
  *
24
16
  * @param {string} message
25
- * @param {{ level: 'info'|'INFO'|'debug'|'DEBUG'|'warn'|'WARN'|'error'|'ERROR'|'success'|'SUCCESS', customEmoji: string }} options
26
17
  * @return {string}
27
18
  */
28
- format(message, options) {
29
- const timestampDiff = FactoryHelper.getTimestampDiff(this.#lastTimestamp)
30
-
31
- this.#lastTimestamp = Date.now()
32
-
33
- const level = FactoryHelper.getEmojiByLevel(
34
- options.level,
35
- options.customEmoji,
19
+ format(message) {
20
+ return this.clean(
21
+ `${this.messageLevel()} - (${this.pid()}) - (${this.hostname()}): ${this.toString(
22
+ message,
23
+ )}`,
36
24
  )
37
-
38
- return `${level} ${message}${timestampDiff}`
39
25
  }
40
26
  }
@@ -7,15 +7,16 @@
7
7
  * file that was distributed with this source code.
8
8
  */
9
9
 
10
- export class NoneFormatter {
10
+ import { Formatter } from '#src/Formatters/Formatter'
11
+
12
+ export class NoneFormatter extends Formatter {
11
13
  /**
12
14
  * Format the message.
13
15
  *
14
16
  * @param {string} message
15
- * @param {any} [_options]
16
17
  * @return {string}
17
18
  */
18
- format(message, _options) {
19
- return message
19
+ format(message) {
20
+ return this.clean(this.toString(message))
20
21
  }
21
22
  }
@@ -8,16 +8,16 @@
8
8
  */
9
9
 
10
10
  import { ColorHelper } from '#src/index'
11
+ import { Formatter } from '#src/Formatters/Formatter'
11
12
 
12
- export class RequestFormatter {
13
+ export class RequestFormatter extends Formatter {
13
14
  /**
14
15
  * Format the message.
15
16
  *
16
17
  * @param {any} ctx
17
- * @param {{ asJson: boolean, chalk: import('chalk').ChalkInstance }} options
18
18
  * @return {string}
19
19
  */
20
- format(ctx, options) {
20
+ format(ctx) {
21
21
  const ip = ctx.request.ip
22
22
  const status = ctx.status
23
23
  const responseTimeMs = `${Math.round(ctx.responseTime)}ms`
@@ -25,8 +25,10 @@ export class RequestFormatter {
25
25
  `${ctx.request.method}::${ctx.request.baseUrl}`,
26
26
  )
27
27
 
28
- if (!options.asJson) {
29
- return `(${ip}) - [${status}] ${methodAndUrl} ${responseTimeMs}`
28
+ if (!this.configs.asJson) {
29
+ return this.clean(
30
+ `(${ip}) - [${status}] ${methodAndUrl} ${responseTimeMs}`,
31
+ )
30
32
  }
31
33
 
32
34
  const metadata = {
@@ -7,33 +7,22 @@
7
7
  * file that was distributed with this source code.
8
8
  */
9
9
 
10
- import { FactoryHelper } from '#src/index'
11
-
12
- export class SimpleFormatter {
13
- /**
14
- * The last timestamp.
15
- *
16
- * @type {number}
17
- */
18
- #lastTimestamp
10
+ import { Formatter } from '#src/Formatters/Formatter'
19
11
 
12
+ export class SimpleFormatter extends Formatter {
20
13
  /**
21
14
  * Format the message.
22
15
  *
23
16
  * @param {string} message
24
- * @param {{ level: 'info'|'INFO'|'debug'|'DEBUG'|'warn'|'WARN'|'error'|'ERROR'|'success'|'SUCCESS', chalk: import('chalk').ChalkInstance }} options
25
17
  * @return {string}
26
18
  */
27
- format(message, options) {
28
- const timestampDiff = FactoryHelper.getTimestampDiff(this.#lastTimestamp)
29
- this.#lastTimestamp = Date.now()
19
+ format(message) {
20
+ const level = this.simpleLevel()
30
21
 
31
- const timestamp = FactoryHelper.getTimestamp()
32
- const level = FactoryHelper.paintByLevel(
33
- options.level.toLowerCase(),
34
- `[${options.level.toUpperCase()}]`,
22
+ return this.clean(
23
+ `${level} - ${this.timestamp()} - (${this.pid()}) ${this.applyColors(
24
+ message,
25
+ )}`,
35
26
  )
36
-
37
- return `${level} - ${timestamp} ${options.chalk(message)}${timestampDiff}`
38
27
  }
39
28
  }
@@ -26,6 +26,15 @@ export class ColorHelper {
26
26
  return ColorHelper.chalk.bold
27
27
  }
28
28
 
29
+ /**
30
+ * Paint as grey.
31
+ *
32
+ * @return {import('chalk').ChalkInstance}
33
+ */
34
+ static get grey() {
35
+ return ColorHelper.chalk.hex('#505050')
36
+ }
37
+
29
38
  /**
30
39
  * Paint as purple.
31
40
  *
@@ -117,12 +126,12 @@ export class ColorHelper {
117
126
  }
118
127
 
119
128
  /**
120
- * Paint infos.
129
+ * Paint debugs.
121
130
  *
122
131
  * @return {import('chalk').ChalkInstance}
123
132
  */
124
- static get info() {
125
- return this.cyan.bold
133
+ static get trace() {
134
+ return this.grey.bold
126
135
  }
127
136
 
128
137
  /**
@@ -135,12 +144,12 @@ export class ColorHelper {
135
144
  }
136
145
 
137
146
  /**
138
- * Paint error.
147
+ * Paint infos.
139
148
  *
140
149
  * @return {import('chalk').ChalkInstance}
141
150
  */
142
- static get error() {
143
- return this.red.bold
151
+ static get info() {
152
+ return this.cyan
144
153
  }
145
154
 
146
155
  /**
@@ -149,25 +158,34 @@ export class ColorHelper {
149
158
  * @return {import('chalk').ChalkInstance}
150
159
  */
151
160
  static get success() {
152
- return this.green.bold
161
+ return this.green
153
162
  }
154
163
 
155
164
  /**
156
- * Paint critical.
165
+ * Paint warning.
157
166
  *
158
167
  * @return {import('chalk').ChalkInstance}
159
168
  */
160
- static get critical() {
161
- return this.darkRed.bold
169
+ static get warn() {
170
+ return this.orange
162
171
  }
163
172
 
164
173
  /**
165
- * Paint warning.
174
+ * Paint error.
166
175
  *
167
176
  * @return {import('chalk').ChalkInstance}
168
177
  */
169
- static get warning() {
170
- return this.orange.bold
178
+ static get error() {
179
+ return this.red
180
+ }
181
+
182
+ /**
183
+ * Paint fatal.
184
+ *
185
+ * @return {import('chalk').ChalkInstance}
186
+ */
187
+ static get fatal() {
188
+ return ColorHelper.chalk.bgRed
171
189
  }
172
190
 
173
191
  /**
@@ -237,7 +255,7 @@ export class ColorHelper {
237
255
  * Remove all colors and special chars of string.
238
256
  *
239
257
  * @param {string} string
240
- * @return {import('chalk').ChalkInstance}
258
+ * @return {string}
241
259
  */
242
260
  static removeColors(string) {
243
261
  return ColorHelper.chalk.reset(string).replace(