7-2 通用模板项目:全局日志模块
1. 日志模块创建与依赖安装
1.1 创建日志模块
使用Nest CLI创建日志模块:
nest gmo config/common/logs --no-spec
bash
扩展说明:
- 模块位置规划:
- 将日志模块放在
config/common
目录下,表明这是一个通用功能模块 - 推荐项目结构:
src/ config/ common/ logs/ logs.module.ts create-rotate-transport.ts
text
- 将日志模块放在
- CLI参数详解:
gmo
:generate module的缩写--no-spec
:不生成测试文件(适合工具类模块)- 其他有用参数:
nest gmo path/to/module --flat # 不创建子目录 nest gmo shared/core --dry-run # 模拟执行
bash
- 模块初始化验证:
- 创建完成后检查:
logs.module.ts
是否生成app.module.ts
是否自动导入新模块- 运行
nest info
确认模块注册成功
- 创建完成后检查:
💡 对于大型项目,建议使用--project
参数指定子项目:
nest gmo logs --project admin-api --no-spec
bash
1.2 安装依赖包
安装必要依赖:
pnpm install winston nest-winston winston-daily-rotate-file
bash
版本选择策略:
包名 | 版本 | 选择依据 |
---|---|---|
winston | 3.13.0 | LTS版本,API稳定,兼容Node.js 12+ |
nest-winston | 1.9.4 | 与NestJS 8+兼容,支持异步配置 |
winston-daily-rotate-file | 5.0.0 | 支持ESM模块,修复时区问题 |
深度技术解析:
- Winston核心功能:
// 基础日志示例 import { createLogger, format, transports } from 'winston'; const logger = createLogger({ level: 'info', format: format.json(), transports: [new transports.Console()] });
typescript - Nest-Winston集成原理:
- 通过
WinstonModule
将logger实例注入NestJS依赖系统 - 重写了NestJS默认的
LoggerService
- 通过
- 日志轮转关键配置:
// winston-daily-rotate-file高级配置 new DailyRotateFile({ frequency: '24h', // 每天轮转 auditFile: 'logs/audit.json', // 审计日志 utc: true // 使用UTC时间 })
javascript
常见安装问题解决:
问题现象 | 解决方案 |
---|---|
版本冲突 | 使用pnpm override 强制版本:"winston": "3.13.0" |
ESM模块报错 | 在package.json中添加:"type": "module" |
类型声明缺失 | 安装@types/winston 和@types/winston-daily-rotate-file |
最佳实践建议:
- 版本锁定:
pnpm add winston@3.13.0 nest-winston@1.9.4 winston-daily-rotate-file@5.0.0 -E
bash - 多环境配置:
# 开发环境安装 pnpm add winston-daily-rotate-file -D # 生产环境安装 pnpm add winston-daily-rotate-file -P
bash - 安全审计:
pnpm audit pnpm outdated
bash
💡 使用winston-transport
可以扩展更多日志输出方式(如Elasticsearch、Slack等):
pnpm add winston-elasticsearch winston-slack-webhook-transport
bash
性能对比数据:
日志方案 | 10万条日志耗时 | 内存占用 |
---|---|---|
纯Console | 1.2s | 50MB |
Winston(文件) | 3.8s | 120MB |
Winston+轮转 | 4.5s | 150MB |
Winston+压缩轮转 | 6.1s | 180MB |
建议开发环境使用Console传输器,生产环境启用轮转压缩。
2. 异步模块加载机制
2.1 forRootAsync 异步加载(深度扩展)
核心代码解析:
@Module({
imports: [
WinstonModule.forRootAsync({
imports: [ConfigModule], // 显式声明依赖模块
useFactory: async (config: ConfigService) => ({
// 动态配置对象
level: config.get('LOG_LEVEL', 'debug'),
transports: [
new transports.Console({
format: format.combine(
format.colorize(),
format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
format.printf(info =>
`${info.timestamp} [${info.level}] ${info.message}`
)
)
})
]
}),
inject: [ConfigService], // 注入的服务Token
extraProviders: [ // 额外提供者
{ provide: 'LOG_OPTIONS', useValue: { maxFiles: 30 } }
]
})
]
})
export class LogsModule {}
typescript
关键点说明:
- 异步工厂函数:
- 支持
async/await
语法 - 可以访问异步配置源(如数据库、远程配置中心)
- 支持
- 多级注入:
- 配置继承:
useFactory: (config) => ({ ...WinstonModule.createLogger(config.get('baseOptions')), transports: [/* 自定义传输器 */] })
typescript
2.2 依赖注入原理(增强版)
依赖解析流程:
高级用法:
- 多服务注入:
inject: [ConfigService, DatabaseService] useFactory: (config, db) => ({ dbLogger: db.createLogger() })
typescript - 条件加载:
imports: [ config.isProd ? WinstonModule.forRootAsync({/* 生产配置 */}) : WinstonModule.forRoot({/* 开发配置 */}) ]
typescript
2.3 环境变量控制(生产级实践)
完整环境配置方案:
useFactory: (config: ConfigService) => {
const isProduction = config.get('NODE_ENV') === 'production';
return {
level: isProduction ? 'warn' : 'debug',
silent: config.get('LOG_SILENT', false),
format: isProduction ?
format.json() :
format.combine(format.colorize(), format.simple()),
transports: [
isProduction &&
new DailyRotateFile(/* 生产日志配置 */),
new transports.Console()
].filter(Boolean)
};
}
typescript
环境变量规范:
变量名 | 类型 | 默认值 | 说明 |
---|---|---|---|
LOG_ON | boolean | true | 总开关 |
LOG_LEVEL | string | info | debug/info/warn/error |
LOG_SILENT | boolean | false | 是否静默模式 |
LOG_MAX_FILES | number | 30 | 最大保留日志文件数 |
LOG_ROTATE_ZIP | boolean | true | 是否压缩旧日志 |
最佳实践:
- 多环境配置:
# .env.development LOG_LEVEL=debug LOG_SILENT=false # .env.production LOG_LEVEL=warn LOG_ROTATE_ZIP=true
dotenv - 配置验证:
import * as Joi from 'joi'; @Module({ imports: [ ConfigModule.forRoot({ validationSchema: Joi.object({ LOG_LEVEL: Joi.string() .valid('error', 'warn', 'info', 'debug', 'verbose') .default('info'), LOG_ON: Joi.boolean().default(true) }) }) ] })
typescript - 动态重载:
// 热更新配置 const logger = app.get(WINSTON_MODULE_NEST_PROVIDER); logger.close().then(() => { logger.configure(/* 新配置 */); });
typescript
💡 在Kubernetes环境中,建议通过ConfigMap管理日志配置,实现动态调整无需重启服务。
3. 日志传输器配置(深度扩展)
3.1 创建日志轮转函数(增强版)
完整实现方案:
// create-rotate-transport.ts
import { format, transports } from 'winston';
import DailyRotateFile from 'winston-daily-rotate-file';
import * as path from 'path';
interface RotateTransportOptions {
level: string;
dirname: string;
filename?: string;
auditFile?: string;
utc?: boolean;
}
export default function createDailyRotateTransport(
options: RotateTransportOptions
) {
const {
level,
dirname,
filename = `${path.basename(dirname)}-%DATE%.log`,
auditFile = path.join(dirname, 'audit.json'),
utc = false
} = options;
return new DailyRotateFile({
level,
dirname: path.normalize(`logs/${dirname}`),
filename,
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '20m',
maxFiles: '14d',
utc, // 是否使用UTC时间
auditFile, // 审计日志路径
format: format.combine(
format.timestamp({
format: 'YYYY-MM-DD HH:mm:ss.SSS'
}),
format.errors({ stack: true }), // 记录错误堆栈
format.ms(),
format.splat(), // 支持占位符替换
format.printf(info => {
const stack = info.stack ? `\n${info.stack}` : '';
return `${info.timestamp} [${info.level}] ${info.message}${stack}`;
})
),
extension: '.log', // 文件扩展名
createSymlink: true, // 创建当前日志的符号链接
symlinkName: 'current.log'
});
}
typescript
关键增强功能:
- 类型安全接口:使用TypeScript接口规范参数
- 路径规范化:通过
path
模块处理跨平台路径 - 错误堆栈记录:自动捕获错误调用栈
- 审计日志:记录日志轮转操作
- 符号链接:快速访问最新日志文件
3.2 参数配置说明(完整版)
参数 | 类型 | 默认值 | 说明 |
---|---|---|---|
level | string | - | 日志级别:error/warn/info/debug/verbose |
dirname | string | - | 日志目录路径(自动添加logs前缀) |
filename | string | [dirname]-%DATE% | 文件名模板,支持日期占位符 |
datePattern | string | YYYY-MM-DD | 日期格式,支持: • HH:mm(每小时轮转) • YYYY-MM(每月轮转) |
zippedArchive | boolean | true | 是否启用Gzip压缩旧日志 |
maxSize | string | 20m | 文件大小限制,支持: • k/m/g 单位 • 组合值:'100k'或'1g' |
maxFiles | string | 14d | 保留时长,支持: • d(天) • h(小时) • m(分钟) |
utc | boolean | false | 是否使用UTC时间戳 |
auditFile | string | ./audit.json | 审计日志文件路径 |
extension | string | .log | 日志文件扩展名 |
createSymlink | boolean | true | 是否创建当前日志的符号链接 |
symlinkName | string | current.log | 符号链接名称 |
高级配置示例:
// 生产环境推荐配置
createDailyRotateTransport({
level: 'info',
dirname: 'production',
datePattern: 'YYYY-MM-DD-HH', // 每小时轮转
maxSize: '100m',
maxFiles: '30d',
utc: true,
format: format.combine(
format.timestamp(),
format.json() // 结构化日志
)
});
// 开发环境配置
createDailyRotateTransport({
level: 'debug',
dirname: 'development',
zippedArchive: false,
maxFiles: '7d',
format: format.combine(
format.colorize(),
format.simple()
)
});
typescript
3.3 性能优化建议
文件系统优化:
new DailyRotateFile({
// ...
options: {
flags: 'a', // 追加模式
mode: 0o644 // 文件权限
},
highWaterMark: 1024 * 1024 // 1MB缓冲区
})
typescript
日志轮转策略对比:
策略 | 适用场景 | 优缺点 |
---|---|---|
按大小轮转 | 高频日志应用 | 防止单个文件过大,但可能频繁轮转 |
按时间轮转 | 规律性日志 | 易于管理,但可能产生空文件 |
混合轮转(大小+时间) | 生产环境推荐 | 兼顾两者优势 |
3.4 异常处理机制
错误监听示例:
const transport = createDailyRotateTransport({ /* 配置 */ });
transport.on('rotate', (oldFile, newFile) => {
console.log(`日志轮转: ${oldFile} → ${newFile}`);
});
transport.on('error', (err) => {
console.error('日志传输错误:', err);
});
transport.on('open', (fd) => {
console.log('日志文件已打开:', fd);
});
typescript
常见问题解决方案:
问题现象 | 排查步骤 | 解决方案 |
---|---|---|
日志文件未生成 | 1. 检查目录权限 2. 查看错误事件 | 确保目录可写,添加错误监听 |
日志丢失 | 检查轮转事件触发情况 | 增加highWaterMark缓冲区大小 |
时区不正确 | 确认utc参数设置 | 设置utc: true使用UTC时间 |
压缩文件损坏 | 验证zippedArchive版本兼容性 | 升级到winston-daily-rotate-file@5.x |
3.5 扩展应用场景
多日志分类:
// 不同业务日志分离
const transports = [
createDailyRotateTransport({
level: 'info',
dirname: 'order',
filename: 'order-%DATE%.log'
}),
createDailyRotateTransport({
level: 'error',
dirname: 'payment',
filename: 'payment-error-%DATE%.log'
})
];
typescript
日志分级存储:
💡 建议结合ELK等日志分析系统,实现日志的集中管理和可视化分析
4. 动态日志开关控制(深度扩展)
4.1 传输器动态配置(生产级实现)
完整动态配置方案:
// dynamic-transports.ts
import { transports } from 'winston';
import createDailyRotateTransport from './create-rotate-transport';
interface TransportConfig {
type: 'file' | 'console';
level?: string;
dirname?: string;
options?: Record<string, any>;
}
export function getDynamicTransports(configService: ConfigService) {
const logConfig = configService.get<{
enabled: boolean;
transports: TransportConfig[];
}>('logging', {
enabled: true,
transports: [
{ type: 'console', level: 'info' },
{ type: 'file', level: 'info', dirname: 'application' },
{ type: 'file', level: 'warn', dirname: 'errors' }
]
});
if (!logConfig.enabled) {
return [new transports.Console({ silent: true })];
}
return logConfig.transports.map(transport => {
switch (transport.type) {
case 'file':
return createDailyRotateTransport({
level: transport.level || 'info',
dirname: transport.dirname || 'logs',
...transport.options
});
case 'console':
default:
return new transports.Console({
level: transport.level,
format: /* 自定义控制台格式 */,
...transport.options
});
}
});
}
// 使用方式
const transports = getDynamicTransports(configService);
typescript
关键增强功能:
- 配置驱动:从中央配置服务获取日志配置
- 多传输器支持:支持同时配置多个文件和控制台传输器
- 类型安全:使用TypeScript接口规范配置结构
- 静默模式:完全禁用日志时可启用静默控制台
配置示例(config.yml):
logging:
enabled: true
transports:
- type: console
level: debug
options:
colorize: true
- type: file
level: info
dirname: app
options:
maxSize: 50m
zippedArchive: false
- type: file
level: error
dirname: errors
options:
maxFiles: 30d
yaml
4.2 环境变量控制效果(增强版)
完整状态流程图:
多环境控制策略:
环境变量 | 开发环境 | 测试环境 | 生产环境 |
---|---|---|---|
LOG_ON | true | true | true |
LOG_LEVEL | debug | info | warn |
LOG_TO_FILE | false | true | true |
LOG_TO_CONSOLE | true | true | false |
LOG_COMPRESSION | false | true | true |
动态切换示例:
// 热切换日志配置
function hotReloadLogging() {
const newTransports = getDynamicTransports(updatedConfig);
logger.configure({ transports: newTransports });
}
// 监听配置变化
configService.on('logging-changed', hotReloadLogging);
typescript
4.3 高级控制场景
1. 基于请求的日志控制
// 请求级日志过滤
app.use((req, res, next) => {
if (req.path.startsWith('/health')) {
req.logger = silentLogger; // 健康检查不记录日志
} else {
req.logger = contextLogger;
}
next();
});
typescript
2. 性能敏感型日志
// 高频日志优化
const performanceTransport = new transports.Console({
level: 'perf',
format: format.json(),
handleExceptions: false,
handleRejections: false
});
// 业务代码中使用
logger.perf('Database query', { duration: 12ms });
typescript
3. 日志采样配置
// 采样率控制
const sampledTransport = new transports.File({
filename: 'sampled.log',
level: 'info',
sampleRate: 0.1 // 10%的日志会被记录
});
typescript
4.4 监控与告警集成
Prometheus监控示例:
import { collectDefaultMetrics } from 'prom-client';
// 日志指标收集
collectDefaultMetrics({
labels: { app: 'node-service' },
gcDurationBuckets: [0.1, 0.5, 1, 2, 5] // GC日志统计
});
// 错误率告警
const errorCounter = new Counter({
name: 'log_errors_total',
help: 'Total error logs',
labelNames: ['type']
});
logger.on('data', (info) => {
if (info.level === 'error') {
errorCounter.inc({ type: info.errorType });
}
});
typescript
日志量监控看板:
指标名称 | 说明 | 告警阈值 |
---|---|---|
log_volume_1m | 每分钟日志量 | > 1000条 |
error_rate_5m | 5分钟错误率 | > 5% |
log_latency_99 | 99%日志写入延迟 | > 200ms |
4.5 故障演练方案
日志系统健壮性测试:
- 磁盘空间不足测试:
dd if=/dev/zero of=/mock_disk_full bs=1M count=100
bash- 预期行为:自动降级到控制台日志,发出磁盘告警
- 高并发写入测试:
ab -n 10000 -c 100 http://localhost:3000/log-test
bash- 监控指标:日志丢失率、写入延迟
- 配置错误测试:
- 故意设置错误轮转参数
- 验证:是否自动回退到安全默认值
通过以上扩展,动态日志控制系统可以满足从开发到生产各种复杂场景的需求,同时保证系统的可靠性和可观测性。
5. 全局日志集成(深度扩展)
5.1 主文件配置(生产级实现)
完整初始化方案:
// main.ts
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { initializeTransactionalContext } from 'typeorm-transactional';
async function bootstrap() {
// 初始化事务上下文(需在应用创建前执行)
initializeTransactionalContext();
const app = await NestFactory.create(AppModule, {
bufferLogs: true, // 启用日志缓冲
abortOnError: false // 禁止错误时立即退出
});
// 获取全局Logger实例
const logger = app.get(WINSTON_MODULE_NEST_PROVIDER);
// 设置全局日志拦截器
app.useLogger(logger);
// 全局异常过滤器集成
app.useGlobalFilters(
new WinstonExceptionFilter(logger)
);
// 启动前日志记录
logger.log(`Starting application in ${process.env.NODE_ENV} mode`);
await app.listen(3000);
}
bootstrap().catch(err => {
// 启动失败日志记录
const startupLogger = new Logger('Startup');
startupLogger.error('Application bootstrap failed', err.stack);
process.exit(1);
});
typescript
关键配置说明:
- 事务上下文集成:确保日志与数据库事务一致性
- 日志缓冲:避免启动过程中的日志丢失
- 错误处理:
abortOnError: false
防止未捕获异常导致进程退出- 启动失败时使用独立Logger记录错误
高级集成模式:
// 微服务场景集成
const microservice = app.connectMicroservice({
strategy: new KafkaTransport(),
logger: app.get(WINSTON_MODULE_NEST_PROVIDER)
});
// 集群模式支持
if (cluster.isPrimary) {
logger.log(`Master ${process.pid} is running`);
cluster.fork();
} else {
logger.log(`Worker ${process.pid} started`);
}
typescript
5.2 日志格式定制(企业级方案)
完整格式化配置:
import * as winston from 'winston';
import { utilities as nestWinstonUtils } from 'nest-winston';
const customFormat = winston.format.combine(
winston.format.timestamp({
format: 'YYYY-MM-DD HH:mm:ss.SSS'
}),
winston.format.errors({ stack: true }), // 记录完整错误堆栈
winston.format.splat(), // 支持字符串插值
winston.format.ms(), // 毫秒计时(黄色显示)
nestWinstonUtils.format.nestLike('MyApp', {
colors: true,
prettyPrint: true
}),
winston.format.printf(info => {
const { timestamp, level, message, ms, ...meta } = info;
return `${timestamp} [${level}] ${message} ${ms} ${Object.keys(meta).length ? JSON.stringify(meta) : ''}`;
})
);
// 生产环境JSON格式
const productionFormat = winston.format.combine(
winston.format.timestamp(),
winston.format.json()
);
typescript
格式组件详解:
格式化组件 | 功能说明 |
---|---|
format.timestamp() | 添加ISO8601标准时间戳 |
format.errors() | 捕获Error对象的stack属性 |
format.splat() | 支持%s 等占位符替换(如logger.log('User %s logged', username) ) |
format.ms() | 显示从日志记录到输出的耗时(开发环境高亮显示) |
nestLike() | 提供NestJS风格的彩色控制台输出 |
format.printf() | 完全自定义输出格式 |
多环境格式策略:
const getFormat = () => {
switch (process.env.NODE_ENV) {
case 'production':
return productionFormat;
case 'test':
return winston.format.simple();
default:
return customFormat;
}
};
const logger = winston.createLogger({
format: getFormat(),
// ...其他配置
});
typescript
5.3 高级集成技巧
1. 请求上下文集成
// 请求级日志追踪
import { ClsService } from 'nestjs-cls';
const requestAwareFormat = winston.format(info => {
const cls = new ClsService();
return {
...info,
requestId: cls.getId(),
userId: cls.get('user')?.id
};
});
// 使用示例
logger.log('Payment processed', {
orderId: 123,
_ctx: { userId: 456 } // 上下文元数据
});
typescript
2. 性能监控集成
// 响应时间跟踪
const perfFormat = winston.format(info => {
if (info.durationMs) {
info.message = `${info.message} (${info.durationMs}ms)`;
}
return info;
});
// 使用方式
console.time('dbQuery');
// ...数据库操作
console.timeEnd('dbQuery'); // 自动记录耗时
typescript
3. 结构化日志最佳实践
// 生产环境日志示例
{
"timestamp": "2023-08-20T14:32:45.123Z",
"level": "error",
"message": "Payment failed",
"transactionId": "txn_123",
"userId": "usr_456",
"error": {
"name": "PaymentError",
"stack": "...",
"code": "LIMIT_EXCEEDED"
},
"context": {
"service": "payment-service",
"region": "us-west-1"
}
}
json
5.4 监控与告警
Prometheus指标集成:
import { Counter } from 'prom-client';
const errorCounter = new Counter({
name: 'app_errors_total',
help: 'Total application errors',
labelNames: ['type']
});
logger.on('logged', info => {
if (info.level === 'error') {
errorCounter.inc({ type: info.error?.name || 'unknown' });
}
});
typescript
ELK日志分析配置:
# Filebeat配置示例
filebeat.inputs:
- type: log
paths:
- /var/log/app/*.log
json.keys_under_root: true
json.add_error_key: true
output.elasticsearch:
hosts: ["elasticsearch:9200"]
indices:
- index: "app-logs-%{+yyyy.MM.dd}"
yaml
5.5 故障排查指南
常见问题解决方案:
问题现象 | 排查步骤 | 解决方案 |
---|---|---|
日志不显示毫秒 | 1. 检查format.ms() 位置2. 确认终端支持颜色 | 确保ms() 在combine 中靠后,设置colors: true |
生产环境日志过大 | 1. 检查轮转配置 2. 验证日志级别 | 调整maxSize 和maxFiles ,设置生产环境level: 'warn' |
丢失请求上下文 | 1. 检查CLS中间件顺序 2. 验证异步上下文 | 确保CLS中间件最先加载,使用AsyncLocalStorage |
日志写入性能瓶颈 | 1. 监控IO等待时间 2. 检查传输器配置 | 增加highWaterMark ,考虑使用Winston的AsyncTransport |
通过以上扩展,全局日志集成可以满足企业级应用的可观测性需求,同时保持高性能和可维护性。
6. Git集成注意事项(深度扩展)
6.1 目录重命名方案(企业级实践)
完整重构步骤:
# 1. 重命名目录(保留Git历史)
git mv src/common/logs src/common/log
# 2. 全局替换引用路径
find . -type f -name "*.ts" -exec sed -i '' 's/common\/logs/common\/log/g' {} +
# 3. 更新模块注册
// app.module.ts
@Module({
imports: [
- LogsModule,
+ LogModule // 同步更新模块类名
]
})
bash
重命名规范建议:
类型 | 旧命名 | 新命名 | 理由 |
---|---|---|---|
目录名 | logs | log | 避开.gitignore默认规则 |
模块类名 | LogsModule | LogModule | 保持单数形式一致性 |
配置文件 | logs.config.ts | log.config.ts | 与目录结构对齐 |
自动化重构脚本:
#!/bin/bash
# rename-log-dir.sh
OLD_DIR="common/logs"
NEW_DIR="common/log"
git mv $OLD_DIR $NEW_DIR
rg -l $OLD_DIR | xargs sed -i '' "s/$OLD_DIR/$NEW_DIR/g"
npm run lint:fix
bash
6.2 .gitignore配置建议(增强版)
完整日志管理方案:
# 日志文件管理
*.log # 忽略所有日志文件
!*.audit.log # 但保留审计日志
*.log.* # 忽略轮转日志
*.gz # 忽略压缩日志
# 目录白名单
!common/log/ # 允许提交日志目录
!common/log/audit/ # 审计日志目录
common/log/*.log # 但忽略目录内日志文件
# 开发环境排除
.idea/
.vscode/
node_modules/
dist/
git-commit
特殊场景处理:
- 敏感日志过滤:
# 提交前清理敏感信息 find common/log/ -name "*.log" -exec sed -i '' '/password/d' {} +
bash - 日志目录结构:
common/ log/ ├── audit/ # 审计日志(需提交) ├── app/ # 应用日志(不提交) └── test/ # 测试日志(不提交)
text
6.3 提交前检查清单(CI/CD集成)
自动化检查脚本:
#!/bin/bash
# pre-commit-checklist.sh
# 1. 路径检查
if ! grep -q "from './log/log.module'" src/app.module.ts; then
echo "❌ 模块导入路径未更新"
exit 1
fi
# 2. 启动测试
timeout 30s pnpm start:dev > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "❌ 应用启动失败"
exit 1
fi
# 3. 日志生成检查
if [ ! -d "common/log/app" ]; then
echo "❌ 日志目录未生成"
exit 1
fi
# 4. Git状态检查
if git status -u | grep -q "common/logs"; then
echo "❌ 存在未更新的旧路径引用"
exit 1
fi
echo "✅ 所有检查通过"
exit 0
bash
Git Hook集成:
# .husky/pre-commit
#!/bin/sh
./scripts/pre-commit-checklist.sh
if [ $? -ne 0 ]; then
exit 1
fi
bash
检查项增强说明:
检查项 | 执行命令 | 成功标准 |
---|---|---|
模块路径更新 | grep -r "from './log" src/ | 所有引用使用新路径 |
应用启动测试 | pnpm test:start | 30秒内无错误退出 |
日志目录结构 | tree common/log | 存在audit/和app/子目录 |
Git残留文件 | `git ls-files | grep "logs"` |
6.4 团队协作规范
分支策略:
Code Review要点:
- 目录变更:
- 确认
git mv
而非删除重建 - 检查所有相关文件路径更新
- 确认
- 忽略规则:
- 验证
.gitignore
白名单有效性 - 确认无敏感日志被提交
- 验证
- 依赖影响:
- 检查其他服务对日志路径的依赖
- 更新相关文档(如API文档中的示例路径)
6.5 异常处理方案
常见问题解决:
问题现象 | 原因分析 | 解决方案 |
---|---|---|
重命名后应用启动失败 | 硬编码路径未更新 | 执行全局搜索替换 |
Git历史丢失 | 直接删除而非git mv | 使用git log --follow 恢复历史 |
白名单规则不生效 | .gitignore顺序错误 | 将否定规则放在对应通配规则之后 |
CI检查误报 | 测试环境残留旧目录 | 添加git clean -fd 预处理步骤 |
回滚方案:
# 回滚目录重命名
git mv common/log common/logs
git checkout HEAD -- .gitignore
find . -type f -name "*.ts" -exec sed -i '' 's/common\/log/common\/logs/g' {} +
bash
通过以上扩展,Git集成方案可确保日志模块变更安全地融入团队开发流程,同时保持代码库的整洁性和可维护性。
↑