logixlysia 2.3.1 → 3.0.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.0.1](https://github.com/PunGrumpy/logixlysia/compare/v3.0.0...v3.0.1) (2024-04-08)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **logger:** use correct status code in error log message ([a3ec49c](https://github.com/PunGrumpy/logixlysia/commit/a3ec49cd3fc1dc7f01a29b21e4de9cf543329c43)), closes [#33](https://github.com/PunGrumpy/logixlysia/issues/33)
9
+
10
+ ## [3.0.0](https://github.com/PunGrumpy/logixlysia/compare/v2.3.1...v3.0.0) (2024-04-08)
11
+
12
+
13
+ ### ⚠ BREAKING CHANGES
14
+
15
+ * Added support for custom log format in the logger
16
+ * Enhanced flexibility for define thier preferred log message structure
17
+
18
+ ### Features
19
+
20
+ * **options:** add support for custom log format ([acc9380](https://github.com/PunGrumpy/logixlysia/commit/acc9380ea25691e7d7fec175094cb6a9878b6c69))
21
+
3
22
  ## [2.3.1](https://github.com/PunGrumpy/logixlysia/compare/v2.3.0...v2.3.1) (2024-04-07)
4
23
 
5
24
 
package/README.md CHANGED
@@ -18,7 +18,13 @@ import { logger } from 'logixlysia'
18
18
 
19
19
  const app = new Elysia({
20
20
  name: 'Logixlysia Example'
21
- }).use(logger())
21
+ }).use(
22
+ logger({
23
+ ip: false,
24
+ customLogMessage:
25
+ '🦊 {now} {level} {duration} {method} {pathname} {status} {message} {ip}'
26
+ })
27
+ )
22
28
 
23
29
  app.listen(3000)
24
30
  ```
@@ -27,9 +33,10 @@ app.listen(3000)
27
33
 
28
34
  ### Options
29
35
 
30
- | Option | Type | Description | Default |
31
- | ------ | --------- | --------------------------------------------------------------------- | ------- |
32
- | `ip` | `boolean` | Display the incoming IP address based on the `X-Forwarded-For` header | `false` |
36
+ | Option | Type | Description | Default |
37
+ | ------------------ | --------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------- |
38
+ | `ip` | `boolean` | Display the incoming IP address based on the `X-Forwarded-For` header | `false` |
39
+ | `customLogMessage` | `string` | Custom log message to display | `🦊 {now} {level} {duration} {method} {pathname} {status} {message} {ip}` |
33
40
 
34
41
  ## `📄` License
35
42
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "logixlysia",
3
- "version": "2.3.1",
3
+ "version": "3.0.1",
4
4
  "description": "🦊 Logixlysia is a logger for Elysia",
5
5
  "type": "module",
6
6
  "module": "src/index.ts",
package/src/index.ts CHANGED
@@ -2,7 +2,7 @@ import Elysia from 'elysia'
2
2
  import { createLogger, handleHttpError } from './logger'
3
3
  import startString from './utils/start'
4
4
  import { Server } from 'bun'
5
- import { Options } from './types'
5
+ import { HttpError, Options } from './types'
6
6
 
7
7
  /**
8
8
  * Creates a logger.
@@ -35,7 +35,12 @@ export const logger = (options?: Options): Elysia => {
35
35
  log.log('INFO', request, { status: 200 }, store as { beforeTime: bigint })
36
36
  })
37
37
  .onError({ as: 'global' }, ({ request, error, store }) => {
38
- handleHttpError(request, error, store as { beforeTime: bigint })
38
+ handleHttpError(
39
+ request,
40
+ error as HttpError,
41
+ store as { beforeTime: bigint },
42
+ options
43
+ )
39
44
  })
40
45
 
41
46
  return elysia
package/src/logger.ts CHANGED
@@ -7,17 +7,36 @@ import statusString from './utils/status'
7
7
  import { HttpError, RequestInfo } from './types'
8
8
  import { LogLevel, LogData, Logger, StoreData, Options } from './types'
9
9
 
10
- async function log(
10
+ /**
11
+ * Logs a message.
12
+ *
13
+ * @param {LogLevel} level The log level.
14
+ * @param {RequestInfo} request The request.
15
+ * @param {LogData} data The log data.
16
+ * @param {StoreData} store The store data.
17
+ * @param {Options} options The options.
18
+ */
19
+ function log(
11
20
  level: LogLevel,
12
21
  request: RequestInfo,
13
22
  data: LogData,
14
23
  store: StoreData,
15
24
  options?: Options
16
- ): Promise<void> {
25
+ ): void {
17
26
  const logMessage = buildLogMessage(level, request, data, store, options)
18
27
  console.log(logMessage)
19
28
  }
20
29
 
30
+ /**
31
+ * Builds a log message.
32
+ *
33
+ * @param {LogLevel} level The log level.
34
+ * @param {RequestInfo} request The request.
35
+ * @param {LogData} data The log data.
36
+ * @param {StoreData} store The store data.
37
+ * @param {Options} options The options.
38
+ * @returns {string} The log message.
39
+ */
21
40
  function buildLogMessage(
22
41
  level: LogLevel,
23
42
  request: RequestInfo,
@@ -32,31 +51,54 @@ function buildLogMessage(
32
51
  const pathnameStr = pathString(request)
33
52
  const statusStr = statusString(data.status || 200)
34
53
  const messageStr = data.message || ''
54
+ const ipStr =
55
+ options?.ip && request.headers.get('x-forwarded-for')
56
+ ? `IP: ${request.headers.get('x-forwarded-for')}`
57
+ : ''
35
58
 
36
- let logMessage = `🦊 ${nowStr} ${levelStr} ${durationStr} ${methodStr} ${pathnameStr} ${statusStr} ${messageStr}`
37
-
38
- if (options?.ip) {
39
- const forwardedFor = request.headers.get('x-forwarded-for')
40
- if (forwardedFor) {
41
- logMessage += ` IP: ${forwardedFor}`
42
- }
43
- }
59
+ const logFormat =
60
+ options?.customLogFormat ||
61
+ '🦊 {now} {level} {duration} {method} {pathname} {status} {message} {ip}'
62
+ const logMessage = logFormat
63
+ .replace('{now}', nowStr)
64
+ .replace('{level}', levelStr)
65
+ .replace('{duration}', durationStr)
66
+ .replace('{method}', methodStr)
67
+ .replace('{pathname}', pathnameStr || '')
68
+ .replace('{status}', statusStr)
69
+ .replace('{message}', messageStr)
70
+ .replace('{ip}', ipStr || '')
44
71
 
45
72
  return logMessage
46
73
  }
47
74
 
75
+ /**
76
+ * Creates a logger.
77
+ *
78
+ * @param {Options} options The options.
79
+ * @returns {Logger} The logger.
80
+ */
48
81
  export const createLogger = (options?: Options): Logger => ({
49
82
  log: (level, request, data, store) =>
50
- log(level, request, data, store, options)
83
+ log(level, request, data, store, options),
84
+ customLogFormat: options?.customLogFormat
51
85
  })
52
86
 
87
+ /**
88
+ * Handles an HTTP error.
89
+ *
90
+ * @param {RequestInfo} request The request.
91
+ * @param {HttpError} error The HTTP error.
92
+ * @param {StoreData} store The store data.
93
+ * @param {Options} options The options.
94
+ */
53
95
  export const handleHttpError = (
54
96
  request: RequestInfo,
55
- error: Error,
97
+ error: HttpError,
56
98
  store: StoreData,
57
99
  options?: Options
58
100
  ): void => {
59
- const statusCode = error instanceof HttpError ? error.status : 500
101
+ const statusCode = error.status || 500
60
102
  const logMessage = buildLogMessage(
61
103
  'ERROR',
62
104
  request,
package/src/types.ts CHANGED
@@ -28,6 +28,7 @@ interface Logger {
28
28
  data: LogData,
29
29
  store: StoreData
30
30
  ): void
31
+ customLogFormat?: string
31
32
  }
32
33
 
33
34
  interface StoreData {
@@ -45,6 +46,7 @@ class HttpError extends Error {
45
46
 
46
47
  interface Options {
47
48
  ip?: boolean
49
+ customLogFormat?: string
48
50
  }
49
51
 
50
52
  export {
@@ -10,7 +10,13 @@ describe('Logixlysia with IP logging enabled', () => {
10
10
 
11
11
  beforeAll(() => {
12
12
  server = new Elysia()
13
- .use(logger({ ip: true }))
13
+ .use(
14
+ logger({
15
+ ip: true,
16
+ customLogFormat:
17
+ '🦊 {now} {duration} {level} {method} {pathname} {status} {message} {ip}'
18
+ })
19
+ )
14
20
  .get('/', ctx => {
15
21
  const ipAddress = ctx.request.headers.get('x-forwarded-for') || 'null'
16
22
  return '🦊 Logixlysia Getting'
@@ -35,7 +41,9 @@ describe('Logixlysia with IP logging enabled', () => {
35
41
  }
36
42
 
37
43
  logs.forEach(log => {
38
- expect(log).toMatch(/^IP: \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)
44
+ expect(log).toMatch(
45
+ /^🦊 .+ INFO .+ .+ GET \/ .+ IP: \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
46
+ )
39
47
  })
40
48
  })
41
49
 
@@ -47,7 +55,7 @@ describe('Logixlysia with IP logging enabled', () => {
47
55
  }
48
56
 
49
57
  logs.forEach(log => {
50
- expect(log).toBe('IP: null')
58
+ expect(log).toMatch(/^🦊 .+ INFO .+ .+ GET \/ .+ IP: null$/)
51
59
  })
52
60
  })
53
61
  })
@@ -59,7 +67,13 @@ describe('Logixlysia with IP logging disabled', () => {
59
67
 
60
68
  beforeAll(() => {
61
69
  server = new Elysia()
62
- .use(logger({ ip: false }))
70
+ .use(
71
+ logger({
72
+ ip: false,
73
+ customLogFormat:
74
+ '🦊 {now} {duration} {level} {method} {pathname} {status} {message} {ip}'
75
+ })
76
+ )
63
77
  .get('/', () => '🦊 Logixlysia Getting')
64
78
  .post('logixlysia', () => '🦊 Logixlysia Posting')
65
79
  .listen(3000)