package mailx import ( "context" "log" ) // Logger 日志接口,可实现或适配任意日志库(如 zap、logrus、slog)。 // 通过 Manager.SetLogger 或 context 注入(WithLogger)后, // 各通道在发送成功/失败时会自动记录。 type Logger interface { Debugf(ctx context.Context, format string, args ...any) Infof(ctx context.Context, format string, args ...any) Warnf(ctx context.Context, format string, args ...any) Errorf(ctx context.Context, format string, args ...any) } // noopLogger 空实现,作为未注入日志器时的安全默认值 type noopLogger struct{} func (noopLogger) Debugf(context.Context, string, ...any) {} func (noopLogger) Infof(context.Context, string, ...any) {} func (noopLogger) Warnf(context.Context, string, ...any) {} func (noopLogger) Errorf(context.Context, string, ...any) {} // stdLogger 基于标准库 log 实现的 Logger type stdLogger struct{} func (stdLogger) Debugf(_ context.Context, format string, args ...any) { log.Printf("[debug] "+format, args...) } func (stdLogger) Infof(_ context.Context, format string, args ...any) { log.Printf("[info] "+format, args...) } func (stdLogger) Warnf(_ context.Context, format string, args ...any) { log.Printf("[warn] "+format, args...) } func (stdLogger) Errorf(_ context.Context, format string, args ...any) { log.Printf("[error] "+format, args...) } // StdLogger 返回一个基于标准库 log 的 Logger 实现。 // 若希望日志带行号/级别前缀,或接入 zap/logrus/slog 等,请自定义实现 Logger 接口。 func StdLogger() Logger { return stdLogger{} } // noop 返回一个空实现的 Logger,用于未注入时的默认值。 func noop() Logger { return noopLogger{} } // ctxKey 用于在 context 中存取 Logger 的私有键 type ctxKey struct{} // WithLogger 将日志器注入 context,通道发送时自动读取。 func WithLogger(ctx context.Context, l Logger) context.Context { return context.WithValue(ctx, ctxKey{}, l) } // LoggerFromContext 从 context 读取日志器;未注入时返回空实现(不输出任何日志)。 func LoggerFromContext(ctx context.Context) Logger { if l, ok := ctx.Value(ctxKey{}).(Logger); ok && l != nil { return l } return noop() }