logixlysia 3.5.0 โ 3.6.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 +15 -0
- package/README.md +18 -1
- package/package.json +16 -15
- package/src/index.ts +6 -3
- package/src/logger/buildLogMessage.ts +35 -26
- package/src/logger/createLogger.ts +22 -12
- package/src/logger/filter.ts +5 -5
- package/src/logger/handleHttpError.ts +5 -11
- package/src/logger/index.ts +2 -2
- package/src/logger/logToFile.ts +7 -3
- package/src/transports/index.ts +22 -0
- package/src/types.ts +34 -2
- package/src/utils/duration.ts +12 -24
- package/src/utils/log.ts +2 -3
- package/src/utils/method.ts +1 -1
- package/src/utils/path.ts +1 -1
- package/src/utils/start.ts +5 -4
- package/src/utils/status.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.6.1](https://github.com/PunGrumpy/logixlysia/compare/v3.6.0...v3.6.1) (2024-08-21)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Performance Improvements
|
|
7
|
+
|
|
8
|
+
* **logger:** improve performance and fix TypeScript errors ([d3ed751](https://github.com/PunGrumpy/logixlysia/commit/d3ed751041443b9bd2ce53350994e1443df40971))
|
|
9
|
+
|
|
10
|
+
## [3.6.0](https://github.com/PunGrumpy/logixlysia/compare/v3.5.0...v3.6.0) (2024-07-24)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* **custom-log:** add unix epoch timestamp option on `customLogFormat` configuration ([58d3e5b](https://github.com/PunGrumpy/logixlysia/commit/58d3e5b89bfef86aed1f5daa70d9a39982750073)), closes [#56](https://github.com/PunGrumpy/logixlysia/issues/56)
|
|
16
|
+
* **transports:** add custom tranporter support for flexible logging ([69e1b89](https://github.com/PunGrumpy/logixlysia/commit/69e1b8991d323d8463fb81cf5bf1b441f678318b)), closes [#51](https://github.com/PunGrumpy/logixlysia/issues/51)
|
|
17
|
+
|
|
3
18
|
## [3.5.0](https://github.com/PunGrumpy/logixlysia/compare/v3.4.0...v3.5.0) (2024-07-11)
|
|
4
19
|
|
|
5
20
|
|
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ const app = new Elysia({
|
|
|
25
25
|
ip: true,
|
|
26
26
|
logFilePath: './logs/example.log',
|
|
27
27
|
customLogFormat:
|
|
28
|
-
'๐ฆ {now} {level} {duration} {method} {pathname} {status} {message} {ip}',
|
|
28
|
+
'๐ฆ {now} {level} {duration} {method} {pathname} {status} {message} {ip} {epoch}',
|
|
29
29
|
logFilter: {
|
|
30
30
|
level: ['ERROR', 'WARNING'],
|
|
31
31
|
status: [500, 404],
|
|
@@ -38,6 +38,9 @@ const app = new Elysia({
|
|
|
38
38
|
app.listen(3000)
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
> [!NOTE]
|
|
42
|
+
> You can discover more about example in the [example](example) directory.
|
|
43
|
+
|
|
41
44
|
## `๐` Documentation
|
|
42
45
|
|
|
43
46
|
### Options
|
|
@@ -50,6 +53,20 @@ app.listen(3000)
|
|
|
50
53
|
| `logFilter` | `object` | Filter the logs based on the level, method, and status | `null` |
|
|
51
54
|
| `logFilePath` | `string` | Path to the log file | `./logs/elysia.log` |
|
|
52
55
|
|
|
56
|
+
### Custom Log Message
|
|
57
|
+
|
|
58
|
+
| Placeholder | Description |
|
|
59
|
+
| ------------ | --------------------------------------------------------------------------- |
|
|
60
|
+
| `{now}` | Current date and time in `YYYY-MM-DD HH:mm:ss` format |
|
|
61
|
+
| `{level}` | Log level (`INFO`, `WARNING`, `ERROR`) |
|
|
62
|
+
| `{duration}` | Request duration in milliseconds |
|
|
63
|
+
| `{method}` | Request method (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`, `OPTIONS`) |
|
|
64
|
+
| `{pathname}` | Request pathname |
|
|
65
|
+
| `{status}` | Response status code |
|
|
66
|
+
| `{message}` | Custom message |
|
|
67
|
+
| `{ip}` | Incoming IP address |
|
|
68
|
+
| `{epoch}` | Current date and time in Unix epoch format (seconds since January 1, 1970 |
|
|
69
|
+
|
|
53
70
|
## `๐` License
|
|
54
71
|
|
|
55
72
|
Licensed under the [MIT License](LICENSE).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "logixlysia",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.6.1",
|
|
4
4
|
"description": "๐ฆ Logixlysia is a logger for Elysia",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "src/index.ts",
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
},
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"scripts": {
|
|
18
|
-
"lint": "eslint
|
|
19
|
-
"lint:fix": "eslint
|
|
18
|
+
"lint": "eslint .",
|
|
19
|
+
"lint:fix": "eslint . --fix",
|
|
20
20
|
"test": "bun test --timeout 5000 --coverage",
|
|
21
|
-
"test:ci": "bun test --timeout 5000 --coverage",
|
|
21
|
+
"test:ci": "bun test --timeout 5000 --coverage --coverage-reporter=lcov",
|
|
22
22
|
"publish": "npm publish",
|
|
23
23
|
"dev": "bun run --watch example/basic.ts",
|
|
24
24
|
"prepare": "husky",
|
|
@@ -71,25 +71,26 @@
|
|
|
71
71
|
],
|
|
72
72
|
"dependencies": {
|
|
73
73
|
"chalk": "^5.3.0",
|
|
74
|
-
"elysia": "^1.
|
|
74
|
+
"elysia": "^1.1.4"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
|
-
"@elysiajs/eden": "^1.
|
|
78
|
-
"@eslint/js": "^9.
|
|
77
|
+
"@elysiajs/eden": "^1.1.1",
|
|
78
|
+
"@eslint/js": "^9.8.0",
|
|
79
79
|
"@trunkio/launcher": "^1.3.1",
|
|
80
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
81
|
-
"@typescript-eslint/parser": "^
|
|
82
|
-
"bun-types": "^1.1.
|
|
80
|
+
"@typescript-eslint/eslint-plugin": "^8.0.1",
|
|
81
|
+
"@typescript-eslint/parser": "^8.0.1",
|
|
82
|
+
"bun-types": "^1.1.20",
|
|
83
83
|
"commitizen": "^4.3.0",
|
|
84
84
|
"cz-conventional-changelog": "^3.3.0",
|
|
85
85
|
"eslint": "9.x",
|
|
86
|
-
"eslint-plugin-simple-import-sort": "^12.1.
|
|
87
|
-
"
|
|
86
|
+
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
87
|
+
"globals": "^15.9.0",
|
|
88
|
+
"husky": "^9.1.1",
|
|
88
89
|
"lint-staged": "^15.2.7",
|
|
89
|
-
"prettier": "^3.3.
|
|
90
|
-
"typescript-eslint": "^
|
|
90
|
+
"prettier": "^3.3.3",
|
|
91
|
+
"typescript-eslint": "^8.0.1"
|
|
91
92
|
},
|
|
92
93
|
"peerDependencies": {
|
|
93
|
-
"typescript": "^5.
|
|
94
|
+
"typescript": "^5.2.2"
|
|
94
95
|
}
|
|
95
96
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Server } from 'bun'
|
|
2
2
|
import Elysia from 'elysia'
|
|
3
3
|
|
|
4
|
-
import { createLogger, handleHttpError } from '
|
|
5
|
-
import { HttpError, Options } from '
|
|
6
|
-
import startServer from '
|
|
4
|
+
import { createLogger, handleHttpError } from '~/logger'
|
|
5
|
+
import { HttpError, Options } from '~/types'
|
|
6
|
+
import startServer from '~/utils/start'
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Creates a logger plugin for ElysiaJS.
|
|
@@ -41,3 +41,6 @@ export default function logixlysia(options?: Options): Elysia {
|
|
|
41
41
|
)
|
|
42
42
|
})
|
|
43
43
|
}
|
|
44
|
+
|
|
45
|
+
export { createLogger } from '~/logger'
|
|
46
|
+
export { handleHttpError } from '~/logger'
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import chalk from 'chalk'
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
LogComponents,
|
|
5
|
+
LogData,
|
|
6
|
+
LogLevel,
|
|
7
|
+
Options,
|
|
8
|
+
RequestInfo,
|
|
9
|
+
StoreData
|
|
10
|
+
} from '~/types'
|
|
4
11
|
import durationString from '~/utils/duration'
|
|
5
12
|
import logString from '~/utils/log'
|
|
6
13
|
import methodString from '~/utils/method'
|
|
7
14
|
import pathString from '~/utils/path'
|
|
8
15
|
import statusString from '~/utils/status'
|
|
9
16
|
|
|
17
|
+
const defaultLogFormat =
|
|
18
|
+
'๐ฆ {now} {level} {duration} {method} {pathname} {status} {message} {ip}'
|
|
19
|
+
|
|
10
20
|
/**
|
|
11
21
|
* Builds a log message.
|
|
12
22
|
*
|
|
@@ -26,31 +36,30 @@ export function buildLogMessage(
|
|
|
26
36
|
options?: Options,
|
|
27
37
|
useColors: boolean = true
|
|
28
38
|
): string {
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
const now = new Date()
|
|
40
|
+
const components: LogComponents = {
|
|
41
|
+
now: useColors
|
|
42
|
+
? chalk.bgYellow(chalk.black(now.toLocaleString()))
|
|
43
|
+
: now.toLocaleString(),
|
|
44
|
+
epoch: Math.floor(now.getTime() / 1000).toString(),
|
|
45
|
+
level: logString(level, useColors),
|
|
46
|
+
duration: durationString(store.beforeTime, useColors),
|
|
47
|
+
method: methodString(request.method, useColors),
|
|
48
|
+
pathname: pathString(request),
|
|
49
|
+
status: statusString(data.status || 200, useColors),
|
|
50
|
+
message: data.message || '',
|
|
51
|
+
ip:
|
|
52
|
+
options?.config?.ip && request.headers.get('x-forwarded-for')
|
|
53
|
+
? `IP: ${request.headers.get('x-forwarded-for')}`
|
|
54
|
+
: ''
|
|
55
|
+
}
|
|
42
56
|
|
|
43
|
-
const logFormat =
|
|
44
|
-
options?.config?.customLogFormat ||
|
|
45
|
-
'๐ฆ {now} {level} {duration} {method} {pathname} {status} {message} {ip}'
|
|
57
|
+
const logFormat = options?.config?.customLogFormat || defaultLogFormat
|
|
46
58
|
|
|
47
|
-
return logFormat
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
.replace('{status}', statusStr)
|
|
54
|
-
.replace('{message}', messageStr)
|
|
55
|
-
.replace('{ip}', ipStr || '')
|
|
59
|
+
return logFormat.replace(/{(\w+)}/g, (_, key: string) => {
|
|
60
|
+
if (key in components) {
|
|
61
|
+
return components[key as keyof LogComponents] || ''
|
|
62
|
+
}
|
|
63
|
+
return ''
|
|
64
|
+
})
|
|
56
65
|
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { buildLogMessage } from '~/logger/buildLogMessage'
|
|
2
|
+
import { filterLog } from '~/logger/filter'
|
|
3
|
+
import { logToFile } from '~/logger/logToFile'
|
|
4
|
+
import { logToTransports } from '~/transports'
|
|
1
5
|
import {
|
|
2
6
|
LogData,
|
|
3
7
|
Logger,
|
|
@@ -7,10 +11,6 @@ import {
|
|
|
7
11
|
StoreData
|
|
8
12
|
} from '~/types'
|
|
9
13
|
|
|
10
|
-
import { buildLogMessage } from './buildLogMessage'
|
|
11
|
-
import { filterLog } from './filter'
|
|
12
|
-
import { logToFile } from './logToFile'
|
|
13
|
-
|
|
14
14
|
/**
|
|
15
15
|
* Logs a message to the console and optionally to a file.
|
|
16
16
|
*
|
|
@@ -32,16 +32,26 @@ async function log(
|
|
|
32
32
|
const logMessage = buildLogMessage(level, request, data, store, options, true)
|
|
33
33
|
console.log(logMessage)
|
|
34
34
|
|
|
35
|
+
const promises = []
|
|
36
|
+
|
|
35
37
|
if (options?.config?.logFilePath) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
promises.push(
|
|
39
|
+
logToFile(
|
|
40
|
+
options.config.logFilePath,
|
|
41
|
+
level,
|
|
42
|
+
request,
|
|
43
|
+
data,
|
|
44
|
+
store,
|
|
45
|
+
options
|
|
46
|
+
)
|
|
43
47
|
)
|
|
44
48
|
}
|
|
49
|
+
|
|
50
|
+
if (options?.config?.transports?.length) {
|
|
51
|
+
promises.push(logToTransports(level, request, data, store, options))
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
await Promise.all(promises)
|
|
45
55
|
}
|
|
46
56
|
|
|
47
57
|
/**
|
|
@@ -52,7 +62,7 @@ async function log(
|
|
|
52
62
|
*/
|
|
53
63
|
export function createLogger(options?: Options): Logger {
|
|
54
64
|
return {
|
|
55
|
-
log:
|
|
65
|
+
log: (level, request, data, store) =>
|
|
56
66
|
log(level, request, data, store, options),
|
|
57
67
|
customLogFormat: options?.config?.customLogFormat
|
|
58
68
|
}
|
package/src/logger/filter.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { LogLevel, Options } from '~/types'
|
|
2
2
|
|
|
3
|
+
const checkFilter = (filterValue: any, value: any) =>
|
|
4
|
+
Array.isArray(filterValue)
|
|
5
|
+
? filterValue.includes(value)
|
|
6
|
+
: filterValue === value
|
|
7
|
+
|
|
3
8
|
/**
|
|
4
9
|
* Filters log messages.
|
|
5
10
|
*
|
|
@@ -18,11 +23,6 @@ export function filterLog(
|
|
|
18
23
|
const filter = options?.config?.logFilter
|
|
19
24
|
if (!filter) return true
|
|
20
25
|
|
|
21
|
-
const checkFilter = (filterValue: any, value: any) =>
|
|
22
|
-
Array.isArray(filterValue)
|
|
23
|
-
? filterValue.includes(value)
|
|
24
|
-
: filterValue === value
|
|
25
|
-
|
|
26
26
|
return (
|
|
27
27
|
(!filter.level || checkFilter(filter.level, logLevel)) &&
|
|
28
28
|
(!filter.status || checkFilter(filter.status, status)) &&
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
+
import { buildLogMessage } from '~/logger/buildLogMessage'
|
|
1
2
|
import { HttpError, Options, RequestInfo, StoreData } from '~/types'
|
|
2
3
|
|
|
3
|
-
import { buildLogMessage } from './buildLogMessage'
|
|
4
|
-
|
|
5
4
|
/**
|
|
6
5
|
* Handles an HTTP error and logs it.
|
|
7
6
|
*
|
|
@@ -10,19 +9,14 @@ import { buildLogMessage } from './buildLogMessage'
|
|
|
10
9
|
* @param {StoreData} store The store data.
|
|
11
10
|
* @param {Options} options The logger options.
|
|
12
11
|
*/
|
|
13
|
-
export
|
|
12
|
+
export function handleHttpError(
|
|
14
13
|
request: RequestInfo,
|
|
15
14
|
error: HttpError,
|
|
16
15
|
store: StoreData,
|
|
17
16
|
options?: Options
|
|
18
|
-
):
|
|
17
|
+
): void {
|
|
19
18
|
const statusCode = error.status || 500
|
|
20
|
-
|
|
21
|
-
'ERROR',
|
|
22
|
-
request,
|
|
23
|
-
{ status: statusCode },
|
|
24
|
-
store,
|
|
25
|
-
options
|
|
19
|
+
console.error(
|
|
20
|
+
buildLogMessage('ERROR', request, { status: statusCode }, store, options)
|
|
26
21
|
)
|
|
27
|
-
console.error(logMessage)
|
|
28
22
|
}
|
package/src/logger/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { createLogger } from '
|
|
2
|
-
export { handleHttpError } from '
|
|
1
|
+
export { createLogger } from '~/logger/createLogger'
|
|
2
|
+
export { handleHttpError } from '~/logger/handleHttpError'
|
package/src/logger/logToFile.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { promises as fs } from 'fs'
|
|
2
2
|
import { dirname } from 'path'
|
|
3
3
|
|
|
4
|
+
import { buildLogMessage } from '~/logger/buildLogMessage'
|
|
4
5
|
import { LogData, LogLevel, Options, RequestInfo, StoreData } from '~/types'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
const dirCache = new Set<string>()
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Ensures that the directory exists. If not, it creates the directory.
|
|
@@ -12,7 +13,10 @@ import { buildLogMessage } from './buildLogMessage'
|
|
|
12
13
|
*/
|
|
13
14
|
async function ensureDirectoryExists(filePath: string): Promise<void> {
|
|
14
15
|
const dir = dirname(filePath)
|
|
15
|
-
|
|
16
|
+
if (!dirCache.has(dir)) {
|
|
17
|
+
await fs.mkdir(dir, { recursive: true })
|
|
18
|
+
dirCache.add(dir)
|
|
19
|
+
}
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
/**
|
|
@@ -36,5 +40,5 @@ export async function logToFile(
|
|
|
36
40
|
await ensureDirectoryExists(filePath)
|
|
37
41
|
const logMessage =
|
|
38
42
|
buildLogMessage(level, request, data, store, options, false) + '\n'
|
|
39
|
-
await fs.appendFile(filePath, logMessage)
|
|
43
|
+
await fs.appendFile(filePath, logMessage, { flag: 'a' })
|
|
40
44
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { buildLogMessage } from '~/logger/buildLogMessage'
|
|
2
|
+
import { LogData, LogLevel, Options, RequestInfo, StoreData } from '~/types'
|
|
3
|
+
|
|
4
|
+
export async function logToTransports(
|
|
5
|
+
level: LogLevel,
|
|
6
|
+
request: RequestInfo,
|
|
7
|
+
data: LogData,
|
|
8
|
+
store: StoreData,
|
|
9
|
+
options?: Options
|
|
10
|
+
): Promise<void> {
|
|
11
|
+
if (!options?.config?.transports || options.config.transports.length === 0) {
|
|
12
|
+
return
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const message = buildLogMessage(level, request, data, store, options, false)
|
|
16
|
+
|
|
17
|
+
const promises = options.config.transports.map(transport =>
|
|
18
|
+
transport.log(level, message, { request, data, store })
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
await Promise.all(promises)
|
|
22
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -31,6 +31,18 @@ interface Logger {
|
|
|
31
31
|
customLogFormat?: string
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
interface LogComponents {
|
|
35
|
+
now: string
|
|
36
|
+
epoch: string
|
|
37
|
+
level: string
|
|
38
|
+
duration: string
|
|
39
|
+
method: string
|
|
40
|
+
pathname: string | undefined
|
|
41
|
+
status: string
|
|
42
|
+
message: string
|
|
43
|
+
ip: string
|
|
44
|
+
}
|
|
45
|
+
|
|
34
46
|
interface StoreData {
|
|
35
47
|
beforeTime: bigint
|
|
36
48
|
}
|
|
@@ -44,9 +56,24 @@ class HttpError extends Error {
|
|
|
44
56
|
}
|
|
45
57
|
}
|
|
46
58
|
|
|
59
|
+
interface TransportFunction {
|
|
60
|
+
(
|
|
61
|
+
level: LogLevel,
|
|
62
|
+
message: string,
|
|
63
|
+
meta: {
|
|
64
|
+
request: RequestInfo
|
|
65
|
+
data: LogData
|
|
66
|
+
store: StoreData
|
|
67
|
+
}
|
|
68
|
+
): Promise<void> | void
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
interface Transport {
|
|
72
|
+
log: TransportFunction
|
|
73
|
+
}
|
|
74
|
+
|
|
47
75
|
interface Options {
|
|
48
76
|
config?: {
|
|
49
|
-
ip?: boolean
|
|
50
77
|
customLogFormat?: string
|
|
51
78
|
logFilePath?: string
|
|
52
79
|
logFilter?: {
|
|
@@ -54,18 +81,23 @@ interface Options {
|
|
|
54
81
|
method?: string | string[]
|
|
55
82
|
status?: number | number[]
|
|
56
83
|
} | null
|
|
84
|
+
ip?: boolean
|
|
57
85
|
showBanner?: boolean
|
|
86
|
+
transports?: Transport[]
|
|
58
87
|
}
|
|
59
88
|
}
|
|
60
89
|
|
|
61
90
|
export {
|
|
62
91
|
ColorMap,
|
|
63
92
|
HttpError,
|
|
93
|
+
LogComponents,
|
|
64
94
|
LogData,
|
|
65
95
|
Logger,
|
|
66
96
|
LogLevel,
|
|
67
97
|
Options,
|
|
68
98
|
RequestInfo,
|
|
69
99
|
Server,
|
|
70
|
-
StoreData
|
|
100
|
+
StoreData,
|
|
101
|
+
Transport,
|
|
102
|
+
TransportFunction
|
|
71
103
|
}
|
package/src/utils/duration.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import chalk from 'chalk'
|
|
2
2
|
|
|
3
|
+
const timeUnits = [
|
|
4
|
+
{ unit: 's', threshold: 1e9, decimalPlaces: 2 },
|
|
5
|
+
{ unit: 'ms', threshold: 1e6, decimalPlaces: 0 },
|
|
6
|
+
{ unit: 'ยตs', threshold: 1e3, decimalPlaces: 0 },
|
|
7
|
+
{ unit: 'ns', threshold: 1, decimalPlaces: 0 }
|
|
8
|
+
]
|
|
9
|
+
|
|
3
10
|
/**
|
|
4
11
|
* Converts a time difference into a formatted string with the most appropriate time unit.
|
|
5
12
|
*
|
|
@@ -8,38 +15,19 @@ import chalk from 'chalk'
|
|
|
8
15
|
* @returns {string} A formatted duration string including the time unit.
|
|
9
16
|
*/
|
|
10
17
|
function durationString(beforeTime: bigint, useColors: boolean): string {
|
|
11
|
-
const
|
|
12
|
-
const nanoseconds = Number(currentTime - beforeTime)
|
|
13
|
-
|
|
14
|
-
const timeUnits = [
|
|
15
|
-
{ unit: 's', threshold: 1e9, decimalPlaces: 2 },
|
|
16
|
-
{ unit: 'ms', threshold: 1e6, decimalPlaces: 0 },
|
|
17
|
-
{ unit: 'ยตs', threshold: 1e3, decimalPlaces: 0 }
|
|
18
|
-
]
|
|
18
|
+
const nanoseconds = Number(process.hrtime.bigint() - beforeTime)
|
|
19
19
|
|
|
20
20
|
for (const { unit, threshold, decimalPlaces } of timeUnits) {
|
|
21
21
|
if (nanoseconds >= threshold) {
|
|
22
22
|
const value = (nanoseconds / threshold).toFixed(decimalPlaces)
|
|
23
|
-
|
|
23
|
+
const timeStr = `${value}${unit}`.padStart(8).padEnd(16)
|
|
24
|
+
return useColors ? chalk.gray(timeStr) : timeStr
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
return formatTime(nanoseconds.toString(), 'ns', useColors)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Formats the time value with the given unit and applies chalk styling.
|
|
32
|
-
*
|
|
33
|
-
* @param {string} value - The time value.
|
|
34
|
-
* @param {string} unit - The time unit.
|
|
35
|
-
* @param {boolean} useColors - Whether to apply colors to the output.
|
|
36
|
-
* @returns {string} Styled time string.
|
|
37
|
-
*/
|
|
38
|
-
function formatTime(value: string, unit: string, useColors: boolean): string {
|
|
39
|
-
const timeStr = `${value}${unit}`
|
|
40
28
|
return useColors
|
|
41
|
-
? chalk.gray(
|
|
42
|
-
:
|
|
29
|
+
? chalk.gray('0ns'.padStart(8).padEnd(16))
|
|
30
|
+
: '0ns'.padStart(8).padEnd(16)
|
|
43
31
|
}
|
|
44
32
|
|
|
45
33
|
export default durationString
|
package/src/utils/log.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { LogLevel } from '~/types'
|
|
2
|
-
|
|
3
|
-
import { LogLevelColorMap } from './colorMapping'
|
|
2
|
+
import { LogLevelColorMap } from '~/utils/colorMapping'
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Converts the log level to a string.
|
|
@@ -9,7 +8,7 @@ import { LogLevelColorMap } from './colorMapping'
|
|
|
9
8
|
* @param {boolean} useColors - Whether to apply colors to the output.
|
|
10
9
|
* @returns {string} The log level as a string.
|
|
11
10
|
*/
|
|
12
|
-
|
|
11
|
+
const logString = (level: LogLevel, useColors: boolean): string => {
|
|
13
12
|
const levelStr = level.toUpperCase()
|
|
14
13
|
return useColors
|
|
15
14
|
? LogLevelColorMap[levelStr]?.(levelStr.padEnd(7)) || levelStr
|
package/src/utils/method.ts
CHANGED
package/src/utils/path.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { RequestInfo } from '~/types'
|
|
|
6
6
|
* @param {RequestInfo} requestInfo The request info.
|
|
7
7
|
* @returns {string | undefined} The path string.
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
const pathString = (requestInfo: RequestInfo): string | undefined => {
|
|
10
10
|
try {
|
|
11
11
|
return new URL(requestInfo.url).pathname
|
|
12
12
|
} catch {
|
package/src/utils/start.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { Options, Server } from '~/types'
|
|
|
7
7
|
* @param {number} width The box width.
|
|
8
8
|
* @returns {string} The box text.
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
const createBoxText = (text: string, width: number): string => {
|
|
11
11
|
const paddingLength = Math.max(0, (width - text.length) / 2)
|
|
12
12
|
const padding = ' '.repeat(paddingLength)
|
|
13
13
|
return `${padding}${text}${padding}`.padEnd(width)
|
|
@@ -29,14 +29,15 @@ function startServer(config: Server, options?: Options): void {
|
|
|
29
29
|
const message = `๐ฆ Elysia is running at ${protocol}://${hostname}:${port}`
|
|
30
30
|
const boxWidth = Math.max(title.length, message.length) + 4
|
|
31
31
|
const border = 'โ'.repeat(boxWidth)
|
|
32
|
+
const emptyLine = createBoxText('', boxWidth)
|
|
32
33
|
|
|
33
34
|
console.log(`
|
|
34
35
|
โ${border}โ
|
|
35
|
-
โ${
|
|
36
|
+
โ${emptyLine}โ
|
|
36
37
|
โ${createBoxText(title, boxWidth)}โ
|
|
37
|
-
โ${
|
|
38
|
+
โ${emptyLine}โ
|
|
38
39
|
โ${createBoxText(message, boxWidth)}โ
|
|
39
|
-
โ${
|
|
40
|
+
โ${emptyLine}โ
|
|
40
41
|
โ${border}โ
|
|
41
42
|
`)
|
|
42
43
|
} else {
|
package/src/utils/status.ts
CHANGED
|
@@ -7,7 +7,7 @@ import chalk from 'chalk'
|
|
|
7
7
|
* @param {boolean} useColors - Whether to apply colors to the output.
|
|
8
8
|
* @returns {string} The status code as a string.
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
const statusString = (status: number, useColors: boolean): string => {
|
|
11
11
|
const color =
|
|
12
12
|
status >= 500
|
|
13
13
|
? 'red'
|