@pori15/logixlysia 0.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,125 +1,138 @@
1
- import pino from 'pino'
2
- import type {
3
- Logger,
4
- LogLevel,
5
- Options,
6
- Pino,
7
- StoreData
8
- } from '../interfaces'
9
- import { logToTransports } from '../output'
10
- import { logToFile } from '../output/file'
11
- import { formatLine } from './create-logger'
12
- import { handleHttpError } from './handle-http-error'
13
-
14
- export const createLogger = (options: Options = {}): Logger => {
15
- const config = options.config
16
-
17
- const pinoConfig = config?.pino
18
- const { prettyPrint, ...pinoOptions } = pinoConfig ?? {}
19
-
20
- const shouldPrettyPrint =
21
- prettyPrint === true && pinoOptions.transport === undefined
22
-
23
- const transport = shouldPrettyPrint
24
- ? pino.transport({
25
- target: 'pino-pretty',
26
- options: {
27
- colorize: process.stdout?.isTTY === true,
28
- translateTime: config?.timestamp?.translateTime,
29
- messageKey: pinoOptions.messageKey,
30
- errorKey: pinoOptions.errorKey
31
- }
32
- })
33
- : pinoOptions.transport
34
-
35
- const pinoLogger: Pino = pino({
36
- ...pinoOptions,
37
- level: pinoOptions.level ?? 'info',
38
- messageKey: pinoOptions.messageKey,
39
- errorKey: pinoOptions.errorKey,
40
- transport
41
- })
42
-
43
- const log = (
44
- level: LogLevel,
45
- request: Request,
46
- data: Record<string, unknown>,
47
- store: StoreData
48
- ): void => {
49
- logToTransports({ level, request, data, store, options })
50
-
51
- const useTransportsOnly = config?.useTransportsOnly === true
52
- const disableInternalLogger = config?.disableInternalLogger === true
53
- const disableFileLogging = config?.disableFileLogging === true
54
-
55
- if (!(useTransportsOnly || disableFileLogging)) {
56
- const filePath = config?.logFilePath
57
- if (filePath) {
58
- logToFile({ filePath, level, request, data, store, options }).catch(
59
- () => {
60
- // Ignore errors
61
- }
62
- )
63
- }
64
- }
65
-
66
- if (useTransportsOnly || disableInternalLogger) {
67
- return
68
- }
69
-
70
- const message = formatLine({ level, request, data, store, options })
71
-
72
- switch (level) {
73
- case 'DEBUG': {
74
- console.debug(message)
75
- break
76
- }
77
- case 'INFO': {
78
- console.info(message)
79
- break
80
- }
81
- case 'WARNING': {
82
- console.warn(message)
83
- break
84
- }
85
- case 'ERROR': {
86
- console.error(message)
87
- break
88
- }
89
- default: {
90
- console.log(message)
91
- break
92
- }
93
- }
94
- }
95
-
96
- const logWithContext = (
97
- level: LogLevel,
98
- request: Request,
99
- message: string,
100
- context?: Record<string, unknown>
101
- ): void => {
102
- const store: StoreData = { beforeTime: process.hrtime.bigint() }
103
- log(level, request, { message, context }, store)
104
- }
105
-
106
- return {
107
- pino: pinoLogger,
108
- log,
109
- handleHttpError: (request, error, store) => {
110
- handleHttpError(request, error, store, options)
111
- },
112
- debug: (request, message, context) => {
113
- logWithContext('DEBUG', request, message, context)
114
- },
115
- info: (request, message, context) => {
116
- logWithContext('INFO', request, message, context)
117
- },
118
- warn: (request, message, context) => {
119
- logWithContext('WARNING', request, message, context)
120
- },
121
- error: (request, message, context) => {
122
- logWithContext('ERROR', request, message, context)
123
- }
124
- }
125
- }
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
+ }