Skip to content

Commit b2ff274

Browse files
author
Dylan Dietz
committed
refactor: Simplify logging format and remove unused features in EnhancedLogger
1 parent 292b908 commit b2ff274

2 files changed

Lines changed: 20 additions & 123 deletions

File tree

src/logger.ts

Lines changed: 17 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,10 @@ import { NextFunction, Request, Response } from 'express';
66
import { mkdirSync, existsSync } from 'fs';
77
import { join } from 'path';
88

9-
import { LoggerConfig, RequestLogData, QueryLogData, WinstonLogInfo, PrismaClientLike } from './types.js';
9+
import { LoggerConfig, QueryLogData, WinstonLogInfo, PrismaClientLike } from './types.js';
1010
import {
1111
DEFAULT_CONFIG,
1212
createTruncateForLog,
13-
getDurationColor,
14-
getStatusColor,
15-
getLevelColor,
16-
getMethodColor,
17-
formatLogMessage,
18-
removeUndefinedDeep,
19-
LEVEL_EMOJIS,
2013
getQueryType,
2114
formatParams,
2215
} from './utils.js';
@@ -125,74 +118,25 @@ export class EnhancedLogger {
125118
? inspect(message, { colors: this.config.enableColors, depth: 5 })
126119
: String(message);
127120
}
128-
const { level, message, timestamp, ...meta } = info as unknown as WinstonLogInfo;
129-
130-
const levelEmoji = LEVEL_EMOJIS[level as keyof typeof LEVEL_EMOJIS] || '📝';
131-
132-
// Type guard for HTTP request logs
133-
const isHttpLog = (
134-
msg: unknown
135-
): msg is {
136-
method: string;
137-
url: string;
138-
status: number;
139-
statusText: string;
140-
duration: string;
141-
} => {
142-
return typeof msg === 'object' && msg !== null && 'method' in msg && 'url' in msg;
143-
};
144-
145-
// Handle HTTP request logs
146-
if (isHttpLog(message)) {
147-
const { method, url, status, statusText, duration } = message;
148-
const durationColor = getDurationColor(duration, this.config.enableColors);
149-
150-
const coloredMethod = getMethodColor(method, this.config.enableColors);
151-
const statusColor = getStatusColor(status, this.config.enableColors);
152-
153-
return formatLogMessage({
154-
timestamp,
155-
levelEmoji,
156-
coloredMethod,
157-
url,
158-
status,
159-
statusText,
160-
duration,
161-
message: message as {
162-
requestId?: string;
163-
userEmail?: string;
164-
query?: string;
165-
body?: unknown;
166-
},
167-
statusColor,
168-
durationColor,
169-
enableColors: this.config.enableColors,
170-
});
171-
}
121+
const { level, message } = info as unknown as WinstonLogInfo;
122+
172123
// Handle SQL query logs - Winston spreads data directly on info, not in message
173124
if (level === 'query' && 'query' in info && 'type' in info) {
174125
const queryInfo = info as unknown as { type: string; query: string; params?: string; duration: string; timestamp: string };
175126
const { query, params = '', duration } = queryInfo;
176127

177-
// Rails-style query logging
128+
// Rails-style query logging: indented with 2 spaces, duration in parentheses
178129
const formattedQuery = this.formatSqlQuery(query, params);
179130
const paramsArray = params ? JSON.parse(params) : [];
180131
const paramsDisplay = paramsArray.length > 0 ? ` ${JSON.stringify(paramsArray)}` : '';
181132

182-
return ` (${duration}) ${formattedQuery}${paramsDisplay}`;
133+
return ` ${formattedQuery} (${duration})${paramsDisplay}`;
183134
}
184135

