@athenna/logger 1.2.8 → 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.
package/README.md CHANGED
@@ -31,4 +31,12 @@
31
31
 
32
32
  ---
33
33
 
34
- Made with 🖤 by [Athenna Team](https://github.com/AthennaIO) :wave:
34
+ <p align='center'>
35
+ With 💜 by <a href='https://github.com/AthennaIO'>Athenna community</a>
36
+ </p>
37
+
38
+ <p align='center'>
39
+ <a href='https://github.com/AthennaIO/Logger/graphs/contributors'>
40
+ <img src='https://contrib.rocks/image?repo=AthennaIO/Logger'/>
41
+ </a>
42
+ </p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@athenna/logger",
3
- "version": "1.2.8",
3
+ "version": "1.2.9",
4
4
  "description": "The Athenna logging solution. Log in stdout, files and buckets.",
5
5
  "license": "MIT",
6
6
  "author": "João Lenon <lenon@athenna.io>",
@@ -47,13 +47,10 @@
47
47
  "./providers/LoggerProvider": "./src/Providers/LoggerProvider.js"
48
48
  },
49
49
  "dependencies": {
50
- "@athenna/ioc": "1.2.3",
51
- "@secjs/utils": "1.9.7",
50
+ "@athenna/ioc": "1.2.4",
51
+ "@secjs/utils": "1.9.9",
52
52
  "axios": "0.26.1",
53
53
  "chalk": "5.0.1",
54
- "debug": "4.3.4",
55
- "pino": "7.10.0",
56
- "pino-pretty": "7.6.1",
57
54
  "telegraf": "4.7.0"
58
55
  },
59
56
  "devDependencies": {
@@ -62,9 +59,10 @@
62
59
  "@japa/runner": "2.0.7",
63
60
  "@japa/spec-reporter": "1.1.12",
64
61
  "c8": "7.11.2",
65
- "commitizen": "4.2.4",
62
+ "commitizen": "4.2.5",
66
63
  "cross-env": "7.0.3",
67
64
  "cz-conventional-changelog": "3.3.0",
65
+ "dotenv": "^16.0.2",
68
66
  "eslint": "8.14.0",
69
67
  "eslint-config-prettier": "8.5.0",
70
68
  "eslint-config-standard": "17.0.0",
@@ -84,16 +82,15 @@
84
82
  "include": [
85
83
  "src/**/*.js"
86
84
  ],
85
+ "exclude": [
86
+ "src/Helpers/ColorHelper.js"
87
+ ],
87
88
  "reporter": [
88
89
  "text-summary",
89
90
  "html"
90
91
  ],
91
92
  "report-dir": "./tests/Coverage",
92
- "check-coverage": true,
93
- "statements": "80",
94
- "branches": "80",
95
- "functions": "50",
96
- "lines": "80"
93
+ "check-coverage": true
97
94
  },
