@pori15/logixlysia 6.0.1 → 6.0.2

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.
@@ -1,139 +1,138 @@
1
- import pino from 'pino'
2
- import type {
3
- Logger,
4
- LogLevel,
5
- Options,
6
- Pino,
7
- RequestInfo,
8
- StoreData,
9
- LogFilter
10
- } from '../interfaces'
11
- import { logToTransports } from '../output'
12
- import { logToFile } from '../output/file'
13
- import { formatLine } from './create-logger'
14
- import { handleHttpError } from './handle-http-error'
15
-
16
- export const createLogger = (options: Options = {}): Logger => {
17
- const config = options.config
18
-
19
- const pinoConfig = config?.pino
20
- const { prettyPrint, ...pinoOptions } = pinoConfig ?? {}
21
-
22
- const shouldPrettyPrint =
23
- prettyPrint === true && pinoOptions.transport === undefined
24
-
25
- const transport = shouldPrettyPrint
26
- ? pino.transport({
27
- target: 'pino-pretty',
28
- options: {
29
- colorize: process.stdout?.isTTY === true,
30
- translateTime: config?.timestamp?.translateTime,
31
- messageKey: pinoOptions.messageKey,
32
- errorKey: pinoOptions.errorKey
33
- }
34
- })
35
- : pinoOptions.transport
36
-
37
- const pinoLogger: Pino = pino({
38
- ...pinoOptions,
39
- level: pinoOptions.level ?? 'info',
40
- messageKey: pinoOptions.messageKey,
41
- errorKey: pinoOptions.errorKey,
42
- transport
43
- })
44
-
45
- const shouldLog = (level: LogLevel, logFilter?: LogFilter): boolean => {
46
- if (!logFilter?.level || logFilter.level.length === 0) {
47
- return true
48
- }
49
- return logFilter.level.includes(level)
50
- }
51
-
52
- const log = (
53
- level: LogLevel,
54
- request: Request,
55
- data: Record<string, unknown>,
56
- store: StoreData
57
- ): void => {
58
- // Check if this log level should be filtered
59
- if (!shouldLog(level, config?.logFilter)) {
60
- return
61
- }
62
-
63
- logToTransports({ level, request, data, store, options })
64
-
65
- const useTransportsOnly = config?.useTransportsOnly === true
66
- const disableInternalLogger = config?.disableInternalLogger === true
67
- const disableFileLogging = config?.disableFileLogging === true
68
-
69
- if (!(useTransportsOnly || disableFileLogging)) {
70
- const filePath = config?.logFilePath
71
- if (filePath) {
72
- logToFile({ filePath, level, request, data, store, options }).catch(
73
- () => {
74
- // Ignore errors
75
- }
76
- )
77
- }
78
- }
79
-
80
- if (useTransportsOnly || disableInternalLogger) {
81
- return
82
- }
83
-
84
- const message = formatLine({ level, request, data, store, options })
85
-
86
- switch (level) {
87
- case 'DEBUG': {
88
- console.debug(message)
89
- break
90
- }
91
- case 'INFO': {
92
- console.info(message)
93
- break
94
- }
95
- case 'WARNING': {
96
- console.warn(message)
97
- break
98
- }
99
- case 'ERROR': {
100
- console.error(message)
101
- break
102
- }
103
- default: {
104
- console.log(message)
105
- break
106
- }
107
- }
108
- }
109
-
110
- const logWithContext = (
111
- level: LogLevel,
112
- request: Request,
113
- message: string,
114
- context?: Record<string, unknown>
115
- ): void => {
116
- const store: StoreData = { beforeTime: process.hrtime.bigint() }
117
- log(level, request, { message, context }, store)
118
- }
119
-
120
- return {
121
- pino: pinoLogger,
122
- log,
123
- handleHttpError: (request, error, store) => {
124
- handleHttpError(request, error, store, options)
125
- },
126
- debug: (request, message, context) => {
127
- logWithContext('DEBUG', request, message, context)
128
- },
129
- info: (request, message, context) => {
130
- logWithContext('INFO', request, message, context)
131
- },
132
- warn: (request, message, context) => {
133
- logWithContext('WARNING', request, message, context)
134
- },
135
- error: (request, message, context) => {
136
- logWithContext('ERROR', request, message, context)
137
- }
138
- }
139
- }
1
+ import pino from 'pino'
2
+ import type {
3
+ LogFilter,
4
+ Logger,
5
+ LogLevel,
6
+ Options,
7
+ Pino,
8
+ StoreData
9
+ } from '../interfaces'
10
+ import { logToTransports } from '../output'
11
+ import { logToFile } from '../output/file'
12
+ import { formatLine } from './create-logger'
13
+ import { handleHttpError } from './handle-http-error'
14
+
15
+ export const createLogger = (options: Options = {}): Logger => {
16
+ const config = options.config
17
+
18
+ const pinoConfig = config?.pino
19
+ const { prettyPrint, ...pinoOptions } = pinoConfig ?? {}
20
+
21
+ const shouldPrettyPrint =
22
+ prettyPrint === true && pinoOptions.transport === undefined
23
+
24
+ const transport = shouldPrettyPrint
25
+ ? pino.transport({
26
+ target: 'pino-pretty',
27
+ options: {
28
+ colorize: process.stdout?.isTTY === true,
29
+ translateTime: config?.timestamp?.translateTime,
30
+ messageKey: pinoOptions.messageKey,
31
+ errorKey: pinoOptions.errorKey
32
+ }
33
+ })
34
+ : pinoOptions.transport
35
+
36
+ const pinoLogger: Pino = pino({
37
+ ...pinoOptions,
38
+ level: pinoOptions.level ?? 'info',
39
+ messageKey: pinoOptions.messageKey,
40
+ errorKey: pinoOptions.errorKey,
41
+ transport
42
+ })
43
+
44
+ const shouldLog = (level: LogLevel, logFilter?: LogFilter): boolean => {
45
+ if (!logFilter?.level || logFilter.level.length === 0) {
46
+ return true
47
+ }
48
+ return logFilter.level.includes(level)
49
+ }
50
+
51
+ const log = (
52
+ level: LogLevel,
53
+ request: Request,
54
+ data: Record<string, unknown>,
55
+ store: StoreData
56
+ ): void => {
57
+ // Check if this log level should be filtered
58
+ if (!shouldLog(level, config?.logFilter)) {
59
+ return
60
+ }
61
+
62
+ logToTransports({ level, request, data, store, options })
63
+
64
+ const useTransportsOnly = config?.useTransportsOnly === true
65
+ const disableInternalLogger = config?.disableInternalLogger === true
66
+ const disableFileLogging = config?.disableFileLogging === true
67
+
68
+ if (!(useTransportsOnly || disableFileLogging)) {
69
+ const filePath = config?.logFilePath
70
+ if (filePath) {
71
+ logToFile({ filePath, level, request, data, store, options }).catch(
72
+ () => {
73
+ // Ignore errors
74
+ }
75
+ )
76
+ }
77
+ }
78
+
79
+ if (useTransportsOnly || disableInternalLogger) {
80
+ return
81
+ }
82
+
83
+ const message = formatLine({ level, request, data, store, options })
84
+
85
+ switch (level) {
86
+ case 'DEBUG': {
87
+ console.debug(message)
88
+ break
89
+ }
90
+ case 'INFO': {
91
+ console.info(message)
92
+ break
93
+ }
94
+ case 'WARNING': {
95
+ console.warn(message)
96
+ break
97
+ }
98
+ case 'ERROR': {
99
+ console.error(message)
100
+ break
101
+ }
102
+ default: {
103
+ console.log(message)
104
+ break
105
+ }
106
+ }
107
+ }
108
+
109
+ const logWithContext = (
110
+ level: LogLevel,
111
+ request: Request,
112
+ message: string,
113
+ context?: Record<string, unknown>
114
+ ): void => {
115
+ const store: StoreData = { beforeTime: process.hrtime.bigint() }
116
+ log(level, request, { message, context }, store)
117
+ }
118
+
119
+ return {
120
+ pino: pinoLogger,
121
+ log,
122
+ handleHttpError: (request, error, store) => {
123
+ handleHttpError(request, error, store, options)
124
+ },
125
+ debug: (request, message, context) => {
126
+ logWithContext('DEBUG', request, message, context)
127
+ },
128
+ info: (request, message, context) => {
129
+ logWithContext('INFO', request, message, context)
130
+ },
131
+ warn: (request, message, context) => {
132
+ logWithContext('WARNING', request, message, context)
133
+ },
134
+ error: (request, message, context) => {
135
+ logWithContext('ERROR', request, message, context)
136
+ }
137
+ }
138
+ }
@@ -1,85 +1,85 @@
1
- import { appendFile } from 'node:fs/promises'
2
- import { dirname } from 'node:path'
3
- import type { LogLevel, Options, RequestInfo, StoreData } from '../interfaces'
4
- import { ensureDir } from './fs'
5
- import { performRotation, shouldRotate } from './rotation-manager'
6
-
7
- interface LogToFileInput {
8
- filePath: string
9
- level: LogLevel
10
- request: RequestInfo
11
- data: Record<string, unknown>
12
- store: StoreData
13
- options: Options
14
- }
15
-
16
- export const logToFile = async (
17
- ...args:
18
- | [LogToFileInput]
19
- | [
20
- string,
21
- LogLevel,
22
- RequestInfo,
23
- Record<string, unknown>,
24
- StoreData,
25
- Options
26
- ]
27
- ): Promise<void> => {
28
- const input: LogToFileInput =
29
- typeof args[0] === 'string'
30
- ? (() => {
31
- const [
32
- filePathArg,
33
- levelArg,
34
- requestArg,
35
- dataArg,
36
- storeArg,
37
- optionsArg
38
- ] = args as [
39
- string,
40
- LogLevel,
41
- RequestInfo,
42
- Record<string, unknown>,
43
- StoreData,
44
- Options
45
- ]
46
- return {
47
- filePath: filePathArg,
48
- level: levelArg,
49
- request: requestArg,
50
- data: dataArg,
51
- store: storeArg,
52
- options: optionsArg
53
- }
54
- })()
55
- : args[0]
56
-
57
- const { filePath, level, request, data, store, options } = input
58
- const config = options.config
59
- const useTransportsOnly = config?.useTransportsOnly === true
60
- const disableFileLogging = config?.disableFileLogging === true
61
- if (useTransportsOnly || disableFileLogging) {
62
- return
63
- }
64
-
65
- const message = typeof data.message === 'string' ? data.message : ''
66
- const durationMs =
67
- store.beforeTime === BigInt(0)
68
- ? 0
69
- : Number(process.hrtime.bigint() - store.beforeTime) / 1_000_000
70
-
71
- const line = `${level} ${durationMs.toFixed(2)}ms ${request.method} ${new URL(request.url).pathname} ${message}\n`
72
-
73
- await ensureDir(dirname(filePath))
74
- await appendFile(filePath, line, { encoding: 'utf-8' })
75
-
76
- const rotation = config?.logRotation
77
- if (!rotation) {
78
- return
79
- }
80
-
81
- const should = await shouldRotate(filePath, rotation)
82
- if (should) {
83
- await performRotation(filePath, rotation)
84
- }
85
- }
1
+ import { appendFile } from 'node:fs/promises'
2
+ import { dirname } from 'node:path'
3
+ import type { LogLevel, Options, RequestInfo, StoreData } from '../interfaces'
4
+ import { ensureDir } from './fs'
5
+ import { performRotation, shouldRotate } from './rotation-manager'
6
+
7
+ interface LogToFileInput {
8
+ filePath: string
9
+ level: LogLevel
10
+ request: RequestInfo
11
+ data: Record<string, unknown>
12
+ store: StoreData
13
+ options: Options
14
+ }
15
+
16
+ export const logToFile = async (
17
+ ...args:
18
+ | [LogToFileInput]
19
+ | [
20
+ string,
21
+ LogLevel,
22
+ RequestInfo,
23
+ Record<string, unknown>,
24
+ StoreData,
25
+ Options
26
+ ]
27
+ ): Promise<void> => {
28
+ const input: LogToFileInput =
29
+ typeof args[0] === 'string'
30
+ ? (() => {
31
+ const [
32
+ filePathArg,
33
+ levelArg,
34
+ requestArg,
35
+ dataArg,
36
+ storeArg,
37
+ optionsArg
38
+ ] = args as [
39
+ string,
40
+ LogLevel,
41
+ RequestInfo,
42
+ Record<string, unknown>,
43
+ StoreData,
44
+ Options
45
+ ]
46
+ return {
47
+ filePath: filePathArg,
48
+ level: levelArg,
49
+ request: requestArg,
50
+ data: dataArg,
51
+ store: storeArg,
52
+ options: optionsArg
53
+ }
54
+ })()
55
+ : args[0]
56
+
57
+ const { filePath, level, request, data, store, options } = input
58
+ const config = options.config
59
+ const useTransportsOnly = config?.useTransportsOnly === true
60
+ const disableFileLogging = config?.disableFileLogging === true
61
+ if (useTransportsOnly || disableFileLogging) {
62
+ return
63
+ }
64
+
65
+ const message = typeof data.message === 'string' ? data.message : ''
66
+ const durationMs =
67
+ store.beforeTime === BigInt(0)
68
+ ? 0
69
+ : Number(process.hrtime.bigint() - store.beforeTime) / 1_000_000
70
+
71
+ const line = `${level} ${durationMs.toFixed(2)}ms ${request.method} ${new URL(request.url).pathname} ${message}\n`
72
+
73
+ await ensureDir(dirname(filePath))
74
+ await appendFile(filePath, line, { encoding: 'utf-8' })
75
+
76
+ const rotation = config?.logRotation
77
+ if (!rotation) {
78
+ return
79
+ }
80
+
81
+ const should = await shouldRotate(filePath, rotation)
82
+ if (should) {
83
+ await performRotation(filePath, rotation)
84
+ }
85
+ }
package/src/output/fs.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { promises as fs } from 'node:fs'
2
-
3
- export const ensureDir = async (dirPath: string): Promise<void> => {
4
- await fs.mkdir(dirPath, { recursive: true })
5
- }
1
+ import { promises as fs } from 'node:fs'
2
+
3
+ export const ensureDir = async (dirPath: string): Promise<void> => {
4
+ await fs.mkdir(dirPath, { recursive: true })
5
+ }
@@ -1,58 +1,58 @@
1
- import type { LogLevel, Options, Request, StoreData } from '../interfaces'
2
-
3
- interface LogToTransportsInput {
4
- level: LogLevel
5
- request: Request
6
- data: Record<string, unknown>
7
- store: StoreData
8
- options: Options
9
- }
10
-
11
- export const logToTransports = (
12
- ...args:
13
- | [LogToTransportsInput]
14
- | [LogLevel, Request, Record<string, unknown>, StoreData, Options]
15
- ): void => {
16
- const input: LogToTransportsInput =
17
- typeof args[0] === 'string'
18
- ? {
19
- level: args[0],
20
- request: args[1],
21
- data: args[2],
22
- store: args[3],
23
- options: args[4]
24
- }
25
- : args[0]
26
-
27
- const { level, request, data, store, options } = input
28
- const transports = options.config?.transports ?? []
29
- if (transports.length === 0) {
30
- return
31
- }
32
-
33
- const message = typeof data.message === 'string' ? data.message : ''
34
- const meta: Record<string, unknown> = {
35
- request: {
36
- method: request.method,
37
- url: request.url
38
- },
39
- ...data,
40
- beforeTime: store.beforeTime
41
- }
42
-
43
- for (const transport of transports) {
44
- try {
45
- const result = transport.log(level, message, meta)
46
- if (
47
- result &&
48
- typeof (result as { catch?: unknown }).catch === 'function'
49
- ) {
50
- ;(result as Promise<void>).catch(() => {
51
- // Ignore errors
52
- })
53
- }
54
- } catch {
55
- // Transport failures must never crash application logging.
56
- }
57
- }
58
- }
1
+ import type { LogLevel, Options, Request, StoreData } from '../interfaces'
2
+
3
+ interface LogToTransportsInput {
4
+ level: LogLevel
5
+ request: Request
6
+ data: Record<string, unknown>
7
+ store: StoreData
8
+ options: Options
9
+ }
10
+
11
+ export const logToTransports = (
12
+ ...args:
13
+ | [LogToTransportsInput]
14
+ | [LogLevel, Request, Record<string, unknown>, StoreData, Options]
15
+ ): void => {
16
+ const input: LogToTransportsInput =
17
+ typeof args[0] === 'string'
18
+ ? {
19
+ level: args[0],
20
+ request: args[1],
21
+ data: args[2],
22
+ store: args[3],
23
+ options: args[4]
24
+ }
25
+ : args[0]
26
+
27
+ const { level, request, data, store, options } = input
28
+ const transports = options.config?.transports ?? []
29
+ if (transports.length === 0) {
30
+ return
31
+ }
32
+
33
+ const message = typeof data.message === 'string' ? data.message : ''
34
+ const meta: Record<string, unknown> = {
35
+ request: {
36
+ method: request.method,
37
+ url: request.url
38
+ },
39
+ ...data,
40
+ beforeTime: store.beforeTime
41
+ }
42
+
43
+ for (const transport of transports) {
44
+ try {
45
+ const result = transport.log(level, message, meta)
46
+ if (
47
+ result &&
48
+ typeof (result as { catch?: unknown }).catch === 'function'
49
+ ) {
50
+ ;(result as Promise<void>).catch(() => {
51
+ // Ignore errors
52
+ })
53
+ }
54
+ } catch {
55
+ // Transport failures must never crash application logging.
56
+ }
57
+ }
58
+ }