logixlysia 3.3.2 → 3.4.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,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.4.0](https://github.com/PunGrumpy/logixlysia/compare/v3.3.2...v3.4.0) (2024-06-17)
4
+
5
+
6
+ ### Features
7
+
8
+ * **logger:** add file logging capability ([6d913a3](https://github.com/PunGrumpy/logixlysia/commit/6d913a3dcc6cbba40bcaa4b6c4c4a4b474a90969))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **logger:** remove ANSI color codes from log files ([df42315](https://github.com/PunGrumpy/logixlysia/commit/df423151399f9436121b0d5d4a9b0424befdc835))
14
+
3
15
  ## [3.3.2](https://github.com/PunGrumpy/logixlysia/compare/v3.3.1...v3.3.2) (2024-06-06)
4
16
 
5
17
 
package/README.md CHANGED
@@ -14,7 +14,7 @@ bun add logixlysia
14
14
 
15
15
  ```ts
16
16
  import { Elysia } from 'elysia'
17
- import { logixlysia } from 'logixlysia'
17
+ import logixlysia from 'logixlysia'
18
18
 
19
19
  const app = new Elysia({
20
20
  name: 'Logixlysia Example'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "logixlysia",
3
- "version": "3.3.2",
3
+ "version": "3.4.0",
4
4
  "description": "🦊 Logixlysia is a logger for Elysia",
5
5
  "type": "module",
6
6
  "module": "src/index.ts",
package/src/index.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import { Server } from 'bun'
2
2
  import Elysia from 'elysia'
3
3
 
4
- import { createLogger } from './logger/createLogger'
5
- import { handleHttpError } from './logger/handleHttpError'
4
+ import { createLogger, handleHttpError } from './logger'
6
5
  import { HttpError, Options } from './types'
7
6
  import startServer from './utils/start'
8
7
 
@@ -16,9 +15,6 @@ import startServer from './utils/start'
16
15
  *
17
16
  * @name Logixlysia
18
17
  * @description Logixlysia is a logger plugin for ElysiaJS.
19
- * @author PunGrumpy
20
- * @license MIT
21
- *
22
18
  * @param {Options} [options] Configuration options for the logger.
23
19
  *
24
20
  * @returns {Elysia} The logger plugin for ElysiaJS.
@@ -26,12 +22,10 @@ import startServer from './utils/start'
26
22
  export default function logixlysia(options?: Options): Elysia {
27
23
  const log = createLogger(options)
28
24
 
29
- const elysia = new Elysia({
25
+ return new Elysia({
30
26
  name: 'Logixlysia'
31
27
  })
32
- .onStart(ctx => {
33
- startServer(ctx.server as Server)
34
- })
28
+ .onStart(ctx => startServer(ctx.server as Server))
35
29
  .onRequest(ctx => {
36
30
  ctx.store = { beforeTime: process.hrtime.bigint() }
37
31
  })
@@ -46,6 +40,4 @@ export default function logixlysia(options?: Options): Elysia {
46
40
  options
47
41
  )
48
42
  })
49
-
50
- return elysia
51
43
  }
@@ -15,6 +15,7 @@ import statusString from '~/utils/status'
15
15
  * @param {LogData} data The log data.
16
16
  * @param {StoreData} store The store data.
17
17
  * @param {Options} options The logger options.
18
+ * @param {boolean} useColors Whether to apply colors to the log message.
18
19
  * @returns {string} The formatted log message.
19
20
  */
20
21
  export function buildLogMessage(
@@ -22,14 +23,17 @@ export function buildLogMessage(
22
23
  request: RequestInfo,
23
24
  data: LogData,
24
25
  store: StoreData,
25
- options?: Options
26
+ options?: Options,
27
+ useColors: boolean = true
26
28
  ): string {
27
- const nowStr = chalk.bgYellow(chalk.black(new Date().toLocaleString()))
28
- const levelStr = logString(level)
29
- const durationStr = durationString(store.beforeTime)
30
- const methodStr = methodString(request.method)
29
+ const nowStr = useColors
30
+ ? chalk.bgYellow(chalk.black(new Date().toLocaleString()))
31
+ : new Date().toLocaleString()
32
+ const levelStr = logString(level, useColors)
33
+ const durationStr = durationString(store.beforeTime, useColors)
34
+ const methodStr = methodString(request.method, useColors)
31
35
  const pathnameStr = pathString(request)
32
- const statusStr = statusString(data.status || 200)
36
+ const statusStr = statusString(data.status || 200, useColors)
33
37
  const messageStr = data.message || ''
34
38
  const ipStr =
35
39
  options?.config?.ip && request.headers.get('x-forwarded-for')
@@ -39,7 +43,8 @@ export function buildLogMessage(
39
43
  const logFormat =
40
44
  options?.config?.customLogFormat ||
41
45
  '🦊 {now} {level} {duration} {method} {pathname} {status} {message} {ip}'
42
- const logMessage = logFormat
46
+
47
+ return logFormat
43
48
  .replace('{now}', nowStr)
44
49
  .replace('{level}', levelStr)
45
50
  .replace('{duration}', durationStr)
@@ -48,6 +53,4 @@ export function buildLogMessage(
48
53
  .replace('{status}', statusStr)
49
54
  .replace('{message}', messageStr)
50
55
  .replace('{ip}', ipStr || '')
51
-
52
- return logMessage
53
56
  }
@@ -9,9 +9,10 @@ import {
9
9
 
10
10
  import { buildLogMessage } from './buildLogMessage'
11
11
  import { filterLog } from './filter'
12
+ import { logToFile } from './logToFile'
12
13
 
13
14
  /**
14
- * Logs a message to the console.
15
+ * Logs a message to the console and optionally to a file.
15
16
  *
16
17
  * @param {LogLevel} level The log level.
17
18
  * @param {RequestInfo} request The request information.
@@ -26,12 +27,21 @@ async function log(
26
27
  store: StoreData,
27
28
  options?: Options
28
29
  ): Promise<void> {
29
- if (!filterLog(level, data.status || 200, request.method, options)) {
30
- return
31
- }
30
+ if (!filterLog(level, data.status || 200, request.method, options)) return
32
31
 
33
- const logMessage = buildLogMessage(level, request, data, store, options)
32
+ const logMessage = buildLogMessage(level, request, data, store, options, true)
34
33
  console.log(logMessage)
34
+
35
+ if (options?.config?.logFilePath) {
36
+ await logToFile(
37
+ options.config.logFilePath,
38
+ level,
39
+ request,
40
+ data,
41
+ store,
42
+ options
43
+ )
44
+ }
35
45
  }
36
46
 
37
47
  /**
@@ -9,41 +9,23 @@ import { LogLevel, Options } from '~/types'
9
9
  * @param {Options} options The options.
10
10
  * @returns {boolean} `true` if the log message should be logged, otherwise `false`.
11
11
  */
12
- function filterLog(
12
+ export function filterLog(
13
13
  logLevel: LogLevel,
14
14
  status: number,
15
15
  method: string,
16
16
  options?: Options
17
17
  ): boolean {
18
18
  const filter = options?.config?.logFilter
19
-
20
19
  if (!filter) return true
21
20
 
22
- if (filter.level) {
23
- if (Array.isArray(filter.level)) {
24
- if (!filter.level.includes(logLevel)) return false
25
- } else {
26
- if (filter.level !== logLevel) return false
27
- }
28
- }
29
-
30
- if (filter.status) {
31
- if (Array.isArray(filter.status)) {
32
- if (!filter.status.includes(status)) return false
33
- } else {
34
- if (filter.status !== status) return false
35
- }
36
- }
21
+ const checkFilter = (filterValue: any, value: any) =>
22
+ Array.isArray(filterValue)
23
+ ? filterValue.includes(value)
24
+ : filterValue === value
37
25
 
38
- if (filter.method) {
39
- if (Array.isArray(filter.method)) {
40
- if (!filter.method.includes(method)) return false
41
- } else {
42
- if (filter.method !== method) return false
43
- }
44
- }
45
-
46
- return true
26
+ return (
27
+ (!filter.level || checkFilter(filter.level, logLevel)) &&
28
+ (!filter.status || checkFilter(filter.status, status)) &&
29
+ (!filter.method || checkFilter(filter.method, method))
30
+ )
47
31
  }
48
-
49
- export { filterLog }
@@ -0,0 +1,2 @@
1
+ export { createLogger } from './createLogger'
2
+ export { handleHttpError } from './handleHttpError'
@@ -0,0 +1,40 @@
1
+ import { promises as fs } from 'fs'
2
+ import { dirname } from 'path'
3
+
4
+ import { LogData, LogLevel, Options, RequestInfo, StoreData } from '~/types'
5
+
6
+ import { buildLogMessage } from './buildLogMessage'
7
+
8
+ /**
9
+ * Ensures that the directory exists. If not, it creates the directory.
10
+ *
11
+ * @param {string} filePath The path to the log file.
12
+ */
13
+ async function ensureDirectoryExists(filePath: string): Promise<void> {
14
+ const dir = dirname(filePath)
15
+ await fs.mkdir(dir, { recursive: true })
16
+ }
17
+
18
+ /**
19
+ * Logs a message to a file.
20
+ *
21
+ * @param {string} filePath The path to the log file.
22
+ * @param {LogLevel} level The log level.
23
+ * @param {RequestInfo} request The request information.
24
+ * @param {LogData} data The log data.
25
+ * @param {StoreData} store The store data.
26
+ * @param {Options} options The logger options.
27
+ */
28
+ export async function logToFile(
29
+ filePath: string,
30
+ level: LogLevel,
31
+ request: RequestInfo,
32
+ data: LogData,
33
+ store: StoreData,
34
+ options?: Options
35
+ ): Promise<void> {
36
+ await ensureDirectoryExists(filePath)
37
+ const logMessage =
38
+ buildLogMessage(level, request, data, store, options, false) + '\n'
39
+ await fs.appendFile(filePath, logMessage)
40
+ }
package/src/types.ts CHANGED
@@ -48,6 +48,7 @@ interface Options {
48
48
  config?: {
49
49
  ip?: boolean
50
50
  customLogFormat?: string
51
+ logFilePath?: string
51
52
  logFilter?: {
52
53
  level?: LogLevel | LogLevel[]
53
54
  method?: string | string[]
@@ -6,9 +6,6 @@ import { ColorMap } from '~/types'
6
6
  * The color map for the log levels.
7
7
  *
8
8
  * @type {ColorMap}
9
- * @property {chalk.Chalk} INFO The color for the INFO log level.
10
- * @property {chalk.Chalk} WARNING The color for the WARNING log level.
11
- * @property {chalk.Chalk} ERROR The color for the ERROR log level.
12
9
  */
13
10
  const LogLevelColorMap: ColorMap = {
14
11
  INFO: chalk.bgGreen.black,
@@ -20,13 +17,6 @@ const LogLevelColorMap: ColorMap = {
20
17
  * The color map for the HTTP methods.
21
18
  *
22
19
  * @type {ColorMap}
23
- * @property {chalk.Chalk} GET The color for the GET HTTP method.
24
- * @property {chalk.Chalk} POST The color for the POST HTTP method.
25
- * @property {chalk.Chalk} PUT The color for the PUT HTTP method.
26
- * @property {chalk.Chalk} PATCH The color for the PATCH HTTP method.
27
- * @property {chalk.Chalk} DELETE The color for the DELETE HTTP method.
28
- * @property {chalk.Chalk} HEAD The color for the HEAD HTTP method.
29
- * @property {chalk.Chalk} OPTIONS The color for the OPTIONS HTTP method.
30
20
  */
31
21
  const HttpMethodColorMap: ColorMap = {
32
22
  GET: chalk.green,
@@ -2,13 +2,12 @@ import chalk from 'chalk'
2
2
 
3
3
  /**
4
4
  * Converts a time difference into a formatted string with the most appropriate time unit.
5
- * Units used are seconds (s), milliseconds (ms), microseconds (µs), and nanoseconds (ns).
6
5
  *
7
6
  * @param {bigint} beforeTime - The timestamp taken before the request.
8
- *
7
+ * @param {boolean} useColors - Whether to apply colors to the output.
9
8
  * @returns {string} A formatted duration string including the time unit.
10
9
  */
11
- function durationString(beforeTime: bigint): string {
10
+ function durationString(beforeTime: bigint, useColors: boolean): string {
12
11
  const currentTime = process.hrtime.bigint()
13
12
  const nanoseconds = Number(currentTime - beforeTime)
14
13
 
@@ -21,11 +20,11 @@ function durationString(beforeTime: bigint): string {
21
20
  for (const { unit, threshold, decimalPlaces } of timeUnits) {
22
21
  if (nanoseconds >= threshold) {
23
22
  const value = (nanoseconds / threshold).toFixed(decimalPlaces)
24
- return formatTime(value, unit)
23
+ return formatTime(value, unit, useColors)
25
24
  }
26
25
  }
27
26
 
28
- return formatTime(nanoseconds.toString(), 'ns')
27
+ return formatTime(nanoseconds.toString(), 'ns', useColors)
29
28
  }
30
29
 
31
30
  /**
@@ -33,11 +32,14 @@ function durationString(beforeTime: bigint): string {
33
32
  *
34
33
  * @param {string} value - The time value.
35
34
  * @param {string} unit - The time unit.
36
- *
35
+ * @param {boolean} useColors - Whether to apply colors to the output.
37
36
  * @returns {string} Styled time string.
38
37
  */
39
- function formatTime(value: string, unit: string): string {
40
- return chalk.gray(`${value}${unit}`).padStart(8).padEnd(16)
38
+ function formatTime(value: string, unit: string, useColors: boolean): string {
39
+ const timeStr = `${value}${unit}`
40
+ return useColors
41
+ ? chalk.gray(timeStr).padStart(8).padEnd(16)
42
+ : timeStr.padStart(8).padEnd(16)
41
43
  }
42
44
 
43
45
  export default durationString
package/src/utils/log.ts CHANGED
@@ -6,11 +6,14 @@ import { LogLevelColorMap } from './colorMapping'
6
6
  * Converts the log level to a string.
7
7
  *
8
8
  * @param {LogLevel} level The log level.
9
+ * @param {boolean} useColors - Whether to apply colors to the output.
9
10
  * @returns {string} The log level as a string.
10
11
  */
11
- function logString(level: LogLevel): string {
12
+ function logString(level: LogLevel, useColors: boolean): string {
12
13
  const levelStr = level.toUpperCase()
13
- return LogLevelColorMap[levelStr]?.(levelStr.padEnd(7)) || levelStr
14
+ return useColors
15
+ ? LogLevelColorMap[levelStr]?.(levelStr.padEnd(7)) || levelStr
16
+ : levelStr.padEnd(7)
14
17
  }
15
18
 
16
19
  export default logString
@@ -4,17 +4,14 @@ import { HttpMethodColorMap } from './colorMapping'
4
4
  * Converts an HTTP request method to a colored string representation.
5
5
  *
6
6
  * @param {string} method The HTTP request method (e.g., 'GET', 'POST').
7
- *
8
- * @returns {string} A colored string representing the method.
7
+ * @param {boolean} useColors - Whether to apply colors to the output.
8
+ * @returns {string} A string representing the method.
9
9
  */
10
- function methodString(method: string): string {
10
+ function methodString(method: string, useColors: boolean): string {
11
11
  const colorFunction = HttpMethodColorMap[method]
12
-
13
- if (colorFunction) {
14
- return colorFunction(method.padEnd(7))
15
- }
16
-
17
- return method
12
+ return useColors && colorFunction
13
+ ? colorFunction(method.padEnd(7))
14
+ : method.padEnd(7)
18
15
  }
19
16
 
20
17
  export default methodString
package/src/utils/path.ts CHANGED
@@ -4,10 +4,8 @@ import { RequestInfo } from '~/types'
4
4
  * Returns the path string.
5
5
  *
6
6
  * @param {RequestInfo} requestInfo The request info.
7
- *
8
7
  * @returns {string | undefined} The path string.
9
8
  */
10
-
11
9
  function pathString(requestInfo: RequestInfo): string | undefined {
12
10
  try {
13
11
  return new URL(requestInfo.url).pathname
@@ -5,7 +5,6 @@ import { Server } from '~/types'
5
5
  *
6
6
  * @param {string} text The text.
7
7
  * @param {number} width The box width.
8
- *
9
8
  * @returns {string} The box text.
10
9
  */
11
10
  function createBoxText(text: string, width: number): string {
@@ -18,7 +17,6 @@ function createBoxText(text: string, width: number): string {
18
17
  * Starts the server string.
19
18
  *
20
19
  * @param {Server} config The server configuration.
21
- *
22
20
  * @returns {void} The server string.
23
21
  */
24
22
  function startServer(config: Server): void {
@@ -4,10 +4,10 @@ import chalk from 'chalk'
4
4
  * Converts the status code to a string.
5
5
  *
6
6
  * @param {number} status The status code.
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
- function statusString(status: number): string {
10
+ function statusString(status: number, useColors: boolean): string {
11
11
  const color =
12
12
  status >= 500
13
13
  ? 'red'
@@ -18,7 +18,7 @@ function statusString(status: number): string {
18
18
  : status >= 200
19
19
  ? 'green'
20
20
  : 'white'
21
- return chalk[color](status.toString())
21
+ return useColors ? chalk[color](status.toString()) : status.toString()
22
22
  }
23
23
 
24
24
  export default statusString
package/.trunk/trunk.yaml DELETED
@@ -1,26 +0,0 @@
1
- ---
2
- version: 0.1
3
- cli:
4
- version: 1.22.1
5
- plugins:
6
- sources:
7
- - id: trunk
8
- ref: v1.5.0
9
- uri: https://github.com/trunk-io/plugins
10
- runtimes:
11
- enabled:
12
- - node@22.2.0
13
- lint:
14
- enabled:
15
- - oxipng@9.1.1
16
- - shfmt@3.6.0
17
- - eslint@9.3.0
18
- - actionlint@1.7.0
19
- - git-diff-check
20
- - markdownlint@0.40.0
21
- - prettier@3.2.5
22
- - trufflehog@3.76.3
23
- - yamllint@1.35.1
24
- actions:
25
- enabled:
26
- - npm-check
@@ -1,8 +0,0 @@
1
- module.exports = {
2
- '**/*.(ts)': () => `bun tsc --noEmit`,
3
- '**/*.(ts|js|cjs)': filenames => [
4
- `bun eslint --fix ${filenames.join(' ')}`,
5
- `bun prettier --write ${filenames.join(' ')}`
6
- ],
7
- '**/*.(md|json)': filenames => `bun prettier --write ${filenames.join(' ')}`
8
- }