98
95
  "husky": {
99
96
  "hooks": {
@@ -7,46 +7,34 @@
7
7
  * file that was distributed with this source code.
8
8
  */
9
9
 
10
- import { Config } from '@secjs/utils'
11
-
12
- import { FactoryHelper, FormatterFactory } from '#src/index'
13
-
14
- export class ConsoleDriver {
15
- /**
16
- * Holds the configuration set of ConsoleDriver.
17
- *
18
- * @type {{ streamType?: 'stdout' | 'stderr', formatter?: any, formatterConfig?: any }}
19
- */
20
- configs
10
+ import { Driver } from '#src/Drivers/Driver'
21
11
 
12
+ export class ConsoleDriver extends Driver {
22
13
  /**
23
14
  * Creates a new instance of ConsoleDriver.
24
15
  *
25
- * @param {string} channel
26
- * @param {any} [configs]
16
+ * @param {any} configs
27
17
  * @return {ConsoleDriver}
28
18
  */
29
- constructor(channel, configs) {
30
- const channelConfig = Config.get(`logging.channels.${channel}`)
31
-
32
- this.configs = FactoryHelper.groupConfigs(configs, channelConfig)
19
+ constructor(configs) {
20
+ super(configs)
33
21
  }
34
22
 
35
23
  /**
36
24
  * Transport the log.
37
25
  *
38
- * @param {string} message
39
- * @param {{ streamType?: 'stdout' | 'stderr', formatter?: any, formatterConfig?: any }} [options]
40
- * @return {void}
26
+ * @param {string} level
27
+ * @param {any} message
28
+ * @return {any}
41
29
  */
42
- transport(message, options = {}) {
43
- const configs = FactoryHelper.groupConfigs(options, this.configs)
30
+ transport(level, message) {
31
+ if (!this.couldBeTransported(level)) {
32
+ return
33
+ }
44
34
 
45
- message = FormatterFactory.fabricate(configs.formatter).format(
46
- message,
47
- configs.formatterConfig,
48
- )
35
+ const formatted = this.format(level, message)
36
+ const streamType = this.getStreamTypeFor(level)
49
37
 
50
- process[configs.streamType].write(`${message}\n`)
38
+ return process[streamType].write(`${formatted}\n`)
51
39
  }
52
40
  }
@@ -9,49 +9,36 @@
9
9
 
10
10
  import axios from 'axios'
11
11
 
12
- import { Config } from '@secjs/utils'
13
-
14
- import { ColorHelper, FactoryHelper, FormatterFactory } from '#src/index'
15
-
16
- export class DiscordDriver {
17
- /**
18
- * Holds the configuration set of DiscordDriver.
19
- *
20
- * @type {{ url?: string, username?: string, formatter?: any, formatterConfig?: any }}
21
- */
22
- configs
12
+ import { Driver } from '#src/Drivers/Driver'
23
13
 
14
+ export class DiscordDriver extends Driver {
24
15
  /**
25
16
  * Creates a new instance of DiscordDriver.
26
17
  *
27
- * @param {string} channel
28
- * @param {any} [configs]
18
+ * @param {any} configs
29
19
  * @return {DiscordDriver}
30
20
  */
31
- constructor(channel, configs = {}) {
32
- const channelConfig = Config.get(`logging.channels.${channel}`)
33
-
34
- this.configs = FactoryHelper.groupConfigs(configs, channelConfig)
21
+ constructor(configs) {
22
+ super(configs)
35
23
  }
36
24
 
37
25
  /**
38
26
  * Transport the log.
39
27
  *
28
+ * @param {string} level
40
29
  * @param {string} message
41
- * @param {{ url?: string, username?: string, formatter?: any, formatterConfig?: any }} [options]
42
- * @return {Promise<void>}
30
+ * @return {Promise<any>}
43
31
  */
44
- async transport(message, options = {}) {
45
- const configs = FactoryHelper.groupConfigs(options, this.configs)
32
+ async transport(level, message) {
33
+ if (!this.couldBeTransported(level)) {
34
+ return
35
+ }
46
36
 
47
- message = FormatterFactory.fabricate(configs.formatter).format(
48
- message,
49
- configs.formatterConfig,
50
- )
37
+ const formatted = this.format(level, message, true)
51
38
 
52
- await axios.post(configs.url, {
53
- username: configs.username,
54
- content: ColorHelper.removeColors(message),
39
+ return axios.post(this.configs.url, {
40
+ username: this.configs.username,
41
+ content: formatted,
55
42
  })
56
43
  }
57
44
  }
@@ -0,0 +1,134 @@
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 { Json } from '@secjs/utils'
11
+ import { FormatterFactory } from '#src/index'
12
+
13
+ export class Driver {
14
+ /**
15
+ * Holds the configuration object itself.
16
+ *
17
+ * @type {any}
18
+ */
19
+ configs = {}
20
+
21
+ /**
22
+ * Holds the configuration object of driver.
23
+ *
24
+ * @type {any}
25
+ */
26
+ driverConfig = {}
27
+
28
+ /**
29
+ * Holds the formatter string value.
30
+ *
31
+ * @type {string}
32
+ */
33
+ formatter = 'none'
34
+
35
+ /**
36
+ * Holds the configuration object of formatter.
37
+ *
38
+ * @type {any}
39
+ */
40
+ formatterConfig = {}
41
+
42
+ /**
43
+ * The max log level that this driver can transport.
44
+ *
45
+ * @return {string}
46
+ */
47
+ level = 'info'
48
+
49
+ /**
50
+ * The log level order to check if log could
51
+ * be transported or not.
52
+ *
53
+ * @type {string[]}
54
+ */
55
+ levelOrder = ['trace', 'debug', 'info', 'success', 'warn', 'error', 'fatal']
56
+
57
+ /**
58
+ * Creates a new instance of ConsoleDriver.
59
+ *
60
+ * @param {any} configs
61
+ * @return {ConsoleDriver}
62
+ */
63
+ constructor(configs) {
64
+ this.configs = configs
65
+
66
+ const json = Json.copy(configs)
67
+
68
+ delete json.formatter
69
+ delete json.formatterConfig
70
+
71
+ this.driverConfig = json
72
+ this.level = json.level || 'info'
73
+ this.formatter = configs.formatter
74
+ this.formatterConfig = configs.formatterConfig
75
+ }
76
+
77
+ /**
78
+ * Transport the log.
79
+ *
80
+ * @param {string} level
81
+ * @param {string} message
82
+ * @return {any | Promise<any>}
83
+ */
84
+ transport(level, message) {}
85
+
86
+ /**
87
+ * Check if message could be transported.
88
+ *
89
+ * @param level {string}
90
+ * @return {boolean}
91
+ */
92
+ couldBeTransported(level) {
93
+ const levelIndex = this.levelOrder.indexOf(level)
94
+ const maxLevelIndex = this.levelOrder.indexOf(this.level)
95
+
96
+ return levelIndex >= maxLevelIndex
97
+ }
98
+
99
+ /**
100
+ * Call formatter factory to format the message.
101
+ *
102
+ * @param level {string}
103
+ * @param message {string}
104
+ * @param [clean] {boolean}
105
+ * @return {any}
106
+ */
107
+ format(level, message, clean = false) {
108
+ const formatterConfig = { level, clean, ...this.formatterConfig }
109
+
110
+ return FormatterFactory.fabricate(this.formatter)
111
+ .config(formatterConfig)
112
+ .format(message)
113
+ }
114
+
115
+ /**
116
+ * Get the stream type for level.
117
+ *
118
+ * @param level {string}
119
+ * @return {string}
120
+ */
121
+ getStreamTypeFor(level) {
122
+ if (this.driverConfig.streamType) {
123
+ return this.driverConfig.streamType
124
+ }
125
+
126
+ let streamType = 'stdout'
127
+
128
+ if (level === 'error' || level === 'fatal') {
129
+ streamType = 'stderr'
130
+ }
131
+
132
+ return streamType
133
+ }
134
+ }
@@ -7,55 +7,41 @@
7
7
  * file that was distributed with this source code.
8
8
  */
9
9
 
10
- import { Config, File } from '@secjs/utils'
10
+ import { File } from '@secjs/utils'
11
11
 
12
- import { ColorHelper, FactoryHelper, FormatterFactory } from '#src/index'
13
-
14
- export class FileDriver {
15
- /**
16
- * Holds the configuration set of FileDriver.
17
- *
18
- * @type {{ filePath?: string, formatter?: any, formatterConfig?: any }}
19
- */
20
- configs
12
+ import { Driver } from '#src/Drivers/Driver'
21
13
 
14
+ export class FileDriver extends Driver {
22
15
  /**
23
16
  * Creates a new instance of FileDriver.
24
17
  *
25
- * @param {string} channel
26
- * @param {any} [configs]
18
+ * @param {any} configs
27
19
  * @return {FileDriver}
28
20
  */
29
- constructor(channel, configs = {}) {
30
- const channelConfig = Config.get(`logging.channels.${channel}`)
31
-
32
- this.configs = FactoryHelper.groupConfigs(configs, channelConfig)
21
+ constructor(configs) {
22
+ super(configs)
33
23
  }
34
24
 
35
25
  /**
36
26
  * Transport the log.
37
27
  *
28
+ * @param {string} level
38
29
  * @param {string} message
39
- * @param {{ filePath?: string, formatter?: any, formatterConfig?: any }} [options]
40
- * @return {Promise<void>}
30
+ * @return {Promise<any>}
41
31
  */
42
- async transport(message, options = {}) {
43
- const configs = FactoryHelper.groupConfigs(options, this.configs)
44
-
45
- message = FormatterFactory.fabricate(configs.formatter).format(
46
- message,
47
- configs.formatterConfig,
48
- )
49
-
50
- const messageBuffer = Buffer.from(`${ColorHelper.removeColors(message)}\n`)
32
+ async transport(level, message) {
33
+ if (!this.couldBeTransported(level)) {
34
+ return
35
+ }
51
36
 
52
- const file = new File(configs.filePath, messageBuffer)
53
- const fileExists = await File.exists(configs.filePath)
37
+ const filePath = this.driverConfig.filePath
38
+ const formatted = this.format(level, message, true)
39
+ const buffer = Buffer.from(`${formatted}\n`, 'utf-8')
54
40
 
55
- if (!fileExists) {
56
- return file.load()
41
+ if (await File.exists(filePath)) {
42
+ return new File(filePath).append(buffer)
57
43
  }
58
44
 
59
- return file.append(messageBuffer)
45
+ return new File(filePath, buffer).load()
60
46
  }
61
47
  }
@@ -7,22 +7,27 @@
7
7
  * file that was distributed with this source code.
8
8
  */
9
9
 
10
- export class NullDriver {
10
+ import { Driver } from '#src/Drivers/Driver'
11
+
12
+ export class NullDriver extends Driver {
11
13
  /**
12
14
  * Creates a new instance of NullDriver.
13
15
  *
14
- * @param {string} _channel
15
- * @param {any} [_configs]
16
+ * @param {string} configs
16
17
  * @return {NullDriver}
17
18
  */
18
- constructor(_channel, _configs = {}) {}
19
+ constructor(configs) {
20
+ super(configs)
21
+ }
19
22
 
20
23
  /**
21
24
  * Transport the log.
22
25
  *
23
- * @param {string} _message
24
- * @param {any} [_options]
25
- * @return {void}
26
+ * @param {string} level
27
+ * @param {string} message
28
+ * @return {any}
26
29
  */
27
- transport(_message, _options) {}
30
+ transport(level, message) {
31
+ return null
32
+ }
28
33
  }
@@ -9,46 +9,33 @@
9
9
 
10
10
  import axios from 'axios'
11
11
 
12
- import { Config } from '@secjs/utils'
13
-
14
- import { ColorHelper, FactoryHelper, FormatterFactory } from '#src/index'
15
-
16
- export class SlackDriver {
17
- /**
18
- * Holds the configuration set of SlackDriver.
19
- *
20
- * @type {{ url?: string, formatter?: 'pino-pretty', formatterConfig?: import('pino-pretty').PrettyOptions }}
21
- */
22
- configs
12
+ import { Driver } from '#src/Drivers/Driver'
23
13
 
14
+ export class SlackDriver extends Driver {
24
15
  /**
25
16
  * Creates a new instance of SlackDriver.
26
17
  *
27
- * @param {string} channel
28
- * @param {any} [configs]
18
+ * @param {any} configs
29
19
  * @return {SlackDriver}
30
20
  */
31
- constructor(channel, configs = {}) {
32
- const channelConfig = Config.get(`logging.channels.${channel}`)
33
-
34
- this.configs = FactoryHelper.groupConfigs(configs, channelConfig)
21
+ constructor(configs) {
22
+ super(configs)
35
23
  }
36
24
 
37
25
  /**
38
26
  * Transport the log.
39
27
  *
28
+ * @param {string} level
40
29
  * @param {string} message
41
- * @param {{ url?: string, formatter?: 'pino-pretty', formatterConfig?: import('pino-pretty').PrettyOptions }} [options]
42
- * @return {Promise<void>}
30
+ * @return {Promise<any>}
43
31
  */
44
- async transport(message, options = {}) {
45
- const configs = FactoryHelper.groupConfigs(options, this.configs)
32
+ async transport(level, message) {
33
+ if (!this.couldBeTransported(level)) {
34
+ return
35
+ }
46
36
 
47
- message = FormatterFactory.fabricate(configs.formatter).format(
48
- message,
49
- configs.formatterConfig,
50
- )
37
+ const formatted = this.format(level, message, true)
51
38
 
52
- await axios.post(configs.url, { text: ColorHelper.removeColors(message) })
39
+ return axios.post(this.configs.url, { text: formatted })
53
40
  }
54
41
  }
@@ -8,45 +8,38 @@
8
8
  */
9
9
 
10
10
  import { Telegraf } from 'telegraf'
11
+ import { Driver } from '#src/Drivers/Driver'
11
12
 
12
- import { Config } from '@secjs/utils'
13
-
14
- import { ColorHelper, FactoryHelper, FormatterFactory } from '#src/index'
15
-
16
- export class TelegramDriver {
13
+ export class TelegramDriver extends Driver {
17
14
  /**
18
- * Holds the configuration set of SlackDriver.
15
+ * Creates a new instance of TelegramDriver.
19
16
  *
20
- * @type {{ token?: string, chatId?: string|number, parseMode?: 'HTML'|'Markdown'|'MarkdownV2', formatter?: 'pino-pretty', formatterConfig?: import('pino-pretty').PrettyOptions }}
17
+ * @param {any} configs
18
+ * @return {TelegramDriver}
21
19
  */
22
- configs
23
-
24
- constructor(channel, configs = {}) {
25
- const channelConfig = Config.get(`logging.channels.${channel}`)
26
-
27
- this.configs = FactoryHelper.groupConfigs(configs, channelConfig)
20
+ constructor(configs) {
21
+ super(configs)
28
22
  }
29
23
 
30
24
  /**
31
25
  * Transport the log.
32
26
  *
27
+ * @param {string} level
33
28
  * @param {string} message
34
- * @param {{ token?: string, chatId?: string|number, parseMode?: 'HTML'|'Markdown'|'MarkdownV2', formatter?: 'pino-pretty', formatterConfig?: import('pino-pretty').PrettyOptions }} [options]
35
- * @return {Promise<void>}
29
+ * @return {Promise<any>}
36
30
  */
37
- async transport(message, options = {}) {
38
- const configs = FactoryHelper.groupConfigs(options, this.configs)
31
+ async transport(level, message) {
32
+ if (!this.couldBeTransported(level)) {
33
+ return
34
+ }
39
35
 
40
- message = FormatterFactory.fabricate(configs.formatter).format(
41
- message,
42
- configs.formatterConfig,
43
- )
36
+ const formatted = this.format(level, message, true)
44
37
 
45
- await new Telegraf(configs.token).telegram.sendMessage(
46
- configs.chatId,
47
- ColorHelper.removeColors(message),
38
+ return new Telegraf(this.driverConfig.token).telegram.sendMessage(
39
+ this.driverConfig.chatId,
40
+ formatted,
48
41
  {
49
- parse_mode: configs.parseMode,
42
+ parse_mode: this.driverConfig.parseMode,
50
43
  },
51
44
  )
52
45
  }
@@ -25,7 +25,7 @@ export class NotFoundDriverException extends Exception {
25
25
  content,
26
26
  500,
27
27
  'E_NOT_FOUND',
28
- `Available drivers are: ${availableDrivers}. Look into your config/logger file if ${driverName} driver is implemented by logger. Or create ${driverName} driver implementation using DriverFactory.createDriver("${driverName}", ...) method.`,
28
+ `Available drivers are: ${availableDrivers}. Look into your config/logger.js file if ${driverName} driver is implemented by logger. Or create ${driverName} driver implementation using DriverFactory.createDriver("${driverName}", ...) method.`,
29
29
  )
30
30
  }
31
31
  }
@@ -25,7 +25,7 @@ export class NotFoundFormatterException extends Exception {
25
25
  content,
26
26
  500,
27
27
  'E_NOT_FOUND',
28
- `Available formatters are: ${availableDrivers}. Look into your config/logger file if ${formatterName} formatter is implemented by logger. Or create ${formatterName} formatter implementation using FormatterFactory.createFormatter("${formatterName}", ...) method.`,
28
+ `Available formatters are: ${availableDrivers}. Look into your config/logger.js file if ${formatterName} formatter is implemented by logger. Or create ${formatterName} formatter implementation using FormatterFactory.createFormatter("${formatterName}", ...) method.`,
29
29
  )
30
30
  }
31
31
  }
@@ -0,0 +1,38 @@
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 { Config, Exception } from '@secjs/utils'
11
+
12
+ export class NotImplementedConfigException extends Exception {
13
+ /**
14
+ * Creates a new instance of NotImplementedConfigException.
15
+ *
16
+ * @param {string} channelName
17
+ * @return {NotImplementedConfigException}
18
+ */
19
+ constructor(channelName) {
20
+ const content = `Channel ${channelName} is not configured inside logging.channels object from config/logging file.`
21
+
22
+ let help = ''
23
+
24
+ if (Config.get('logging.channels')) {
25
+ const availableConfigs = Object.keys(Config.get('logging.channels')).join(
26
+ ', ',
27
+ )
28
+
29
+ help += `Available configurations are: ${availableConfigs}.`
30
+ } else {
31
+ help += `The "Config.get('logging.channels') is empty, maybe your configuration files are not loaded?`
32
+ }
33
+
34
+ help += ` Create your configuration inside channels object to use it. Or load your configuration files using "new Config().safeLoad(Path.config('logging.js'))`
35
+
36
+ super(content, 500, 'E_NOT_IMPLEMENTED_CONFIG_ERROR', help)
37
+ }
38
+ }
@@ -12,6 +12,6 @@ import { Facade } from '@athenna/ioc'
12
12
  /**
13
13
  * Log facade.
14
14
  *
15
- * @type {Facade & import('../index').Logger}
15
+ * @type {Facade & import('#src/index').Logger}
16
16
  */
17
17
  export const Log = Facade.createFor('Athenna/Core/Logger')