talos/pkg/logging/zap.go
Alexey Palazhchenko e60469a38c
feat: initial support for JSON logging
Hook into logging machinery.

Signed-off-by: Alexey Palazhchenko <alexey.palazhchenko@talos-systems.com>
2021-10-16 16:46:59 +00:00

142 lines
3.2 KiB
Go

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package logging
import (
"io"
"log"
"strings"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
// LogWriter is a wrapper around zap.Logger that implements io.Writer interface.
type LogWriter struct {
dest *zap.Logger
level zapcore.Level
}
// NewWriter creates new log zap log writer.
func NewWriter(l *zap.Logger, level zapcore.Level) io.Writer {
return &LogWriter{
dest: l,
level: level,
}
}
// Write implements io.Writer interface.
func (lw *LogWriter) Write(line []byte) (int, error) {
checked := lw.dest.Check(lw.level, strings.TrimSpace(string(line)))
if checked == nil {
return 0, nil
}
checked.Write()
return len(line), nil
}
// logWrapper wraps around standard logger.
type logWrapper struct {
log *log.Logger
}
// Write implements io.Writer interface.
func (lw *logWrapper) Write(line []byte) (int, error) {
if lw.log == nil {
log.Print(string(line))
} else {
lw.log.Print(string(line))
}
return len(line), nil
}
// StdWriter creates a sync writer that writes all logs to the std logger.
var StdWriter = &logWrapper{nil}
// LogDestination defines logging destination Config.
type LogDestination struct {
// Level log level.
level zapcore.LevelEnabler
writer io.Writer
config zapcore.EncoderConfig
}
// EncoderOption defines a log destination encoder config setter.
type EncoderOption func(config *zapcore.EncoderConfig)
// WithoutTimestamp disables timestamp.
func WithoutTimestamp() EncoderOption {
return func(config *zapcore.EncoderConfig) {
config.EncodeTime = nil
}
}
// WithoutLogLevels disable log level.
func WithoutLogLevels() EncoderOption {
return func(config *zapcore.EncoderConfig) {
config.EncodeLevel = nil
}
}
// WithColoredLevels enables log level colored output.
func WithColoredLevels() EncoderOption {
return func(config *zapcore.EncoderConfig) {
config.EncodeLevel = zapcore.CapitalColorLevelEncoder
}
}
// NewLogDestination creates new log destination.
func NewLogDestination(writer io.Writer, logLevel zapcore.LevelEnabler, options ...EncoderOption) *LogDestination {
config := zap.NewDevelopmentEncoderConfig()
config.ConsoleSeparator = " "
config.StacktraceKey = "error"
for _, option := range options {
option(&config)
}
return &LogDestination{
level: logLevel,
config: config,
writer: writer,
}
}
// Wrap is a simple helper to wrap io.Writer with default arguments.
func Wrap(writer io.Writer) *zap.Logger {
return ZapLogger(
NewLogDestination(writer, zapcore.DebugLevel),
)
}
// ZapLogger creates new default Zap Logger.
func ZapLogger(dests ...*LogDestination) *zap.Logger {
if len(dests) == 0 {
panic("at least one writer must be defined")
}
cores := []zapcore.Core{}
for _, dest := range dests {
consoleEncoder := zapcore.NewConsoleEncoder(dest.config)
cores = append(cores, zapcore.NewCore(consoleEncoder, zapcore.AddSync(dest.writer), dest.level))
}
core := zapcore.NewTee(cores...)
logger := zap.New(core)
return logger
}
// Component helper for creating zap.Field.
func Component(name string) zapcore.Field {
return zap.String("component", name)
}