create-fluxstack 1.1.0 → 1.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/app/server/backend-only.ts +5 -5
- package/app/server/index.ts +63 -54
- package/app/server/live/FluxStackConfig.ts +43 -39
- package/app/server/live/SystemMonitorIntegration.ts +2 -2
- package/app/server/live/register-components.ts +1 -1
- package/app/server/middleware/errorHandling.ts +6 -4
- package/app/server/routes/config.ts +145 -0
- package/app/server/routes/index.ts +5 -3
- package/config/app.config.ts +113 -0
- package/config/build.config.ts +24 -0
- package/config/database.config.ts +99 -0
- package/config/index.ts +68 -0
- package/config/logger.config.ts +27 -0
- package/config/runtime.config.ts +92 -0
- package/config/server.config.ts +46 -0
- package/config/services.config.ts +130 -0
- package/config/system.config.ts +105 -0
- package/core/build/index.ts +10 -4
- package/core/cli/index.ts +29 -12
- package/core/config/env.ts +37 -95
- package/core/config/runtime-config.ts +61 -58
- package/core/config/schema.ts +4 -0
- package/core/framework/server.ts +22 -10
- package/core/plugins/built-in/index.ts +7 -17
- package/core/plugins/built-in/swagger/index.ts +228 -228
- package/core/plugins/built-in/vite/index.ts +374 -358
- package/core/plugins/dependency-manager.ts +5 -5
- package/core/plugins/manager.ts +12 -12
- package/core/plugins/registry.ts +3 -3
- package/core/server/index.ts +0 -1
- package/core/server/live/ComponentRegistry.ts +34 -8
- package/core/server/live/LiveComponentPerformanceMonitor.ts +1 -1
- package/core/server/live/websocket-plugin.ts +434 -434
- package/core/server/middleware/README.md +488 -0
- package/core/server/middleware/elysia-helpers.ts +227 -0
- package/core/server/middleware/index.ts +25 -9
- package/core/server/plugins/static-files-plugin.ts +231 -231
- package/core/utils/config-schema.ts +484 -0
- package/core/utils/env.ts +306 -0
- package/core/utils/helpers.ts +4 -4
- package/core/utils/logger/colors.ts +114 -0
- package/core/utils/logger/config.ts +35 -0
- package/core/utils/logger/formatter.ts +82 -0
- package/core/utils/logger/group-logger.ts +101 -0
- package/core/utils/logger/index.ts +199 -250
- package/core/utils/logger/stack-trace.ts +92 -0
- package/core/utils/logger/startup-banner.ts +92 -0
- package/core/utils/logger/winston-logger.ts +152 -0
- package/core/utils/version.ts +5 -0
- package/create-fluxstack.ts +1 -0
- package/fluxstack.config.ts +2 -2
- package/package.json +117 -115
- package/core/config/env-dynamic.ts +0 -326
- package/core/plugins/built-in/logger/index.ts +0 -180
- package/core/server/plugins/logger.ts +0 -47
- package/core/utils/env-runtime-v2.ts +0 -232
- package/core/utils/env-runtime.ts +0 -259
- package/core/utils/logger/formatters.ts +0 -222
- package/core/utils/logger/middleware.ts +0 -253
- package/core/utils/logger/performance.ts +0 -384
- package/core/utils/logger/transports.ts +0 -365
- package/core/utils/logger.ts +0 -106
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FluxStack Logger Middleware Integration
|
|
3
|
-
* Easy integration with Elysia and other frameworks
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { Logger } from './index'
|
|
7
|
-
import { RequestLogger, PerformanceLogger } from './performance'
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Enhanced logger middleware for Elysia
|
|
11
|
-
*/
|
|
12
|
-
export function createElysiaLoggerMiddleware(logger: Logger) {
|
|
13
|
-
const requestLogger = new RequestLogger(logger)
|
|
14
|
-
const performanceLogger = new PerformanceLogger(logger)
|
|
15
|
-
|
|
16
|
-
return {
|
|
17
|
-
// Before request handler
|
|
18
|
-
beforeHandle: ({ request, set }: any) => {
|
|
19
|
-
const method = request.method
|
|
20
|
-
const url = new URL(request.url)
|
|
21
|
-
const path = url.pathname
|
|
22
|
-
const userAgent = request.headers.get('user-agent')
|
|
23
|
-
const ip = request.headers.get('x-forwarded-for') ||
|
|
24
|
-
request.headers.get('x-real-ip') ||
|
|
25
|
-
'unknown'
|
|
26
|
-
|
|
27
|
-
// Start request tracking
|
|
28
|
-
const requestId = requestLogger.startRequest(method, path, {
|
|
29
|
-
userAgent,
|
|
30
|
-
ip,
|
|
31
|
-
query: Object.fromEntries(url.searchParams),
|
|
32
|
-
headers: Object.fromEntries(request.headers.entries())
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
// Add request context to set for access in handlers
|
|
36
|
-
set.requestId = requestId
|
|
37
|
-
set.logger = requestLogger.childLogger(requestId)
|
|
38
|
-
set.performance = performanceLogger
|
|
39
|
-
|
|
40
|
-
// Start overall request timer
|
|
41
|
-
performanceLogger.startTimer(`request:${requestId}`, {
|
|
42
|
-
method,
|
|
43
|
-
path
|
|
44
|
-
})
|
|
45
|
-
},
|
|
46
|
-
|
|
47
|
-
// After request handler
|
|
48
|
-
afterHandle: ({ request, response, set }: any) => {
|
|
49
|
-
if (set.requestId) {
|
|
50
|
-
const status = response?.status || 200
|
|
51
|
-
|
|
52
|
-
// End request tracking
|
|
53
|
-
requestLogger.endRequest(set.requestId, status, {
|
|
54
|
-
responseSize: response?.headers?.get('content-length'),
|
|
55
|
-
contentType: response?.headers?.get('content-type')
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
// End request timer
|
|
59
|
-
performanceLogger.endTimer(`request:${set.requestId}`)
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
|
|
63
|
-
// Error handler
|
|
64
|
-
onError: ({ request, error, set }: any) => {
|
|
65
|
-
if (set.requestId) {
|
|
66
|
-
requestLogger.errorRequest(set.requestId, error)
|
|
67
|
-
performanceLogger.endTimer(`request:${set.requestId}`)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Log the error with context
|
|
71
|
-
logger.error('Request error', {
|
|
72
|
-
error: {
|
|
73
|
-
name: error.name,
|
|
74
|
-
message: error.message,
|
|
75
|
-
stack: error.stack
|
|
76
|
-
},
|
|
77
|
-
request: {
|
|
78
|
-
method: request.method,
|
|
79
|
-
url: request.url
|
|
80
|
-
}
|
|
81
|
-
})
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Database query logging middleware
|
|
88
|
-
*/
|
|
89
|
-
export function createDatabaseLoggerMiddleware(logger: Logger) {
|
|
90
|
-
const performanceLogger = new PerformanceLogger(logger)
|
|
91
|
-
|
|
92
|
-
return {
|
|
93
|
-
beforeQuery: (query: string, params?: any[]) => {
|
|
94
|
-
const queryId = `query:${Date.now()}:${Math.random().toString(36).substr(2, 9)}`
|
|
95
|
-
|
|
96
|
-
logger.debug('Executing database query', {
|
|
97
|
-
type: 'db_query_start',
|
|
98
|
-
queryId,
|
|
99
|
-
query: query.replace(/\s+/g, ' ').trim(),
|
|
100
|
-
params
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
performanceLogger.startTimer(queryId, {
|
|
104
|
-
query: query.substring(0, 100) + (query.length > 100 ? '...' : ''),
|
|
105
|
-
paramCount: params?.length || 0
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
return queryId
|
|
109
|
-
},
|
|
110
|
-
|
|
111
|
-
afterQuery: (queryId: string, result?: any) => {
|
|
112
|
-
const duration = performanceLogger.endTimer(queryId)
|
|
113
|
-
|
|
114
|
-
logger.debug('Database query completed', {
|
|
115
|
-
type: 'db_query_end',
|
|
116
|
-
queryId,
|
|
117
|
-
duration,
|
|
118
|
-
rowCount: result?.rowCount || result?.length || 0
|
|
119
|
-
})
|
|
120
|
-
},
|
|
121
|
-
|
|
122
|
-
onQueryError: (queryId: string, error: Error) => {
|
|
123
|
-
performanceLogger.endTimer(queryId)
|
|
124
|
-
|
|
125
|
-
logger.error('Database query failed', {
|
|
126
|
-
type: 'db_query_error',
|
|
127
|
-
queryId,
|
|
128
|
-
error: {
|
|
129
|
-
name: error.name,
|
|
130
|
-
message: error.message,
|
|
131
|
-
stack: error.stack
|
|
132
|
-
}
|
|
133
|
-
})
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Plugin execution logging
|
|
140
|
-
*/
|
|
141
|
-
export function createPluginLoggerMiddleware(logger: Logger) {
|
|
142
|
-
const performanceLogger = new PerformanceLogger(logger)
|
|
143
|
-
|
|
144
|
-
return {
|
|
145
|
-
beforePluginExecution: (pluginName: string, hook: string, context?: any) => {
|
|
146
|
-
const executionId = `plugin:${pluginName}:${hook}:${Date.now()}`
|
|
147
|
-
|
|
148
|
-
logger.debug(`Executing plugin hook: ${pluginName}.${hook}`, {
|
|
149
|
-
type: 'plugin_execution_start',
|
|
150
|
-
plugin: pluginName,
|
|
151
|
-
hook,
|
|
152
|
-
executionId,
|
|
153
|
-
context
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
performanceLogger.startTimer(executionId, {
|
|
157
|
-
plugin: pluginName,
|
|
158
|
-
hook
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
return executionId
|
|
162
|
-
},
|
|
163
|
-
|
|
164
|
-
afterPluginExecution: (executionId: string, result?: any) => {
|
|
165
|
-
const duration = performanceLogger.endTimer(executionId)
|
|
166
|
-
|
|
167
|
-
logger.debug('Plugin hook execution completed', {
|
|
168
|
-
type: 'plugin_execution_end',
|
|
169
|
-
executionId,
|
|
170
|
-
duration,
|
|
171
|
-
success: true
|
|
172
|
-
})
|
|
173
|
-
},
|
|
174
|
-
|
|
175
|
-
onPluginError: (executionId: string, pluginName: string, hook: string, error: Error) => {
|
|
176
|
-
performanceLogger.endTimer(executionId)
|
|
177
|
-
|
|
178
|
-
logger.error(`Plugin hook execution failed: ${pluginName}.${hook}`, {
|
|
179
|
-
type: 'plugin_execution_error',
|
|
180
|
-
plugin: pluginName,
|
|
181
|
-
hook,
|
|
182
|
-
executionId,
|
|
183
|
-
error: {
|
|
184
|
-
name: error.name,
|
|
185
|
-
message: error.message,
|
|
186
|
-
stack: error.stack
|
|
187
|
-
}
|
|
188
|
-
})
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Build process logging
|
|
195
|
-
*/
|
|
196
|
-
export function createBuildLoggerMiddleware(logger: Logger) {
|
|
197
|
-
const performanceLogger = new PerformanceLogger(logger)
|
|
198
|
-
|
|
199
|
-
return {
|
|
200
|
-
beforeBuild: (target: string, config?: any) => {
|
|
201
|
-
const buildId = `build:${target}:${Date.now()}`
|
|
202
|
-
|
|
203
|
-
logger.info(`Starting build process for ${target}`, {
|
|
204
|
-
type: 'build_start',
|
|
205
|
-
target,
|
|
206
|
-
buildId,
|
|
207
|
-
config
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
performanceLogger.startTimer(buildId, { target })
|
|
211
|
-
performanceLogger.logMemoryUsage(`build-start-${target}`)
|
|
212
|
-
|
|
213
|
-
return buildId
|
|
214
|
-
},
|
|
215
|
-
|
|
216
|
-
afterBuild: (buildId: string, result: any) => {
|
|
217
|
-
const duration = performanceLogger.endTimer(buildId)
|
|
218
|
-
performanceLogger.logMemoryUsage(`build-end`)
|
|
219
|
-
|
|
220
|
-
logger.info('Build process completed', {
|
|
221
|
-
type: 'build_end',
|
|
222
|
-
buildId,
|
|
223
|
-
duration,
|
|
224
|
-
success: true,
|
|
225
|
-
result
|
|
226
|
-
})
|
|
227
|
-
},
|
|
228
|
-
|
|
229
|
-
onBuildError: (buildId: string, error: Error) => {
|
|
230
|
-
performanceLogger.endTimer(buildId)
|
|
231
|
-
performanceLogger.logMemoryUsage(`build-error`)
|
|
232
|
-
|
|
233
|
-
logger.error('Build process failed', {
|
|
234
|
-
type: 'build_error',
|
|
235
|
-
buildId,
|
|
236
|
-
error: {
|
|
237
|
-
name: error.name,
|
|
238
|
-
message: error.message,
|
|
239
|
-
stack: error.stack
|
|
240
|
-
}
|
|
241
|
-
})
|
|
242
|
-
},
|
|
243
|
-
|
|
244
|
-
logBuildStep: (buildId: string, step: string, details?: any) => {
|
|
245
|
-
logger.info(`Build step: ${step}`, {
|
|
246
|
-
type: 'build_step',
|
|
247
|
-
buildId,
|
|
248
|
-
step,
|
|
249
|
-
details
|
|
250
|
-
})
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
@@ -1,384 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FluxStack Performance and Request Logging
|
|
3
|
-
* Utilities for measuring and logging performance metrics
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { randomUUID } from 'crypto'
|
|
7
|
-
import type { Logger } from './index'
|
|
8
|
-
|
|
9
|
-
export interface RequestContext {
|
|
10
|
-
id: string
|
|
11
|
-
method: string
|
|
12
|
-
path: string
|
|
13
|
-
userAgent?: string
|
|
14
|
-
ip?: string
|
|
15
|
-
startTime: number
|
|
16
|
-
endTime?: number
|
|
17
|
-
duration?: number
|
|
18
|
-
status?: number
|
|
19
|
-
error?: Error
|
|
20
|
-
meta?: any
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface PerformanceTimer {
|
|
24
|
-
label: string
|
|
25
|
-
startTime: number
|
|
26
|
-
endTime?: number
|
|
27
|
-
duration?: number
|
|
28
|
-
meta?: any
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Request correlation and contextual logging
|
|
33
|
-
*/
|
|
34
|
-
export class RequestLogger {
|
|
35
|
-
private logger: Logger
|
|
36
|
-
private activeRequests: Map<string, RequestContext> = new Map()
|
|
37
|
-
|
|
38
|
-
constructor(logger: Logger) {
|
|
39
|
-
this.logger = logger
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Start tracking a request
|
|
44
|
-
*/
|
|
45
|
-
startRequest(method: string, path: string, meta?: any): string {
|
|
46
|
-
const id = randomUUID()
|
|
47
|
-
const context: RequestContext = {
|
|
48
|
-
id,
|
|
49
|
-
method,
|
|
50
|
-
path,
|
|
51
|
-
startTime: Date.now(),
|
|
52
|
-
meta
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
this.activeRequests.set(id, context)
|
|
56
|
-
|
|
57
|
-
// Log request start
|
|
58
|
-
this.logger.child({ requestId: id }).info(`→ ${method} ${path}`, {
|
|
59
|
-
type: 'request_start',
|
|
60
|
-
method,
|
|
61
|
-
path,
|
|
62
|
-
...meta
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
return id
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* End tracking a request
|
|
70
|
-
*/
|
|
71
|
-
endRequest(id: string, status: number, meta?: any): void {
|
|
72
|
-
const context = this.activeRequests.get(id)
|
|
73
|
-
if (!context) return
|
|
74
|
-
|
|
75
|
-
const endTime = Date.now()
|
|
76
|
-
const duration = endTime - context.startTime
|
|
77
|
-
|
|
78
|
-
context.endTime = endTime
|
|
79
|
-
context.duration = duration
|
|
80
|
-
context.status = status
|
|
81
|
-
|
|
82
|
-
// Determine log level based on status and duration
|
|
83
|
-
const logLevel = this.getRequestLogLevel(status, duration)
|
|
84
|
-
const statusEmoji = this.getStatusEmoji(status)
|
|
85
|
-
|
|
86
|
-
// Log request completion
|
|
87
|
-
this.logger.child({ requestId: id })[logLevel](
|
|
88
|
-
`← ${context.method} ${context.path} ${statusEmoji} ${status} (${duration}ms)`,
|
|
89
|
-
{
|
|
90
|
-
type: 'request_end',
|
|
91
|
-
method: context.method,
|
|
92
|
-
path: context.path,
|
|
93
|
-
status,
|
|
94
|
-
duration,
|
|
95
|
-
...context.meta,
|
|
96
|
-
...meta
|
|
97
|
-
}
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
// Clean up
|
|
101
|
-
this.activeRequests.delete(id)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Log request error
|
|
106
|
-
*/
|
|
107
|
-
errorRequest(id: string, error: Error, status?: number): void {
|
|
108
|
-
const context = this.activeRequests.get(id)
|
|
109
|
-
if (!context) return
|
|
110
|
-
|
|
111
|
-
const endTime = Date.now()
|
|
112
|
-
const duration = endTime - context.startTime
|
|
113
|
-
const finalStatus = status || 500
|
|
114
|
-
|
|
115
|
-
context.endTime = endTime
|
|
116
|
-
context.duration = duration
|
|
117
|
-
context.status = finalStatus
|
|
118
|
-
context.error = error
|
|
119
|
-
|
|
120
|
-
// Log request error
|
|
121
|
-
this.logger.child({ requestId: id }).error(
|
|
122
|
-
`✗ ${context.method} ${context.path} ${finalStatus} (${duration}ms)`,
|
|
123
|
-
{
|
|
124
|
-
type: 'request_error',
|
|
125
|
-
method: context.method,
|
|
126
|
-
path: context.path,
|
|
127
|
-
status: finalStatus,
|
|
128
|
-
duration,
|
|
129
|
-
error: {
|
|
130
|
-
name: error.name,
|
|
131
|
-
message: error.message,
|
|
132
|
-
stack: error.stack
|
|
133
|
-
},
|
|
134
|
-
...context.meta
|
|
135
|
-
}
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
// Clean up
|
|
139
|
-
this.activeRequests.delete(id)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Get request context for correlation
|
|
144
|
-
*/
|
|
145
|
-
getRequestContext(id: string): RequestContext | undefined {
|
|
146
|
-
return this.activeRequests.get(id)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Create child logger with request context
|
|
151
|
-
*/
|
|
152
|
-
childLogger(id: string, additionalContext?: any): Logger {
|
|
153
|
-
const context = this.activeRequests.get(id)
|
|
154
|
-
if (!context) {
|
|
155
|
-
return this.logger.child({ requestId: id, ...additionalContext })
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return this.logger.child({
|
|
159
|
-
requestId: id,
|
|
160
|
-
method: context.method,
|
|
161
|
-
path: context.path,
|
|
162
|
-
...additionalContext
|
|
163
|
-
})
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
private getRequestLogLevel(status: number, duration: number): 'info' | 'warn' | 'error' {
|
|
167
|
-
if (status >= 500) return 'error'
|
|
168
|
-
if (status >= 400) return 'warn'
|
|
169
|
-
if (duration > 5000) return 'warn' // Slow requests
|
|
170
|
-
return 'info'
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
private getStatusEmoji(status: number): string {
|
|
174
|
-
if (status >= 500) return '💥'
|
|
175
|
-
if (status >= 400) return '⚠️'
|
|
176
|
-
if (status >= 300) return '↩️'
|
|
177
|
-
if (status >= 200) return '✅'
|
|
178
|
-
return '❓'
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Performance timing utilities
|
|
184
|
-
*/
|
|
185
|
-
export class PerformanceLogger {
|
|
186
|
-
private logger: Logger
|
|
187
|
-
private timers: Map<string, PerformanceTimer> = new Map()
|
|
188
|
-
|
|
189
|
-
constructor(logger: Logger) {
|
|
190
|
-
this.logger = logger
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Start a performance timer
|
|
195
|
-
*/
|
|
196
|
-
startTimer(label: string, meta?: any): void {
|
|
197
|
-
const timer: PerformanceTimer = {
|
|
198
|
-
label,
|
|
199
|
-
startTime: performance.now(),
|
|
200
|
-
meta
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
this.timers.set(label, timer)
|
|
204
|
-
|
|
205
|
-
this.logger.debug(`⏱️ Started timer: ${label}`, {
|
|
206
|
-
type: 'timer_start',
|
|
207
|
-
label,
|
|
208
|
-
...meta
|
|
209
|
-
})
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* End a performance timer
|
|
214
|
-
*/
|
|
215
|
-
endTimer(label: string, meta?: any): number | undefined {
|
|
216
|
-
const timer = this.timers.get(label)
|
|
217
|
-
if (!timer) {
|
|
218
|
-
this.logger.warn(`Timer not found: ${label}`)
|
|
219
|
-
return undefined
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const endTime = performance.now()
|
|
223
|
-
const duration = endTime - timer.startTime
|
|
224
|
-
|
|
225
|
-
timer.endTime = endTime
|
|
226
|
-
timer.duration = duration
|
|
227
|
-
|
|
228
|
-
// Determine log level based on duration
|
|
229
|
-
const logLevel = this.getTimerLogLevel(duration)
|
|
230
|
-
const durationEmoji = this.getDurationEmoji(duration)
|
|
231
|
-
|
|
232
|
-
this.logger[logLevel](`${durationEmoji} Timer ${label}: ${duration.toFixed(2)}ms`, {
|
|
233
|
-
type: 'timer_end',
|
|
234
|
-
label,
|
|
235
|
-
duration,
|
|
236
|
-
...timer.meta,
|
|
237
|
-
...meta
|
|
238
|
-
})
|
|
239
|
-
|
|
240
|
-
// Clean up
|
|
241
|
-
this.timers.delete(label)
|
|
242
|
-
|
|
243
|
-
return duration
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Measure execution time of a function
|
|
248
|
-
*/
|
|
249
|
-
async measure<T>(label: string, fn: () => Promise<T>, meta?: any): Promise<T> {
|
|
250
|
-
this.startTimer(label, meta)
|
|
251
|
-
try {
|
|
252
|
-
const result = await fn()
|
|
253
|
-
this.endTimer(label, { success: true })
|
|
254
|
-
return result
|
|
255
|
-
} catch (error) {
|
|
256
|
-
this.endTimer(label, { success: false, error: error.message })
|
|
257
|
-
throw error
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* Measure execution time of a synchronous function
|
|
263
|
-
*/
|
|
264
|
-
measureSync<T>(label: string, fn: () => T, meta?: any): T {
|
|
265
|
-
this.startTimer(label, meta)
|
|
266
|
-
try {
|
|
267
|
-
const result = fn()
|
|
268
|
-
this.endTimer(label, { success: true })
|
|
269
|
-
return result
|
|
270
|
-
} catch (error) {
|
|
271
|
-
this.endTimer(label, { success: false, error: error.message })
|
|
272
|
-
throw error
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Log memory usage
|
|
278
|
-
*/
|
|
279
|
-
logMemoryUsage(label?: string): void {
|
|
280
|
-
const memUsage = process.memoryUsage()
|
|
281
|
-
const formatBytes = (bytes: number) => (bytes / 1024 / 1024).toFixed(2) + ' MB'
|
|
282
|
-
|
|
283
|
-
this.logger.info(`📊 Memory usage${label ? ` (${label})` : ''}`, {
|
|
284
|
-
type: 'memory_usage',
|
|
285
|
-
label,
|
|
286
|
-
memory: {
|
|
287
|
-
rss: formatBytes(memUsage.rss),
|
|
288
|
-
heapTotal: formatBytes(memUsage.heapTotal),
|
|
289
|
-
heapUsed: formatBytes(memUsage.heapUsed),
|
|
290
|
-
external: formatBytes(memUsage.external)
|
|
291
|
-
},
|
|
292
|
-
raw: memUsage
|
|
293
|
-
})
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Log system performance metrics
|
|
298
|
-
*/
|
|
299
|
-
logSystemMetrics(label?: string): void {
|
|
300
|
-
const cpuUsage = process.cpuUsage()
|
|
301
|
-
const uptime = process.uptime()
|
|
302
|
-
|
|
303
|
-
this.logger.info(`⚡ System metrics${label ? ` (${label})` : ''}`, {
|
|
304
|
-
type: 'system_metrics',
|
|
305
|
-
label,
|
|
306
|
-
cpu: {
|
|
307
|
-
user: cpuUsage.user,
|
|
308
|
-
system: cpuUsage.system
|
|
309
|
-
},
|
|
310
|
-
uptime: {
|
|
311
|
-
seconds: uptime,
|
|
312
|
-
formatted: this.formatUptime(uptime)
|
|
313
|
-
}
|
|
314
|
-
})
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
private getTimerLogLevel(duration: number): 'debug' | 'info' | 'warn' {
|
|
318
|
-
if (duration > 1000) return 'warn' // > 1 second
|
|
319
|
-
if (duration > 100) return 'info' // > 100ms
|
|
320
|
-
return 'debug'
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
private getDurationEmoji(duration: number): string {
|
|
324
|
-
if (duration > 5000) return '🐌' // Very slow
|
|
325
|
-
if (duration > 1000) return '⏳' // Slow
|
|
326
|
-
if (duration > 100) return '⏱️' // Medium
|
|
327
|
-
return '⚡' // Fast
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
private formatUptime(seconds: number): string {
|
|
331
|
-
const days = Math.floor(seconds / 86400)
|
|
332
|
-
const hours = Math.floor((seconds % 86400) / 3600)
|
|
333
|
-
const minutes = Math.floor((seconds % 3600) / 60)
|
|
334
|
-
const secs = Math.floor(seconds % 60)
|
|
335
|
-
|
|
336
|
-
if (days > 0) return `${days}d ${hours}h ${minutes}m ${secs}s`
|
|
337
|
-
if (hours > 0) return `${hours}h ${minutes}m ${secs}s`
|
|
338
|
-
if (minutes > 0) return `${minutes}m ${secs}s`
|
|
339
|
-
return `${secs}s`
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Middleware for automatic request logging
|
|
345
|
-
*/
|
|
346
|
-
export function createRequestLoggingMiddleware(logger: Logger) {
|
|
347
|
-
const requestLogger = new RequestLogger(logger)
|
|
348
|
-
|
|
349
|
-
return {
|
|
350
|
-
onRequest: (request: any) => {
|
|
351
|
-
const method = request.method
|
|
352
|
-
const path = request.url || request.path
|
|
353
|
-
const userAgent = request.headers?.['user-agent']
|
|
354
|
-
const ip = request.headers?.['x-forwarded-for'] || request.ip
|
|
355
|
-
|
|
356
|
-
const requestId = requestLogger.startRequest(method, path, {
|
|
357
|
-
userAgent,
|
|
358
|
-
ip,
|
|
359
|
-
headers: request.headers
|
|
360
|
-
})
|
|
361
|
-
|
|
362
|
-
// Attach request ID to request for correlation
|
|
363
|
-
request.requestId = requestId
|
|
364
|
-
request.logger = requestLogger.childLogger(requestId)
|
|
365
|
-
|
|
366
|
-
return requestId
|
|
367
|
-
},
|
|
368
|
-
|
|
369
|
-
onResponse: (request: any, response: any) => {
|
|
370
|
-
if (request.requestId) {
|
|
371
|
-
const status = response.status || response.statusCode || 200
|
|
372
|
-
requestLogger.endRequest(request.requestId, status, {
|
|
373
|
-
responseHeaders: response.headers
|
|
374
|
-
})
|
|
375
|
-
}
|
|
376
|
-
},
|
|
377
|
-
|
|
378
|
-
onError: (request: any, error: Error) => {
|
|
379
|
-
if (request.requestId) {
|
|
380
|
-
requestLogger.errorRequest(request.requestId, error)
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
}
|