| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | package external_logger | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | import ( | 
					
						
							|  |  |  |  | 	"fmt" | 
					
						
							|  |  |  |  | 	"os" | 
					
						
							|  |  |  |  | 	"path/filepath" | 
					
						
							|  |  |  |  | 	"time" | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	"go.uber.org/zap" | 
					
						
							|  |  |  |  | 	"go.uber.org/zap/zapcore" | 
					
						
							|  |  |  |  | 	"gopkg.in/natefinch/lumberjack.v2" | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ExternalServiceLoggingConfig 外部服务日志配置 | 
					
						
							|  |  |  |  | type ExternalServiceLoggingConfig struct { | 
					
						
							|  |  |  |  | 	Enabled               bool                                      `yaml:"enabled"` | 
					
						
							|  |  |  |  | 	LogDir                string                                    `yaml:"log_dir"` | 
					
						
							|  |  |  |  | 	ServiceName           string                                    `yaml:"service_name"` // 服务名称,用于区分日志目录 | 
					
						
							|  |  |  |  | 	UseDaily              bool                                      `yaml:"use_daily"` | 
					
						
							|  |  |  |  | 	EnableLevelSeparation bool                                      `yaml:"enable_level_separation"` | 
					
						
							|  |  |  |  | 	LevelConfigs          map[string]ExternalServiceLevelFileConfig `yaml:"level_configs"` | 
					
						
							| 
									
										
										
										
											2025-08-27 22:19:19 +08:00
										 |  |  |  | 	// 新增:请求和响应日志的独立配置 | 
					
						
							|  |  |  |  | 	RequestLogConfig  ExternalServiceLevelFileConfig `yaml:"request_log_config"` | 
					
						
							|  |  |  |  | 	ResponseLogConfig ExternalServiceLevelFileConfig `yaml:"response_log_config"` | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ExternalServiceLevelFileConfig 外部服务级别文件配置 | 
					
						
							|  |  |  |  | type ExternalServiceLevelFileConfig struct { | 
					
						
							|  |  |  |  | 	MaxSize    int  `yaml:"max_size"` | 
					
						
							|  |  |  |  | 	MaxBackups int  `yaml:"max_backups"` | 
					
						
							|  |  |  |  | 	MaxAge     int  `yaml:"max_age"` | 
					
						
							|  |  |  |  | 	Compress   bool `yaml:"compress"` | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // ExternalServiceLogger 外部服务日志器 | 
					
						
							|  |  |  |  | type ExternalServiceLogger struct { | 
					
						
							|  |  |  |  | 	logger      *zap.Logger | 
					
						
							|  |  |  |  | 	config      ExternalServiceLoggingConfig | 
					
						
							|  |  |  |  | 	serviceName string | 
					
						
							| 
									
										
										
										
											2025-08-27 22:19:19 +08:00
										 |  |  |  | 	// 新增:用于区分请求和响应日志的字段 | 
					
						
							|  |  |  |  | 	requestLogger  *zap.Logger | 
					
						
							|  |  |  |  | 	responseLogger *zap.Logger | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // NewExternalServiceLogger 创建外部服务日志器 | 
					
						
							|  |  |  |  | func NewExternalServiceLogger(config ExternalServiceLoggingConfig) (*ExternalServiceLogger, error) { | 
					
						
							|  |  |  |  | 	if !config.Enabled { | 
					
						
							|  |  |  |  | 		return &ExternalServiceLogger{ | 
					
						
							|  |  |  |  | 			logger:      zap.NewNop(), | 
					
						
							|  |  |  |  | 			serviceName: config.ServiceName, | 
					
						
							|  |  |  |  | 		}, nil | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 根据服务名称创建独立的日志目录 | 
					
						
							|  |  |  |  | 	serviceLogDir := filepath.Join(config.LogDir, config.ServiceName) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 确保日志目录存在 | 
					
						
							|  |  |  |  | 	if err := os.MkdirAll(serviceLogDir, 0755); err != nil { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("创建日志目录失败: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 创建基础配置 | 
					
						
							|  |  |  |  | 	zapConfig := zap.NewProductionConfig() | 
					
						
							|  |  |  |  | 	zapConfig.OutputPaths = []string{"stdout"} | 
					
						
							|  |  |  |  | 	zapConfig.ErrorOutputPaths = []string{"stderr"} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 创建基础logger | 
					
						
							|  |  |  |  | 	baseLogger, err := zapConfig.Build() | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return nil, fmt.Errorf("创建基础logger失败: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-27 22:19:19 +08:00
										 |  |  |  | 	// 创建请求和响应日志器 | 
					
						
							|  |  |  |  | 	requestLogger, err := createRequestLogger(serviceLogDir, config) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		// 如果创建失败,使用基础logger作为备选 | 
					
						
							|  |  |  |  | 		requestLogger = baseLogger | 
					
						
							|  |  |  |  | 		fmt.Printf("创建请求日志器失败,使用基础logger: %v\n", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	responseLogger, err := createResponseLogger(serviceLogDir, config) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		// 如果创建失败,使用基础logger作为备选 | 
					
						
							|  |  |  |  | 		responseLogger = baseLogger | 
					
						
							|  |  |  |  | 		fmt.Printf("创建响应日志器失败,使用基础logger: %v\n", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | 	// 如果启用级别分离,创建文件输出 | 
					
						
							|  |  |  |  | 	if config.EnableLevelSeparation { | 
					
						
							|  |  |  |  | 		core := createSeparatedCore(serviceLogDir, config) | 
					
						
							|  |  |  |  | 		baseLogger = zap.New(core) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 创建日志器实例 | 
					
						
							|  |  |  |  | 	logger := &ExternalServiceLogger{ | 
					
						
							| 
									
										
										
										
											2025-08-27 22:19:19 +08:00
										 |  |  |  | 		logger:         baseLogger, | 
					
						
							|  |  |  |  | 		config:         config, | 
					
						
							|  |  |  |  | 		serviceName:    config.ServiceName, | 
					
						
							|  |  |  |  | 		requestLogger:  requestLogger, | 
					
						
							|  |  |  |  | 		responseLogger: responseLogger, | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 如果启用按天分隔,启动定时清理任务 | 
					
						
							|  |  |  |  | 	if config.UseDaily { | 
					
						
							|  |  |  |  | 		go logger.startCleanupTask() | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return logger, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-27 22:19:19 +08:00
										 |  |  |  | // createRequestLogger 创建请求日志器 | 
					
						
							|  |  |  |  | func createRequestLogger(logDir string, config ExternalServiceLoggingConfig) (*zap.Logger, error) { | 
					
						
							|  |  |  |  | 	// 创建编码器 | 
					
						
							|  |  |  |  | 	encoderConfig := zap.NewProductionEncoderConfig() | 
					
						
							|  |  |  |  | 	encoderConfig.TimeKey = "timestamp" | 
					
						
							|  |  |  |  | 	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder | 
					
						
							|  |  |  |  | 	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 使用默认配置如果未指定 | 
					
						
							|  |  |  |  | 	requestConfig := config.RequestLogConfig | 
					
						
							|  |  |  |  | 	if requestConfig.MaxSize == 0 { | 
					
						
							|  |  |  |  | 		requestConfig.MaxSize = 100 | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if requestConfig.MaxBackups == 0 { | 
					
						
							|  |  |  |  | 		requestConfig.MaxBackups = 5 | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if requestConfig.MaxAge == 0 { | 
					
						
							|  |  |  |  | 		requestConfig.MaxAge = 30 | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 创建请求日志文件写入器 | 
					
						
							|  |  |  |  | 	requestWriter := createFileWriter(logDir, "request", requestConfig, config.ServiceName, config.UseDaily) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 创建请求日志核心 | 
					
						
							|  |  |  |  | 	requestCore := zapcore.NewCore( | 
					
						
							|  |  |  |  | 		zapcore.NewJSONEncoder(encoderConfig), | 
					
						
							|  |  |  |  | 		zapcore.AddSync(requestWriter), | 
					
						
							|  |  |  |  | 		zapcore.InfoLevel, | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return zap.New(requestCore), nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // createResponseLogger 创建响应日志器 | 
					
						
							|  |  |  |  | func createResponseLogger(logDir string, config ExternalServiceLoggingConfig) (*zap.Logger, error) { | 
					
						
							|  |  |  |  | 	// 创建编码器 | 
					
						
							|  |  |  |  | 	encoderConfig := zap.NewProductionEncoderConfig() | 
					
						
							|  |  |  |  | 	encoderConfig.TimeKey = "timestamp" | 
					
						
							|  |  |  |  | 	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder | 
					
						
							|  |  |  |  | 	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 使用默认配置如果未指定 | 
					
						
							|  |  |  |  | 	responseConfig := config.ResponseLogConfig | 
					
						
							|  |  |  |  | 	if responseConfig.MaxSize == 0 { | 
					
						
							|  |  |  |  | 		responseConfig.MaxSize = 100 | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if responseConfig.MaxBackups == 0 { | 
					
						
							|  |  |  |  | 		responseConfig.MaxBackups = 5 | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if responseConfig.MaxAge == 0 { | 
					
						
							|  |  |  |  | 		responseConfig.MaxAge = 30 | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 创建响应日志文件写入器 | 
					
						
							|  |  |  |  | 	responseWriter := createFileWriter(logDir, "response", responseConfig, config.ServiceName, config.UseDaily) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 创建响应日志核心 | 
					
						
							|  |  |  |  | 	responseCore := zapcore.NewCore( | 
					
						
							|  |  |  |  | 		zapcore.NewJSONEncoder(encoderConfig), | 
					
						
							|  |  |  |  | 		zapcore.AddSync(responseWriter), | 
					
						
							|  |  |  |  | 		zapcore.InfoLevel, | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return zap.New(responseCore), nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | // createSeparatedCore 创建分离的日志核心 | 
					
						
							|  |  |  |  | func createSeparatedCore(logDir string, config ExternalServiceLoggingConfig) zapcore.Core { | 
					
						
							|  |  |  |  | 	// 创建编码器 | 
					
						
							|  |  |  |  | 	encoderConfig := zap.NewProductionEncoderConfig() | 
					
						
							|  |  |  |  | 	encoderConfig.TimeKey = "timestamp" | 
					
						
							|  |  |  |  | 	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder | 
					
						
							|  |  |  |  | 	encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 创建不同级别的文件输出 | 
					
						
							|  |  |  |  | 	infoWriter := createFileWriter(logDir, "info", config.LevelConfigs["info"], config.ServiceName, config.UseDaily) | 
					
						
							|  |  |  |  | 	errorWriter := createFileWriter(logDir, "error", config.LevelConfigs["error"], config.ServiceName, config.UseDaily) | 
					
						
							|  |  |  |  | 	warnWriter := createFileWriter(logDir, "warn", config.LevelConfigs["warn"], config.ServiceName, config.UseDaily) | 
					
						
							| 
									
										
										
										
											2025-08-27 22:19:19 +08:00
										 |  |  |  | 	 | 
					
						
							|  |  |  |  | 	// 新增:请求和响应日志的独立文件输出 | 
					
						
							|  |  |  |  | 	requestWriter := createFileWriter(logDir, "request", config.RequestLogConfig, config.ServiceName, config.UseDaily) | 
					
						
							|  |  |  |  | 	responseWriter := createFileWriter(logDir, "response", config.ResponseLogConfig, config.ServiceName, config.UseDaily) | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 修复:创建真正的级别分离核心 | 
					
						
							|  |  |  |  | 	// 使用自定义的LevelEnabler来确保每个Core只处理特定级别的日志 | 
					
						
							|  |  |  |  | 	infoCore := zapcore.NewCore( | 
					
						
							|  |  |  |  | 		zapcore.NewJSONEncoder(encoderConfig), | 
					
						
							|  |  |  |  | 		zapcore.AddSync(infoWriter), | 
					
						
							|  |  |  |  | 		&levelEnabler{minLevel: zapcore.InfoLevel, maxLevel: zapcore.InfoLevel}, // 只接受INFO级别 | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	errorCore := zapcore.NewCore( | 
					
						
							|  |  |  |  | 		zapcore.NewJSONEncoder(encoderConfig), | 
					
						
							|  |  |  |  | 		zapcore.AddSync(errorWriter), | 
					
						
							|  |  |  |  | 		&levelEnabler{minLevel: zapcore.ErrorLevel, maxLevel: zapcore.ErrorLevel}, // 只接受ERROR级别 | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	warnCore := zapcore.NewCore( | 
					
						
							|  |  |  |  | 		zapcore.NewJSONEncoder(encoderConfig), | 
					
						
							|  |  |  |  | 		zapcore.AddSync(warnWriter), | 
					
						
							|  |  |  |  | 		&levelEnabler{minLevel: zapcore.WarnLevel, maxLevel: zapcore.WarnLevel}, // 只接受WARN级别 | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-27 22:19:19 +08:00
										 |  |  |  | 	// 新增:请求和响应日志核心 | 
					
						
							|  |  |  |  | 	requestCore := zapcore.NewCore( | 
					
						
							|  |  |  |  | 		zapcore.NewJSONEncoder(encoderConfig), | 
					
						
							|  |  |  |  | 		zapcore.AddSync(requestWriter), | 
					
						
							|  |  |  |  | 		&requestResponseEnabler{logType: "request"}, // 只接受请求日志 | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	responseCore := zapcore.NewCore( | 
					
						
							|  |  |  |  | 		zapcore.NewJSONEncoder(encoderConfig), | 
					
						
							|  |  |  |  | 		zapcore.AddSync(responseWriter), | 
					
						
							|  |  |  |  | 		&requestResponseEnabler{logType: "response"}, // 只接受响应日志 | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 使用 zapcore.NewTee 合并核心,现在每个核心只会处理自己类型的日志 | 
					
						
							|  |  |  |  | 	return zapcore.NewTee(infoCore, errorCore, warnCore, requestCore, responseCore) | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // levelEnabler 自定义级别过滤器,确保只接受指定级别的日志 | 
					
						
							|  |  |  |  | type levelEnabler struct { | 
					
						
							|  |  |  |  | 	minLevel zapcore.Level | 
					
						
							|  |  |  |  | 	maxLevel zapcore.Level | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // Enabled 实现 zapcore.LevelEnabler 接口 | 
					
						
							|  |  |  |  | func (l *levelEnabler) Enabled(level zapcore.Level) bool { | 
					
						
							|  |  |  |  | 	return level >= l.minLevel && level <= l.maxLevel | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-27 22:19:19 +08:00
										 |  |  |  | // requestResponseEnabler 自定义日志类型过滤器,确保只接受特定类型的日志 | 
					
						
							|  |  |  |  | type requestResponseEnabler struct { | 
					
						
							|  |  |  |  | 	logType string | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // Enabled 实现 zapcore.LevelEnabler 接口 | 
					
						
							|  |  |  |  | func (r *requestResponseEnabler) Enabled(level zapcore.Level) bool { | 
					
						
							|  |  |  |  | 	// 请求和响应日志通常是INFO级别 | 
					
						
							|  |  |  |  | 	return level == zapcore.InfoLevel | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | // createFileWriter 创建文件写入器 | 
					
						
							|  |  |  |  | func createFileWriter(logDir, level string, config ExternalServiceLevelFileConfig, serviceName string, useDaily bool) *lumberjack.Logger { | 
					
						
							|  |  |  |  | 	// 使用默认配置如果未指定 | 
					
						
							|  |  |  |  | 	if config.MaxSize == 0 { | 
					
						
							|  |  |  |  | 		config.MaxSize = 100 | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if config.MaxBackups == 0 { | 
					
						
							|  |  |  |  | 		config.MaxBackups = 3 | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if config.MaxAge == 0 { | 
					
						
							|  |  |  |  | 		config.MaxAge = 28 | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 构建文件名 | 
					
						
							|  |  |  |  | 	var filename string | 
					
						
							|  |  |  |  | 	if useDaily { | 
					
						
							|  |  |  |  | 		// 按天分隔:logs/westdex/2024-01-01/westdex_info.log | 
					
						
							|  |  |  |  | 		date := time.Now().Format("2006-01-02") | 
					
						
							|  |  |  |  | 		dateDir := filepath.Join(logDir, date) | 
					
						
							| 
									
										
										
										
											2025-08-26 16:03:46 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | 		// 确保日期目录存在 | 
					
						
							|  |  |  |  | 		if err := os.MkdirAll(dateDir, 0755); err != nil { | 
					
						
							|  |  |  |  | 			// 如果创建日期目录失败,回退到根目录 | 
					
						
							|  |  |  |  | 			filename = filepath.Join(logDir, fmt.Sprintf("%s_%s.log", serviceName, level)) | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							|  |  |  |  | 			filename = filepath.Join(dateDir, fmt.Sprintf("%s_%s.log", serviceName, level)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} else { | 
					
						
							|  |  |  |  | 		// 传统方式:logs/westdex/westdex_info.log | 
					
						
							|  |  |  |  | 		filename = filepath.Join(logDir, fmt.Sprintf("%s_%s.log", serviceName, level)) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return &lumberjack.Logger{ | 
					
						
							|  |  |  |  | 		Filename:   filename, | 
					
						
							|  |  |  |  | 		MaxSize:    config.MaxSize, | 
					
						
							|  |  |  |  | 		MaxBackups: config.MaxBackups, | 
					
						
							|  |  |  |  | 		MaxAge:     config.MaxAge, | 
					
						
							|  |  |  |  | 		Compress:   config.Compress, | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // LogRequest 记录请求日志 | 
					
						
							| 
									
										
										
										
											2025-08-26 16:03:46 +08:00
										 |  |  |  | func (e *ExternalServiceLogger) LogRequest(requestID, transactionID, apiCode string, url interface{}, params interface{}) { | 
					
						
							| 
									
										
										
										
											2025-08-27 22:19:19 +08:00
										 |  |  |  | 	e.requestLogger.Info(fmt.Sprintf("%s API请求", e.serviceName), | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | 		zap.String("service", e.serviceName), | 
					
						
							|  |  |  |  | 		zap.String("request_id", requestID), | 
					
						
							| 
									
										
										
										
											2025-08-26 16:03:46 +08:00
										 |  |  |  | 		zap.String("transaction_id", transactionID), | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | 		zap.String("api_code", apiCode), | 
					
						
							|  |  |  |  | 		zap.Any("url", url), | 
					
						
							|  |  |  |  | 		zap.Any("params", params), | 
					
						
							|  |  |  |  | 		zap.String("timestamp", time.Now().Format(time.RFC3339)), | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // LogResponse 记录响应日志 | 
					
						
							| 
									
										
										
										
											2025-08-26 16:03:46 +08:00
										 |  |  |  | func (e *ExternalServiceLogger) LogResponse(requestID, transactionID, apiCode string, statusCode int, response []byte, duration time.Duration) { | 
					
						
							| 
									
										
										
										
											2025-08-27 22:19:19 +08:00
										 |  |  |  | 	e.responseLogger.Info(fmt.Sprintf("%s API响应", e.serviceName), | 
					
						
							| 
									
										
										
										
											2025-08-26 16:03:46 +08:00
										 |  |  |  | 		zap.String("service", e.serviceName), | 
					
						
							|  |  |  |  | 		zap.String("request_id", requestID), | 
					
						
							|  |  |  |  | 		zap.String("transaction_id", transactionID), | 
					
						
							|  |  |  |  | 		zap.String("api_code", apiCode), | 
					
						
							|  |  |  |  | 		zap.Int("status_code", statusCode), | 
					
						
							|  |  |  |  | 		zap.String("response", string(response)), | 
					
						
							|  |  |  |  | 		zap.Duration("duration", duration), | 
					
						
							|  |  |  |  | 		zap.String("timestamp", time.Now().Format(time.RFC3339)), | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // LogResponseWithID 记录包含响应ID的响应日志 | 
					
						
							|  |  |  |  | func (e *ExternalServiceLogger) LogResponseWithID(requestID, transactionID, apiCode string, statusCode int, response []byte, duration time.Duration, responseID string) { | 
					
						
							| 
									
										
										
										
											2025-08-27 22:19:19 +08:00
										 |  |  |  | 	e.responseLogger.Info(fmt.Sprintf("%s API响应", e.serviceName), | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | 		zap.String("service", e.serviceName), | 
					
						
							|  |  |  |  | 		zap.String("request_id", requestID), | 
					
						
							| 
									
										
										
										
											2025-08-26 16:03:46 +08:00
										 |  |  |  | 		zap.String("transaction_id", transactionID), | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | 		zap.String("api_code", apiCode), | 
					
						
							|  |  |  |  | 		zap.Int("status_code", statusCode), | 
					
						
							|  |  |  |  | 		zap.String("response", string(response)), | 
					
						
							|  |  |  |  | 		zap.Duration("duration", duration), | 
					
						
							| 
									
										
										
										
											2025-08-26 16:03:46 +08:00
										 |  |  |  | 		zap.String("response_id", responseID), | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | 		zap.String("timestamp", time.Now().Format(time.RFC3339)), | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // LogError 记录错误日志 | 
					
						
							| 
									
										
										
										
											2025-08-26 16:03:46 +08:00
										 |  |  |  | func (e *ExternalServiceLogger) LogError(requestID, transactionID, apiCode string, err error, params interface{}) { | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | 	e.logger.Error(fmt.Sprintf("%s API错误", e.serviceName), | 
					
						
							|  |  |  |  | 		zap.String("service", e.serviceName), | 
					
						
							|  |  |  |  | 		zap.String("request_id", requestID), | 
					
						
							| 
									
										
										
										
											2025-08-26 16:03:46 +08:00
										 |  |  |  | 		zap.String("transaction_id", transactionID), | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | 		zap.String("api_code", apiCode), | 
					
						
							|  |  |  |  | 		zap.Error(err), | 
					
						
							|  |  |  |  | 		zap.Any("params", params), | 
					
						
							|  |  |  |  | 		zap.String("timestamp", time.Now().Format(time.RFC3339)), | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-26 16:03:46 +08:00
										 |  |  |  | // LogErrorWithResponseID 记录包含响应ID的错误日志 | 
					
						
							|  |  |  |  | func (e *ExternalServiceLogger) LogErrorWithResponseID(requestID, transactionID, apiCode string, err error, params interface{}, responseID string) { | 
					
						
							|  |  |  |  | 	e.logger.Error(fmt.Sprintf("%s API错误", e.serviceName), | 
					
						
							|  |  |  |  | 		zap.String("service", e.serviceName), | 
					
						
							|  |  |  |  | 		zap.String("request_id", requestID), | 
					
						
							|  |  |  |  | 		zap.String("transaction_id", transactionID), | 
					
						
							|  |  |  |  | 		zap.String("api_code", apiCode), | 
					
						
							|  |  |  |  | 		zap.Error(err), | 
					
						
							|  |  |  |  | 		zap.Any("params", params), | 
					
						
							|  |  |  |  | 		zap.String("response_id", responseID), | 
					
						
							|  |  |  |  | 		zap.String("timestamp", time.Now().Format(time.RFC3339)), | 
					
						
							|  |  |  |  | 	) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | // LogInfo 记录信息日志 | 
					
						
							|  |  |  |  | func (e *ExternalServiceLogger) LogInfo(message string, fields ...zap.Field) { | 
					
						
							|  |  |  |  | 	allFields := []zap.Field{zap.String("service", e.serviceName)} | 
					
						
							|  |  |  |  | 	allFields = append(allFields, fields...) | 
					
						
							|  |  |  |  | 	e.logger.Info(message, allFields...) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // LogWarn 记录警告日志 | 
					
						
							|  |  |  |  | func (e *ExternalServiceLogger) LogWarn(message string, fields ...zap.Field) { | 
					
						
							|  |  |  |  | 	allFields := []zap.Field{zap.String("service", e.serviceName)} | 
					
						
							|  |  |  |  | 	allFields = append(allFields, fields...) | 
					
						
							|  |  |  |  | 	e.logger.Warn(message, allFields...) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // LogErrorWithFields 记录带字段的错误日志 | 
					
						
							|  |  |  |  | func (e *ExternalServiceLogger) LogErrorWithFields(message string, fields ...zap.Field) { | 
					
						
							|  |  |  |  | 	allFields := []zap.Field{zap.String("service", e.serviceName)} | 
					
						
							|  |  |  |  | 	allFields = append(allFields, fields...) | 
					
						
							|  |  |  |  | 	e.logger.Error(message, allFields...) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // Sync 同步日志 | 
					
						
							|  |  |  |  | func (e *ExternalServiceLogger) Sync() error { | 
					
						
							|  |  |  |  | 	return e.logger.Sync() | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // CleanupOldDateDirs 清理过期的日期目录 | 
					
						
							|  |  |  |  | func (e *ExternalServiceLogger) CleanupOldDateDirs() error { | 
					
						
							|  |  |  |  | 	if !e.config.UseDaily { | 
					
						
							|  |  |  |  | 		return nil | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	logDir := filepath.Join(e.config.LogDir, e.serviceName) | 
					
						
							| 
									
										
										
										
											2025-08-26 16:03:46 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | 	// 读取日志目录 | 
					
						
							|  |  |  |  | 	entries, err := os.ReadDir(logDir) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							|  |  |  |  | 		return fmt.Errorf("读取日志目录失败: %w", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 计算过期时间(基于配置的MaxAge) | 
					
						
							|  |  |  |  | 	maxAge := 28 // 默认28天 | 
					
						
							|  |  |  |  | 	if errorConfig, exists := e.config.LevelConfigs["error"]; exists && errorConfig.MaxAge > 0 { | 
					
						
							|  |  |  |  | 		maxAge = errorConfig.MaxAge | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-08-26 16:03:46 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-25 15:44:06 +08:00
										 |  |  |  | 	cutoffTime := time.Now().AddDate(0, 0, -maxAge) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	for _, entry := range entries { | 
					
						
							|  |  |  |  | 		if !entry.IsDir() { | 
					
						
							|  |  |  |  | 			continue | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		// 尝试解析目录名为日期 | 
					
						
							|  |  |  |  | 		dirName := entry.Name() | 
					
						
							|  |  |  |  | 		dirTime, err := time.Parse("2006-01-02", dirName) | 
					
						
							|  |  |  |  | 		if err != nil { | 
					
						
							|  |  |  |  | 			// 如果不是日期格式的目录,跳过 | 
					
						
							|  |  |  |  | 			continue | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		// 检查是否过期 | 
					
						
							|  |  |  |  | 		if dirTime.Before(cutoffTime) { | 
					
						
							|  |  |  |  | 			dirPath := filepath.Join(logDir, dirName) | 
					
						
							|  |  |  |  | 			if err := os.RemoveAll(dirPath); err != nil { | 
					
						
							|  |  |  |  | 				return fmt.Errorf("删除过期目录失败 %s: %w", dirPath, err) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // startCleanupTask 启动定时清理任务 | 
					
						
							|  |  |  |  | func (e *ExternalServiceLogger) startCleanupTask() { | 
					
						
							|  |  |  |  | 	// 每天凌晨2点执行清理 | 
					
						
							|  |  |  |  | 	ticker := time.NewTicker(24 * time.Hour) | 
					
						
							|  |  |  |  | 	defer ticker.Stop() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 等待到下一个凌晨2点 | 
					
						
							|  |  |  |  | 	now := time.Now() | 
					
						
							|  |  |  |  | 	next := time.Date(now.Year(), now.Month(), now.Day()+1, 2, 0, 0, 0, now.Location()) | 
					
						
							|  |  |  |  | 	time.Sleep(time.Until(next)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 立即执行一次清理 | 
					
						
							|  |  |  |  | 	if err := e.CleanupOldDateDirs(); err != nil { | 
					
						
							|  |  |  |  | 		// 记录清理错误(这里使用标准输出,因为logger可能还未初始化) | 
					
						
							|  |  |  |  | 		fmt.Printf("清理过期日志目录失败: %v\n", err) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// 定时执行清理 | 
					
						
							|  |  |  |  | 	for range ticker.C { | 
					
						
							|  |  |  |  | 		if err := e.CleanupOldDateDirs(); err != nil { | 
					
						
							|  |  |  |  | 			fmt.Printf("清理过期日志目录失败: %v\n", err) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | // GetServiceName 获取服务名称 | 
					
						
							|  |  |  |  | func (e *ExternalServiceLogger) GetServiceName() string { | 
					
						
							|  |  |  |  | 	return e.serviceName | 
					
						
							|  |  |  |  | } |