bootifyjs 0.0.1 → 0.0.3
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/README.md +567 -0
- package/package.json +1 -1
- package/src/application/Application.ts +0 -355
- package/src/container/container.ts +0 -28
- package/src/decorators/cache/ICacheClient.ts +0 -5
- package/src/decorators/cache/cache.decorator.ts +0 -36
- package/src/decorators/controller.decorator.ts +0 -119
- package/src/decorators/http.decorator.ts +0 -25
- package/src/decorators/timing.decorator.ts +0 -23
- package/src/decorators/transaction/IDatabaseClient.ts +0 -9
- package/src/decorators/transaction/transactional.decorator.ts +0 -24
- package/src/index.ts +0 -10
- package/src/logger/Logger.ts +0 -179
- package/src/middleware/http.ts +0 -81
- package/src/middleware/requestcontext.ts +0 -12
package/src/logger/Logger.ts
DELETED
@@ -1,179 +0,0 @@
|
|
1
|
-
import pino from 'pino'
|
2
|
-
import { LogContext, requestContext } from '../middleware/requestcontext'
|
3
|
-
// import { requestContext, LogContext } from '../middleware/requestcontext'
|
4
|
-
|
5
|
-
// --- Define interfaces for your specific log types ---
|
6
|
-
interface AppLogPayload {
|
7
|
-
// For general application messages
|
8
|
-
message: string
|
9
|
-
[key: string]: any // Allow other custom fields
|
10
|
-
}
|
11
|
-
|
12
|
-
interface AuditLogPayload {
|
13
|
-
// Based on your AuditLog type
|
14
|
-
action: string
|
15
|
-
resources: string[]
|
16
|
-
details: any // Renamed from 'data' to avoid conflict if 'data' is a generic field
|
17
|
-
[key: string]: any
|
18
|
-
}
|
19
|
-
|
20
|
-
interface EventLogPayload {
|
21
|
-
// Based on your EventLog type
|
22
|
-
eventName: string
|
23
|
-
status: 'success' | 'failure' | 'pending'
|
24
|
-
metadata: any
|
25
|
-
[key: string]: any
|
26
|
-
}
|
27
|
-
|
28
|
-
// (HttpLogPayload is implicitly handled by pino-http)
|
29
|
-
|
30
|
-
class Logger {
|
31
|
-
private pinoInstance: pino.Logger
|
32
|
-
private static instance: Logger
|
33
|
-
|
34
|
-
private constructor() {
|
35
|
-
const basePinoOptions: pino.LoggerOptions = {
|
36
|
-
level: process.env.LOG_LEVEL || 'info',
|
37
|
-
timestamp: () => `,"time":"${new Date().toISOString()}"`,
|
38
|
-
messageKey: 'message', // Consistent message key
|
39
|
-
base: {
|
40
|
-
// Remove default pino fields if not needed
|
41
|
-
pid: undefined,
|
42
|
-
hostname: undefined,
|
43
|
-
},
|
44
|
-
formatters: {
|
45
|
-
level: (label: string) => ({ level: label.toLowerCase() }), // Ensure lowercase level
|
46
|
-
},
|
47
|
-
mixin: () => {
|
48
|
-
const store = requestContext.getStore()
|
49
|
-
return {
|
50
|
-
// Common context fields from AsyncLocalStorage
|
51
|
-
requestId: store?.requestId,
|
52
|
-
userId: store?.userId, // This might be overridden by specific log methods like audit
|
53
|
-
traceId: store?.traceId,
|
54
|
-
username: store?.username,
|
55
|
-
// 'additionalContext' from ALS will be merged into the 'context' field for ClickHouse by the transport
|
56
|
-
// context: store?.additionalContext || {},
|
57
|
-
}
|
58
|
-
},
|
59
|
-
}
|
60
|
-
|
61
|
-
const transports = []
|
62
|
-
// const clickHouseTransportPath = path.resolve(__dirname, 'pino-clickhouse-transport.js')
|
63
|
-
|
64
|
-
transports.push({
|
65
|
-
level: 'info', // Minimum level for ClickHouse transport
|
66
|
-
// target: clickHouseTransportPath,
|
67
|
-
options: {
|
68
|
-
url: process.env.CLICKHOUSE_URL || 'http://localhost:8123',
|
69
|
-
username: process.env.CLICKHOUSE_USER || 'default',
|
70
|
-
password: process.env.CLICKHOUSE_PASSWORD || '',
|
71
|
-
database: process.env.CLICKHOUSE_DB || 'default',
|
72
|
-
maxBatchSize: parseInt(process.env.CLICKHOUSE_MAX_BATCH_SIZE || '1000', 10),
|
73
|
-
flushInterval: parseInt(process.env.CLICKHOUSE_FLUSH_INTERVAL || '3000', 10),
|
74
|
-
application: process.env.APP_NAME || 'my-application',
|
75
|
-
},
|
76
|
-
})
|
77
|
-
|
78
|
-
if (process.env.NODE_ENV !== 'production') {
|
79
|
-
transports.push({
|
80
|
-
level: 'debug',
|
81
|
-
target: 'pino-pretty',
|
82
|
-
options: {
|
83
|
-
colorize: true,
|
84
|
-
translateTime: 'SYS:standard',
|
85
|
-
ignore: 'pid,hostname,context,username,requestId,userId,traceId,application',
|
86
|
-
messageKey: 'message', // Ensure pino-pretty uses the same messageKey
|
87
|
-
},
|
88
|
-
})
|
89
|
-
}
|
90
|
-
|
91
|
-
this.pinoInstance = pino({
|
92
|
-
...basePinoOptions,
|
93
|
-
// transport: transports.length > 0 ? { targets: transports } : undefined,
|
94
|
-
})
|
95
|
-
}
|
96
|
-
|
97
|
-
public static getInstance(): Logger {
|
98
|
-
if (!Logger.instance) {
|
99
|
-
try {
|
100
|
-
Logger.instance = new Logger()
|
101
|
-
} catch (error: any) {
|
102
|
-
console.error('CRITICAL: Error creating logger instance:', error.message)
|
103
|
-
// Fallback to a very basic console logger if main setup fails
|
104
|
-
const fallbackPino = pino({ level: 'info', messageKey: 'message' })
|
105
|
-
fallbackPino.error(
|
106
|
-
{ err: error },
|
107
|
-
'Fallback console logger activated due to error in primary logger setup.'
|
108
|
-
)
|
109
|
-
const fallbackInstance = Object.create(Logger.prototype) as Logger
|
110
|
-
fallbackInstance.pinoInstance = fallbackPino
|
111
|
-
Logger.instance = fallbackInstance
|
112
|
-
}
|
113
|
-
}
|
114
|
-
return Logger.instance
|
115
|
-
}
|
116
|
-
|
117
|
-
/**
|
118
|
-
* Provides access to the raw pino instance, primarily for use with pino-http.
|
119
|
-
*/
|
120
|
-
public getPinoInstance(): pino.Logger {
|
121
|
-
return this.pinoInstance
|
122
|
-
}
|
123
|
-
|
124
|
-
// --- Application Logging Methods ---
|
125
|
-
private appLog(level: pino.Level, payload: AppLogPayload): void {
|
126
|
-
this.pinoInstance[level]({ ...payload, logType: 'application' })
|
127
|
-
}
|
128
|
-
public info(message: string, data?: Record<string, any>): void {
|
129
|
-
this.appLog('info', { message, ...data })
|
130
|
-
}
|
131
|
-
public error(message: string, error?: Error, data?: Record<string, any>): void {
|
132
|
-
const payload: AppLogPayload = { message, ...data }
|
133
|
-
if (error) {
|
134
|
-
payload.err = error // pino stdSerializers.err will handle this
|
135
|
-
}
|
136
|
-
this.appLog('error', payload)
|
137
|
-
}
|
138
|
-
public warn(message: string, data?: Record<string, any>): void {
|
139
|
-
this.appLog('warn', { message, ...data })
|
140
|
-
}
|
141
|
-
public debug(message: string, data?: Record<string, any>): void {
|
142
|
-
this.appLog('debug', { message, ...data })
|
143
|
-
}
|
144
|
-
public fatal(message: string, error?: Error, data?: Record<string, any>): void {
|
145
|
-
const payload: AppLogPayload = { message, ...data }
|
146
|
-
if (error) {
|
147
|
-
payload.err = error
|
148
|
-
}
|
149
|
-
this.appLog('fatal', payload)
|
150
|
-
}
|
151
|
-
public trace(message: string, data?: Record<string, any>): void {
|
152
|
-
this.appLog('trace', { message, ...data })
|
153
|
-
}
|
154
|
-
|
155
|
-
// --- Audit Logging Method ---
|
156
|
-
public audit(payload: AuditLogPayload): void {
|
157
|
-
// userId from payload will override userId from mixin if both exist
|
158
|
-
this.pinoInstance.info({ ...payload, logType: 'audit' })
|
159
|
-
}
|
160
|
-
|
161
|
-
// --- Event Logging Method ---
|
162
|
-
public event(payload: EventLogPayload): void {
|
163
|
-
this.pinoInstance.info({ ...payload, logType: 'event' })
|
164
|
-
}
|
165
|
-
|
166
|
-
// --- Child Logger ---
|
167
|
-
public child(bindings: Partial<LogContext> & Record<string, any> = {}): Logger {
|
168
|
-
// Create a new pino child logger instance with additional static bindings
|
169
|
-
const pinoChild = this.pinoInstance.child(bindings)
|
170
|
-
// Create a new Logger wrapper for this pino child
|
171
|
-
const childLoggerInstance = Object.create(Logger.prototype) as Logger
|
172
|
-
childLoggerInstance.pinoInstance = pinoChild
|
173
|
-
return childLoggerInstance
|
174
|
-
}
|
175
|
-
}
|
176
|
-
|
177
|
-
const logger = Logger.getInstance()
|
178
|
-
|
179
|
-
export default logger
|
package/src/middleware/http.ts
DELETED
@@ -1,81 +0,0 @@
|
|
1
|
-
import PinoHttp from 'pino-http'
|
2
|
-
import pino from 'pino'
|
3
|
-
import logger from '../logger/Logger'
|
4
|
-
export const httpLoggerMiddleware = PinoHttp({
|
5
|
-
logger: logger.getPinoInstance(), // Use the main pino instance
|
6
|
-
|
7
|
-
customLogLevel: (req, res, err) => {
|
8
|
-
if (res.statusCode >= 500 || err) return 'error'
|
9
|
-
if (res.statusCode >= 400) return 'warn'
|
10
|
-
return 'info'
|
11
|
-
},
|
12
|
-
serializers: {
|
13
|
-
req: (req) => ({
|
14
|
-
id: req.id, // Made available as objFromPinoHttp.req.id
|
15
|
-
method: req.method,
|
16
|
-
url: req.url,
|
17
|
-
remoteAddress: req.remoteAddress || req.socket?.remoteAddress,
|
18
|
-
}),
|
19
|
-
res: (res) => ({
|
20
|
-
statusCode: res.statusCode,
|
21
|
-
}),
|
22
|
-
err: pino.stdSerializers.err,
|
23
|
-
},
|
24
|
-
|
25
|
-
// This formatter *must* return the complete, flat object you want to log.
|
26
|
-
formatters: {
|
27
|
-
log: (objFromPinoHttp: any) => {
|
28
|
-
// objFromPinoHttp contains:
|
29
|
-
// - .req, .res, .err (from serializers above)
|
30
|
-
// - .responseTime (number)
|
31
|
-
// - .level (string, from customLogLevel)
|
32
|
-
// - .message (string, from customSuccessMessage/customErrorMessage)
|
33
|
-
// - properties from `customProps` (e.g., .requestId from req.id fallback)
|
34
|
-
// - IMPORTANT: It ALSO contains properties from the parent `appLogger`'s `mixin`
|
35
|
-
// because pino-http uses the parent logger, and its mixin will have run.
|
36
|
-
|
37
|
-
const finalHttpLog: Record<string, any> = {
|
38
|
-
// Standard fields (time will be added by parent pino instance when it actually logs)
|
39
|
-
level: 'hello',
|
40
|
-
test: '123',
|
41
|
-
message: objFromPinoHttp.message,
|
42
|
-
|
43
|
-
// Contextual fields (these should be present in objFromPinoHttp thanks to parent logger's mixin)
|
44
|
-
requestId: objFromPinoHttp.requestId, // This should be the definitive one after mixin
|
45
|
-
userId: objFromPinoHttp.userId,
|
46
|
-
username: objFromPinoHttp.username,
|
47
|
-
traceId: objFromPinoHttp.traceId,
|
48
|
-
context: objFromPinoHttp.context, // from ALS additionalContext
|
49
|
-
application: objFromPinoHttp.application, // from parent logger or transport default
|
50
|
-
|
51
|
-
// HTTP specific data, flattened:
|
52
|
-
logType: 'http',
|
53
|
-
method: objFromPinoHttp.req?.method,
|
54
|
-
url: objFromPinoHttp.req?.url,
|
55
|
-
remoteAddress: objFromPinoHttp.req?.remoteAddress,
|
56
|
-
statusCode: objFromPinoHttp.res?.statusCode,
|
57
|
-
responseTimeMs: objFromPinoHttp.responseTime,
|
58
|
-
// If you need req.id specifically, and it's different from the main requestId:
|
59
|
-
// originalHttpRequestId: objFromPinoHttp.req?.id,
|
60
|
-
|
61
|
-
// Error object (already serialized)
|
62
|
-
err: objFromPinoHttp.err,
|
63
|
-
}
|
64
|
-
|
65
|
-
// Clean up any top-level undefined properties from the explicitly built object
|
66
|
-
Object.keys(finalHttpLog).forEach((key) => {
|
67
|
-
if (finalHttpLog[key] === undefined) {
|
68
|
-
delete (finalHttpLog as any)[key]
|
69
|
-
}
|
70
|
-
})
|
71
|
-
|
72
|
-
// DEBUG: Log what this formatter is about to return
|
73
|
-
// console.log('--- pino-http formatters.log IS RETURNING: ---', JSON.stringify(finalHttpLog, null, 2));
|
74
|
-
|
75
|
-
return finalHttpLog
|
76
|
-
},
|
77
|
-
},
|
78
|
-
|
79
|
-
customSuccessMessage: (req, res) => `${req.method} ${req.url} request_completed`,
|
80
|
-
customErrorMessage: (req, res, err) => `${req.method} ${req.url} request_errored`,
|
81
|
-
})
|
@@ -1,12 +0,0 @@
|
|
1
|
-
import { AsyncLocalStorage } from 'async_hooks'
|
2
|
-
import { FastifyRequest } from 'fastify'
|
3
|
-
|
4
|
-
export interface LogContext {
|
5
|
-
requestId: string
|
6
|
-
userId?: string
|
7
|
-
traceId?: string
|
8
|
-
username?: string
|
9
|
-
additionalContext?: { [key: string]: any } // Additional context data
|
10
|
-
}
|
11
|
-
|
12
|
-
export const requestContext = new AsyncLocalStorage<LogContext>()
|