Terminus高级配置:自定义错误处理与日志记录技巧 Terminus高级配置自定义错误处理与日志记录技巧【免费下载链接】terminusTerminus module for Nest framework (node.js) :robot:项目地址: https://gitcode.com/gh_mirrors/terminus3/terminus在构建现代Nest.js应用时健康检查是不可或缺的功能而Terminus作为Nest.js生态中的健康检查模块提供了强大的自定义错误处理和日志记录功能。本文将深入探讨如何通过高级配置优化Terminus的错误处理和日志记录帮助您构建更可靠、更易维护的微服务应用。为什么需要自定义错误处理 在分布式系统中健康检查不仅仅是简单的活着状态检测。当数据库连接失败、外部API不可用或磁盘空间不足时您需要清晰的错误信息- 快速定位问题根源结构化的日志输出- 便于监控系统收集和分析优雅的错误处理- 避免服务雪崩效应可定制的错误格式- 适应不同的监控需求Terminus提供了灵活的配置选项让您可以根据应用需求定制错误处理和日志记录策略。配置Terminus错误日志样式Terminus支持两种错误日志样式JSON格式和Pretty格式。默认情况下Terminus使用JSON格式但您可以根据环境需求进行切换。JSON格式日志配置JSON格式是生产环境的理想选择因为它易于被日志收集系统如ELK、Splunk解析// app.module.ts import { Module } from nestjs/common; import { TerminusModule } from nestjs/terminus; Module({ imports: [ TerminusModule.forRoot({ errorLogStyle: json, // 默认值 logger: true, // 启用内置日志记录器 gracefulShutdownTimeoutMs: 10000, // 优雅关闭超时时间 }), ], }) export class AppModule {}JSON格式的错误日志会生成类似以下的结构化输出{ message: Health Check has failed!, causes: { database: { status: down, message: Connection timeout, timestamp: 2024-01-01T12:00:00Z } } }Pretty格式日志配置在开发环境中Pretty格式提供了更易读的控制台输出// app.module.ts import { Module } from nestjs/common; import { TerminusModule } from nestjs/terminus; Module({ imports: [ TerminusModule.forRoot({ errorLogStyle: pretty, // 启用美化格式 logger: true, }), ], }) export class AppModule {}Pretty格式会在控制台中显示带颜色的框状输出让开发人员一眼就能识别健康状态Health Check has failed! ┌──────────────┐ │ ❌ database │ ├──────────────┤ │ status: down │ │ message: │ │ Connection │ │ timeout │ └──────────────┘自定义错误日志记录器当内置的日志记录器不能满足需求时您可以创建自定义的错误日志记录器。Terminus提供了扩展接口让您完全控制错误信息的格式和输出方式。创建自定义错误日志记录器首先实现ErrorLogger接口// custom-error-logger.service.ts import { Injectable } from nestjs/common; import { ErrorLogger } from nestjs/terminus; import { HealthIndicatorResult } from nestjs/terminus; Injectable() export class CustomErrorLogger implements ErrorLogger { getErrorMessage(message: string, causes: HealthIndicatorResult): string { // 自定义错误信息格式 const timestamp new Date().toISOString(); const serviceName process.env.SERVICE_NAME || unknown; return JSON.stringify({ level: ERROR, timestamp, service: serviceName, message, details: this.formatCauses(causes), environment: process.env.NODE_ENV, }); } private formatCauses(causes: HealthIndicatorResult): any { // 自定义原因格式化逻辑 const formatted {}; for (const [key, value] of Object.entries(causes)) { formatted[key] { status: value.status, timestamp: new Date().toISOString(), metadata: value.metadata || {}, }; } return formatted; } }注册自定义日志记录器在模块配置中注册您的自定义日志记录器// health.module.ts import { Module } from nestjs/common; import { TerminusModule } from nestjs/terminus; import { CustomErrorLogger } from ./custom-error-logger.service; Module({ imports: [ TerminusModule.forRootAsync({ useFactory: () ({ logger: CustomErrorLogger, // 使用自定义日志记录器 errorLogStyle: json, }), }), ], }) export class HealthModule {}异步配置与动态设置在实际应用中您可能需要根据环境变量或配置文件动态调整Terminus的配置。Terminus支持异步配置方式让您能够灵活地获取配置信息。使用ConfigService进行动态配置// health.module.ts import { Module } from nestjs/common; import { TerminusModule } from nestjs/terminus; import { ConfigModule, ConfigService } from nestjs/config; Module({ imports: [ TerminusModule.forRootAsync({ imports: [ConfigModule], useFactory: (configService: ConfigService) ({ errorLogStyle: configService.getstring(TERMINUS_ERROR_LOG_STYLE) as json | pretty, logger: configService.getboolean(TERMINUS_ENABLE_LOGGER, true), gracefulShutdownTimeoutMs: configService.getnumber(TERMINUS_SHUTDOWN_TIMEOUT, 10000), }), inject: [ConfigService], }), ], }) export class HealthModule {}环境变量配置示例在.env文件中配置Terminus参数# Terminus配置 TERMINUS_ERROR_LOG_STYLEjson TERMINUS_ENABLE_LOGGERtrue TERMINUS_SHUTDOWN_TIMEOUT15000 TERMINUS_HEALTH_CHECK_TIMEOUT5000错误处理最佳实践 1. 分层错误处理策略根据错误类型采用不同的处理策略// health.controller.ts import { Controller, Get } from nestjs/common; import { HealthCheck, HealthCheckService, HealthCheckError, HttpHealthIndicator, TypeOrmHealthIndicator } from nestjs/terminus; Controller(health) export class HealthController { constructor( private health: HealthCheckService, private http: HttpHealthIndicator, private db: TypeOrmHealthIndicator, ) {} Get() HealthCheck() async check() { try { return await this.health.check([ // 关键依赖 - 数据库连接 async () { try { return await this.db.pingCheck(database, { timeout: 3000 }); } catch (error) { // 数据库连接失败 - 严重错误 throw new HealthCheckError( Database connection failed, { database: { status: down, message: error.message, code: DB_CONNECTION_FAILED } } ); } }, // 重要依赖 - 外部API async () { try { return await this.http.pingCheck(external-api, https://api.example.com); } catch (error) { // 外部API不可用 - 警告级别 return { external-api: { status: down, message: External API temporarily unavailable, severity: warning } }; } }, ]); } catch (error) { // 全局错误处理 this.logCriticalError(error); throw error; } } private logCriticalError(error: any) { // 发送到监控系统 console.error(Critical health check failure:, { timestamp: new Date().toISOString(), error: error.message, stack: error.stack, }); } }2. 结构化错误信息为不同的健康指标提供详细的错误信息// custom-health-indicator.ts import { Injectable } from nestjs/common; import { HealthIndicator, HealthIndicatorResult, HealthCheckError } from nestjs/terminus; Injectable() export class CustomHealthIndicator extends HealthIndicator { async isHealthy(key: string): PromiseHealthIndicatorResult { try { const isHealthy await this.checkCustomService(); if (!isHealthy) { throw new HealthCheckError( Custom service check failed, this.getStatus(key, false, { service: custom-service, endpoint: /api/v1/health, responseTime: 150, // ms errorCode: SERVICE_UNAVAILABLE, retryCount: 3, lastSuccessfulCheck: 2024-01-01T10:00:00Z, }) ); } return this.getStatus(key, true, { service: custom-service, endpoint: /api/v1/health, responseTime: 45, // ms version: 1.2.3, uptime: 7d 12h, }); } catch (error) { throw new HealthCheckError( Custom service health check failed, this.getStatus(key, false, { service: custom-service, error: error.message, stack: error.stack?.split(\n)[0], timestamp: new Date().toISOString(), }) ); } } private async checkCustomService(): Promiseboolean { // 实现自定义健康检查逻辑 return true; } }3. 优雅关闭配置配置优雅关闭超时时间确保在关闭前完成所有健康检查// app.module.ts import { Module } from nestjs/common; import { TerminusModule } from nestjs/terminus; Module({ imports: [ TerminusModule.forRoot({ gracefulShutdownTimeoutMs: 30000, // 30秒超时 errorLogStyle: json, logger: true, }), ], }) export class AppModule {}监控与告警集成 集成Prometheus监控将Terminus健康检查结果导出为Prometheus指标// prometheus-health.controller.ts import { Controller, Get } from nestjs/common; import { HealthCheck, HealthCheckService } from nestjs/terminus; import { PrometheusService } from ./prometheus.service; Controller(metrics/health) export class PrometheusHealthController { constructor( private health: HealthCheckService, private prometheus: PrometheusService, ) {} Get() HealthCheck() async check() { const result await this.health.check([ // 健康检查逻辑 ]); // 将健康状态导出为Prometheus指标 this.prometheus.recordHealthMetrics(result); return result; } }告警规则配置基于健康检查结果配置告警规则# alert-rules.yaml groups: - name: health_checks rules: - alert: DatabaseHealthCheckFailed expr: health_check_status{dependencydatabase} 0 for: 1m labels: severity: critical annotations: summary: Database health check failed description: Database connection has been down for more than 1 minute - alert: ExternalAPIHealthCheckFailed expr: health_check_status{dependencyexternal-api} 0 for: 5m labels: severity: warning annotations: summary: External API health check failed description: External API has been unavailable for more than 5 minutes性能优化技巧 ⚡1. 超时配置优化为不同的健康检查设置合理的超时时间// health.controller.ts Controller(health) export class HealthController { constructor( private health: HealthCheckService, private http: HttpHealthIndicator, private db: TypeOrmHealthIndicator, private disk: DiskHealthIndicator, ) {} Get() HealthCheck() check() { return this.health.check([ // 快速检查 - 内部服务 async () this.db.pingCheck(database, { timeout: 1000 }), // 中等检查 - 外部API async () this.http.pingCheck(external-api, https://api.example.com, { timeout: 3000, }), // 慢速检查 - 磁盘空间 async () this.disk.checkStorage(storage, { thresholdPercent: 0.9, path: /, timeout: 5000, }), ]); } }2. 缓存健康检查结果对于昂贵的健康检查实现缓存机制// cached-health.service.ts import { Injectable } from nestjs/common; import { HealthIndicator, HealthIndicatorResult } from nestjs/terminus; Injectable() export class CachedHealthService { private cache new Mapstring, { result: any; timestamp: number }(); private readonly CACHE_TTL 30000; // 30秒 async getCachedHealth( key: string, checkFn: () PromiseHealthIndicatorResult, ): PromiseHealthIndicatorResult { const cached this.cache.get(key); if (cached Date.now() - cached.timestamp this.CACHE_TTL) { return cached.result; } const result await checkFn(); this.cache.set(key, { result, timestamp: Date.now() }); return result; } clearCache() { this.cache.clear(); } }调试与故障排除 启用详细日志在开发环境中启用详细日志记录// main.ts import { NestFactory } from nestjs/core; import { AppModule } from ./app.module; import { Logger } from nestjs/common; async function bootstrap() { const app await NestFactory.create(AppModule, { logger: [error, warn, log, debug, verbose], }); await app.listen(3000); } bootstrap();健康检查调试端点创建专门的调试端点// debug.controller.ts import { Controller, Get } from nestjs/common; import { HealthCheckService } from nestjs/terminus; Controller(debug/health) export class DebugHealthController { constructor(private health: HealthCheckService) {} Get(verbose) async verboseCheck() { const startTime Date.now(); const result await this.health.check([ // 所有健康检查 ]); const duration Date.now() - startTime; return { ...result, metadata: { checkDuration: ${duration}ms, timestamp: new Date().toISOString(), nodeVersion: process.version, memoryUsage: process.memoryUsage(), }, }; } }总结通过Terminus的高级配置您可以构建强大的健康检查系统具备完整的错误处理和日志记录能力。关键要点包括选择合适的日志格式- JSON用于生产Pretty用于开发自定义错误处理逻辑- 实现ErrorLogger接口完全控制错误输出异步配置支持- 根据环境动态调整配置分层错误处理- 根据错误严重程度采取不同策略监控集成- 与Prometheus等监控系统无缝集成性能优化- 合理设置超时和缓存机制掌握这些高级配置技巧后您的Nest.js应用将具备企业级的健康检查能力能够快速发现和诊断问题确保系统的高可用性和可靠性。通过合理的错误处理和日志记录配置Terminus不仅能够告诉您系统是否健康还能提供详细的诊断信息帮助您快速定位和解决问题真正实现健康检查的价值。【免费下载链接】terminusTerminus module for Nest framework (node.js) :robot:项目地址: https://gitcode.com/gh_mirrors/terminus3/terminus创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考