logixlysia 3.6.2 → 4.0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.0.0](https://github.com/PunGrumpy/logixlysia/compare/v3.7.0...v4.0.0) (2024-10-28)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * **timestamp:** The timestamp format in logs will now respect the new timestamp configuration options when provided
9
+
10
+ ### Features
11
+
12
+ * **timestamp:** add customize timestamp formatting ([5a4e2a5](https://github.com/PunGrumpy/logixlysia/commit/5a4e2a5230443761d8c2ca99d9ebc586ff26a8c0)), closes [#69](https://github.com/PunGrumpy/logixlysia/issues/69)
13
+
14
+ ## [3.7.0](https://github.com/PunGrumpy/logixlysia/compare/v3.6.2...v3.7.0) (2024-09-26)
15
+
16
+
17
+ ### Features
18
+
19
+ * **optional:** add startup message config ([#66](https://github.com/PunGrumpy/logixlysia/pull/66)) ([c7a76db](https://github.com/PunGrumpy/logixlysia/commit/c7a76dbc0f30f4c9c607b52dedc49979e26b67ec)) by [@n0ky4](https://github.com/n0ky4)
20
+
3
21
  ## [3.6.2](https://github.com/PunGrumpy/logixlysia/compare/v3.6.1...v3.6.2) (2024-09-18)
4
22
 
5
23
 
package/README.md CHANGED
@@ -21,7 +21,11 @@ const app = new Elysia({
21
21
  }).use(
22
22
  logixlysia({
23
23
  config: {
24
- showBanner: true,
24
+ showStartupMessage: true,
25
+ startupMessageFormat: 'simple',
26
+ timestamp: {
27
+ translateTime: 'yyyy-mm-dd HH:MM:ss'
28
+ },
25
29
  ip: true,
26
30
  logFilePath: './logs/example.log',
27
31
  customLogFormat:
@@ -45,13 +49,15 @@ app.listen(3000)
45
49
 
46
50
  ### Options
47
51
 
48
- | Option | Type | Description | Default |
49
- | ------------------ | --------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------- |
50
- | `showBanner` | `boolean` | Display the banner on the console | `true` |
51
- | `ip` | `boolean` | Display the incoming IP address based on the `X-Forwarded-For` header | `false` |
52
- | `customLogMessage` | `string` | Custom log message to display | `🦊 {now} {level} {duration} {method} {pathname} {status} {message} {ip}` |
53
- | `logFilter` | `object` | Filter the logs based on the level, method, and status | `null` |
54
- | `logFilePath` | `string` | Path to the log file | `./logs/elysia.log` |
52
+ | Option | Type | Description | Default |
53
+ | ---------------------- | ------------------------ | --------------------------------------------------------------------- | ------------------------------------------------------------------------- |
54
+ | `showStartupMessage` | `boolean` | Display the startup message | `true` |
55
+ | `startupMessageFormat` | `"banner"` \| `"simple"` | Choose the startup message format | `"banner"` |
56
+ | `timestamp` | `object` | Display the timestamp in the logs | `{ translateTime: 'yyyy-mm-dd HH:MM:ss' }` |
57
+ | `ip` | `boolean` | Display the incoming IP address based on the `X-Forwarded-For` header | `false` |
58
+ | `customLogMessage` | `string` | Custom log message to display | `🦊 {now} {level} {duration} {method} {pathname} {status} {message} {ip}` |
59
+ | `logFilter` | `object` | Filter the logs based on the level, method, and status | `null` |
60
+ | `logFilePath` | `string` | Path to the log file | `./logs/elysia.log` |
55
61
 
56
62
  ### Custom Log Message
57
63
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "logixlysia",
3
- "version": "3.6.2",
3
+ "version": "4.0.0",
4
4
  "description": "🦊 Logixlysia is a logger for Elysia",
5
5
  "type": "module",
6
6
  "module": "src/index.ts",
@@ -10,6 +10,12 @@
10
10
  "maintainers": [
11
11
  "PunGrumpy"
12
12
  ],
13
+ "contributors": [
14
+ {
15
+ "name": "n0ky4",
16
+ "url": "https://github.com/n0ky4"
17
+ }
18
+ ],
13
19
  "publishConfig": {
14
20
  "access": "public"
15
21
  },
@@ -71,24 +77,21 @@
71
77
  ],
72
78
  "dependencies": {
73
79
  "chalk": "^5.3.0",
74
- "elysia": "^1.1.4"
80
+ "elysia": "^1.1.19"
75
81
  },
76
82
  "devDependencies": {
77
- "@elysiajs/eden": "^1.1.1",
78
- "@eslint/js": "^9.8.0",
79
- "@trunkio/launcher": "^1.3.1",
80
- "@typescript-eslint/eslint-plugin": "^8.0.1",
81
- "@typescript-eslint/parser": "^8.0.1",
82
- "bun-types": "^1.1.20",
83
- "commitizen": "^4.3.0",
84
- "cz-conventional-changelog": "^3.3.0",
85
- "eslint": "9.x",
83
+ "@elysiajs/eden": "^1.1.3",
84
+ "@eslint/js": "^9.12.0",
85
+ "@trunkio/launcher": "^1.3.2",
86
+ "@typescript-eslint/eslint-plugin": "^8.8.1",
87
+ "@typescript-eslint/parser": "^8.8.1",
88
+ "bun-types": "^1.1.30",
86
89
  "eslint-plugin-simple-import-sort": "^12.1.1",
87
- "globals": "^15.9.0",
88
- "husky": "^9.1.1",
89
- "lint-staged": "^15.2.7",
90
+ "globals": "^15.11.0",
91
+ "husky": "^9.1.6",
92
+ "lint-staged": "^15.2.10",
90
93
  "prettier": "^3.3.3",
91
- "typescript-eslint": "^8.0.1"
94
+ "typescript-eslint": "^8.8.1"
92
95
  },
93
96
  "peerDependencies": {
94
97
  "typescript": "^5.2.2"
@@ -10,6 +10,7 @@ import {
10
10
  } from '../types'
11
11
  import {
12
12
  durationString,
13
+ formatTimestamp,
13
14
  logString,
14
15
  methodString,
15
16
  pathString,
@@ -38,14 +39,16 @@ export function buildLogMessage(
38
39
  const now = new Date()
39
40
  const components: LogComponents = {
40
41
  now: actuallyUseColors
41
- ? chalk.bgYellow(chalk.black(now.toLocaleString()))
42
- : now.toLocaleString(),
42
+ ? chalk.bgYellow(
43
+ chalk.black(formatTimestamp(now, options?.config?.timestamp))
44
+ )
45
+ : formatTimestamp(now, options?.config?.timestamp),
43
46
  epoch: Math.floor(now.getTime() / 1000).toString(),
44
- level: logString(level, actuallyUseColors),
45
- duration: durationString(store.beforeTime, actuallyUseColors),
46
- method: methodString(request.method, actuallyUseColors),
47
+ level: logString(level, useColors),
48
+ duration: durationString(store.beforeTime, useColors),
49
+ method: methodString(request.method, useColors),
47
50
  pathname: pathString(request),
48
- status: statusString(data.status || 200, actuallyUseColors),
51
+ status: statusString(data.status || 200, useColors),
49
52
  message: data.message || '',
50
53
  ip:
51
54
  options?.config?.ip && request.headers.get('x-forwarded-for')
package/src/index.ts CHANGED
@@ -10,7 +10,10 @@ export default function logixlysia(options?: Options): Elysia {
10
10
  return new Elysia({
11
11
  name: 'Logixlysia'
12
12
  })
13
- .onStart(ctx => startServer(ctx.server as Server, options))
13
+ .onStart(ctx => {
14
+ const showStartupMessage = options?.config?.showStartupMessage ?? true
15
+ if (showStartupMessage) startServer(ctx.server as Server, options)}
16
+ )
14
17
  .onRequest(ctx => {
15
18
  ctx.store = { beforeTime: process.hrtime.bigint() }
16
19
  })
@@ -26,6 +29,6 @@ export default function logixlysia(options?: Options): Elysia {
26
29
  })
27
30
  }
28
31
 
29
- export { createLogger } from './core'
30
- export { handleHttpError } from './core'
32
+ export { createLogger, handleHttpError } from './core'
31
33
  export { logToTransports } from './transports'
34
+
@@ -8,7 +8,7 @@ const createBoxText = (text: string, width: number): string => {
8
8
 
9
9
  export default function startServer(config: Server, options?: Options): void {
10
10
  const { hostname, port, protocol } = config
11
- const showBanner = options?.config?.showBanner ?? true
11
+ const showBanner = options?.config?.startupMessageFormat !== 'simple'
12
12
 
13
13
  if (showBanner) {
14
14
  const ELYSIA_VERSION = import.meta.require('elysia/package.json').version
@@ -77,6 +77,10 @@ export interface Transport {
77
77
  log: TransportFunction
78
78
  }
79
79
 
80
+ export interface TimestampConfig {
81
+ translateTime?: boolean | string
82
+ }
83
+
80
84
  export interface Options {
81
85
  config?: {
82
86
  customLogFormat?: string
@@ -88,7 +92,9 @@ export interface Options {
88
92
  } | null
89
93
  ip?: boolean
90
94
  useColors?: boolean
91
- showBanner?: boolean
95
+ showStartupMessage?: boolean
96
+ startupMessageFormat?: 'banner' | 'simple'
92
97
  transports?: Transport[]
98
+ timestamp?: TimestampConfig // Add this new option
93
99
  }
94
100
  }
@@ -4,3 +4,4 @@ export { default as logString } from './log'
4
4
  export { default as methodString } from './method'
5
5
  export { default as pathString } from './path'
6
6
  export { default as statusString } from './status'
7
+ export { formatTimestamp } from './timestamp'
@@ -0,0 +1,48 @@
1
+ import { TimestampConfig } from '../types'
2
+
3
+ // const DEFAULT_TIMESTAMP_FORMAT = 'yyyy-mm-dd HH:MM:ss'
4
+ const SYS_TIME = 'SYS:STANDARD'
5
+
6
+ const pad = (n: number): string => n.toString().padStart(2, '0')
7
+
8
+ function formatSystemTime(date: Date): string {
9
+ const year = date.getFullYear()
10
+ const month = pad(date.getMonth() + 1)
11
+ const day = pad(date.getDate())
12
+ const hours = pad(date.getHours())
13
+ const minutes = pad(date.getMinutes())
14
+ const seconds = pad(date.getSeconds())
15
+ const ms = date.getMilliseconds().toString().padStart(3, '0')
16
+
17
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${ms}`
18
+ }
19
+
20
+ function formatCustomTime(date: Date, format: string): string {
21
+ const tokens: { [key: string]: string | number } = {
22
+ yyyy: date.getFullYear(),
23
+ yy: date.getFullYear().toString().slice(-2),
24
+ mm: pad(date.getMonth() + 1),
25
+ dd: pad(date.getDate()),
26
+ HH: pad(date.getHours()),
27
+ MM: pad(date.getMinutes()),
28
+ ss: pad(date.getSeconds()),
29
+ SSS: pad(date.getMilliseconds()),
30
+ Z: -date.getTimezoneOffset() / 60
31
+ }
32
+
33
+ return format.replace(/yyyy|yy|mm|dd|HH|MM|ss|SSS|Z/g, match =>
34
+ (tokens[match] ?? '').toString()
35
+ )
36
+ }
37
+
38
+ export function formatTimestamp(date: Date, config?: TimestampConfig): string {
39
+ if (!config || !config.translateTime) {
40
+ return date.toISOString()
41
+ }
42
+
43
+ if (config.translateTime === true || config.translateTime === SYS_TIME) {
44
+ return formatSystemTime(date)
45
+ }
46
+
47
+ return formatCustomTime(date, config.translateTime)
48
+ }
@@ -0,0 +1,35 @@
1
+ import { expect, test } from 'bun:test'
2
+
3
+ import { formatTimestamp } from '../../src/utils/timestamp'
4
+
5
+ test('formatTimestamp with different configurations', () => {
6
+ const testDate = new Date('2024-01-15T14:30:45.123Z')
7
+
8
+ // Test default format
9
+ expect(formatTimestamp(testDate)).toBe(testDate.toISOString())
10
+
11
+ // Test system time format
12
+ expect(formatTimestamp(testDate, { translateTime: true })).toMatch(
13
+ /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}$/
14
+ )
15
+
16
+ // Test custom format
17
+ expect(
18
+ formatTimestamp(testDate, {
19
+ translateTime: 'yyyy-mm-dd HH:MM:ss.SSS'
20
+ })
21
+ ).toMatch(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}$/)
22
+
23
+ // Test different custom formats
24
+ expect(
25
+ formatTimestamp(testDate, {
26
+ translateTime: 'HH:MM:ss'
27
+ })
28
+ ).toMatch(/^\d{2}:\d{2}:\d{2}$/)
29
+
30
+ expect(
31
+ formatTimestamp(testDate, {
32
+ translateTime: 'yyyy/mm/dd'
33
+ })
34
+ ).toMatch(/^\d{4}\/\d{2}\/\d{2}$/)
35
+ })