引言:为什么要在 TypeScript 中使用日志?
日志记录不仅仅是向控制台写入消息。在现代TypeScript应用(基于Node.js的服务端、基于React/Angular的客户端或全栈项目)中,日志已成为调试、监控和性能分析的关键工具。没有高质量的日志,开发者会花费数小时重现错误,DevOps工程师也无法快速定位生产环境故障的原因。
TypeScript作为JavaScript的超集,增加了严格的类型系统,这使得创建更可靠、可预测的日志系统成为可能。本文将涵盖帮助您在TypeScript项目中组织高效日志记录的最佳实践。
日志记录的基本原则
日志级别
正确使用日志级别是所有监控系统的基础。在TypeScript中,通常使用以下级别(按重要性递增排序):
debug— 详细的调试信息(仅限开发环境);info— 标准信息性消息(服务器启动、请求);warn— 警告(非关键问题);error— 需要关注的错误;fatal— 导致应用程序崩溃的严重错误。
使用Winston库配置级别的示例:
import winston from 'winston';
const logger = winston.createLogger({ level: process.env.NODE_ENV === 'production' ? 'info' : 'debug', format: winston.format.json(), transports: [ new winston.transports.Console(), new winston.transports.File({ filename: 'error.log', level: 'error' }), ],});
logger.info('Server started on port 3000');logger.warn('Memory is near the limit');logger.error('Database connection error');结构化日志
避免使用简单的字符串消息。请使用包含上下文信息的结构化日志(JSON格式)。这能简化在ELK或Grafana等系统中的搜索和分析。
// 不好的做法logger.info(`User ${userId} performed action ${action}`);
// 好的做法logger.info('User action', { userId: userId, action: action, timestamp: new Date().toISOString(), ip: request.ip,});这种方法允许您按字段过滤日志并构建图表。
TypeScript的最佳实践
使用TypeScript进行日志类型定义
TypeScript允许您为日志上下文定义接口,从而防止字段名称的意外错误:
interface LogContext { userId: string; action: string; durationMs: number; success: boolean;}
function logUserAction(context: LogContext): void { logger.info('User action', context);}
// 编译器会验证是否所有字段都正确传递logUserAction({ userId: '123', action: 'login', durationMs: 150, success: true,});避免记录敏感数据
切勿记录密码、令牌、信用卡号或个人数据(遵守GDPR)。使用遮蔽工具函数:
function sanitizeLogData(data: Record<string, unknown>): Record<string, unknown> { const sensitiveFields = ['password', 'token', 'ssn']; const sanitized = { ...data }; for (const field of sensitiveFields) { if (sanitized[field]) { sanitized[field] = '***'; } } return sanitized;}
logger.info('User registration', sanitizeLogData(userData));异步日志记录与性能
在高负载应用中,同步日志记录可能会降低性能。请使用异步传输(例如,winston支持缓冲功能)。