185-
// Handle regular logs
186-
const colorFn = getLevelColor(level, this.config.enableColors);
187-
return `${timestamp} ${levelEmoji} ${colorFn(level)}: ${
188-
typeof message === 'object'
189-
? inspect(message, { colors: this.config.enableColors, depth: 5 })
190-
: message
191-
}${
192-
Object.keys(meta).length
193-
? `\n${inspect(meta, { colors: this.config.enableColors, depth: 5 })}`
194-
: ''
195-
}`;
136+
// Handle regular logs - simple Rails style without emojis or fancy formatting
137+
return typeof message === 'object'
138+
? inspect(message, { colors: this.config.enableColors, depth: 5 })
139+
: String(message);
196140
})
197141
);
198142
}
@@ -221,7 +165,6 @@ export class EnhancedLogger {
221165
// Request logging middleware
222166
requestLogger = (req: Request, res: Response, next: NextFunction) => {
223167
const start = performance.now();
224-
const startMemory = process.memoryUsage().heapUsed;
225168

226169
// Rails-style: Log request start
227170
const timestamp = new Date().toLocaleString('en-US', {
@@ -284,9 +227,7 @@ export class EnhancedLogger {
284227
this.info(` Parameters: ${inspect(allParams, { depth: 5, compact: true })}`);
285228
}
286229

287-
// Extract user and request ID using configured functions with null safety
288-
const userResult = this.config.getUserFromRequest ? this.config.getUserFromRequest(req) : undefined;
289-
const userEmail = typeof userResult === 'string' ? userResult : userResult?.email;
230+
// Extract request ID using configured function with null safety
290231
const requestId = this.config.getRequestId ? this.config.getRequestId(req) : undefined;
291232

292233
// Preserve request context with safe property access
@@ -313,62 +254,18 @@ export class EnhancedLogger {
313254
res.off('error', errorHandler);
314255

315256
const duration = performance.now() - start;
316-
const memoryUsed = process.memoryUsage().heapUsed - startMemory;
317257

318-
// Rails-style completion log
319-
const statusText = res.statusMessage || '';
258+
// Rails-style completion log - simple and clean
259+
const statusText = res.statusMessage || 'OK';
320260
const durationMs = Math.round(duration);
321-
this.info(`Completed ${res.statusCode} ${statusText} in ${durationMs}ms`);
322-
const routeParams = req?.params && typeof req.params === 'object' ? req.params : {};
323-
324-
// Truncate large data structures before logging with type guards
325-
const truncatedBody =
326-
req?.body && typeof req.body === 'object' ? this.truncateForLog(req.body) : undefined;
327-
const truncatedQuery =
328-
req?.query && typeof req.query === 'object' ? this.truncateForLog(req.query) : undefined;
329-
const truncatedParams =
330-
Object.keys(routeParams).length > 0 ? this.truncateForLog(routeParams) : undefined;
331-
332-
// Get additional metadata from config with safe function call
333-
const additionalMeta = this.config.additionalMetadata
334-
? this.config.additionalMetadata(req, res)
335-
: {};
336-
337-
const logData: RequestLogData = removeUndefinedDeep({
338-
timestamp: new Date().toISOString(),
339-
requestId,
340-
correlationId: reqContext.correlationId,
341-
method: req?.method || 'UNKNOWN',
342-
url: req?.url || req?.path || '/',
343-
status: res.statusCode || 0,
344-
statusText: res.statusMessage || '',
345-
duration: Math.round(duration),
346-
memoryUsed: Math.round(memoryUsed / 1024 / 1024) + 'MB',
347-
query: truncatedQuery,
348-
params: truncatedParams,
349-
body: truncatedBody,
350-
userEmail,
351-
context: reqContext,
352-
headers: {
353-
contentType: res.get?.('Content-Type'),
354-
contentLength: res.get?.('Content-Length'),
355-
},
356-
...additionalMeta,
357-
}) as RequestLogData;
358-
359-
// Log at different levels based on conditions
261+
262+
// Simple Rails format: Completed 200 OK in 88ms
360263
if (res.statusCode >= 500) {
361-
this.error(logData);
264+
this.error(`Completed ${res.statusCode} ${statusText} in ${durationMs}ms`);
362265
} else if (duration > this.config.slowRequestThreshold) {
363-
const durationColor = getDurationColor(String(duration), this.config.enableColors);
364-
this.warn({
365-
...logData,
366-
message: `Slow request detected - ${durationColor(`${duration}ms`)}`,
367-
});
368-
} else if (memoryUsed > this.config.memoryWarningThreshold) {
369-
this.warn({ ...logData, message: 'High memory usage detected' });
266+
this.warn(`Completed ${res.statusCode} ${statusText} in ${durationMs}ms (Slow request)`);
370267
} else {
371-
this.info(logData);
268+
this.info(`Completed ${res.statusCode} ${statusText} in ${durationMs}ms`);
372269
}
373270
};
374271

tests/unit/loggerCoverage.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ describe('Logger Coverage Tests', () => {
272272
once: jest.fn(),
273273
off: jest.fn(),
274274
get: jest.fn(),
275+
statusMessage: 'OK',
275276
} as unknown as Response;
276277

277278
const mockNext = jest.fn();
@@ -282,9 +283,8 @@ describe('Logger Coverage Tests', () => {
282283
const finishHandler = (mockRes.once as jest.Mock).mock.calls.find(c => c[0] === 'finish')[1];
283284
finishHandler();
284285

285-
expect(warnSpy).toHaveBeenCalledWith(expect.objectContaining({
286-
message: expect.stringContaining('Slow request detected')
287-
}));
286+
// Updated to match new Rails-style output format
287+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Slow request'));
288288

289289
// Restore original performance.now
290290
Object.defineProperty(performance, 'now', {

0 commit comments

Comments
 (0)