ZapSmtp
Let's be real, who's regularly browsing through megabytes of log files? Wouldn't it be nice, if important messages
were delivered to you in time, and the log files just served the purpose of holding the details?
This package offers extended functionality for the zap logger, with the purpose
of handling (some) log messages via (optionally signed and/or encrypted) SMTP mails.
We use this package to notice critical issues fast, so we can roll out a fix, before the user pushes the same buttons
again. Yes, yes, alternatively, you can expand the turbine stack of your production environment
by deploying, configuring and maintaining additional log management software.
Installation
As Golang only supports plain text SMTP mails natively, OpenSSL has to be installed if encryption and/or signature is
to be enabled. Other than that a simple go get
is sufficient.
Usage
Because sending out a new mail for every single log message is not desirable in most cases, it is recommended to use
some kind of buffered Core. For this the delayedCore
provided in this package can be used.
func Exmaple() {
sink, errSink := smtp.NewWriteSyncCloser(
conf.Server,
conf.Port,
conf.Subject,
conf.Sender,
conf.Recipients,
conf.OpensslPath,
conf.SignatureCertPath,
conf.SignatureKeyPath,
conf.EncryptionCertPaths,
conf.TempDir,
)
if errSink != nil {
fmt.Printf("Initializing SMTP sink failed: %s\n", errSink)
return
}
defer func() {
if errClose := sink.Close(); errClose != nil {
fmt.Printf("Closing SMTP sink failed: %s\n", errClose)
}
}()
enc := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
core, errCore := cores.NewDelayedCore(zapcore.WarnLevel, enc, sink, zapcore.ErrorLevel, time.Minute*1, time.Second*5)
if errCore != nil {
fmt.Printf("Initializing SMTP core failed: %s\n", errCore)
return
}
logger := zap.New(core)
defer func() { _ = logger.Sync() }()
logger.Warn("Warn message, triggering email after 1 minute")
logger.Error("Error message, triggering email after 5 seconds")
}
Note that even though the writeSyncCloser
satisfies zap's Sink
interface it is not recommended using it with
RegisterSink
as this way only standard ioCores
can be used.
Another example can be found in ./examples
.
You can also visit Large-Scale Discovery to see it applied.
Best practices
- When possible the
writeSyncCloser
should be preferred over the writeSyncer
, as it will convert files only once and
keep a reference to the resulting files until Close
is called. - As encrypting and signing mails via OpenSSL is slow it is recommended to not log too frequently. This depends
heavily on your use case though.
- Email signature and encryption needs certificate and key files in PEM format. The
writeSyncer
(and writeSyncCloser
)
also allows for DER format and will convert them internally. It's advised though to use PEM format if possible.