mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
260d2571c1
Co-authored-by: Daniel Weiße <66256922+daniel-weisse@users.noreply.github.com> Co-authored-by: 3u13r <lc@edgeless.systems>
188 lines
6.1 KiB
Go
188 lines
6.1 KiB
Go
/*
|
|
Package logger provides logging functionality for Constellation services.
|
|
It is a thin wrapper around the zap package, providing a consistent interface for logging.
|
|
Use this package to implement logging for your Constellation services.
|
|
|
|
Usage
|
|
|
|
1. Create a logger using New().
|
|
|
|
2. Defer the Sync() method to ensure that all log entries are flushed.
|
|
|
|
3. Use the Debugf(), Infof(), Warnf(), Errorf(), and Fatalf() methods depending on the level of logging you need.
|
|
|
|
4. Use the Named() method to create a named child logger.
|
|
|
|
5. Use the With() method to create a child logger with structured context.
|
|
This can also be used to add context to a single log message:
|
|
|
|
logger.With(zap.String("key", "value")).Infof("log message")
|
|
|
|
Log Levels
|
|
|
|
Use Debugf() to log low level and detailed information that is useful for debugging.
|
|
|
|
Use Infof() to log general information. This method is correct for most logging purposes.
|
|
|
|
Use Warnf() to log information that may indicate unwanted behavior, but is not an error.
|
|
|
|
Use Errorf() to log information about any errors that occurred.
|
|
|
|
Use Fatalf() to log information about any errors that occurred and then exit the program.
|
|
*/
|
|
package logger
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"testing"
|
|
|
|
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
|
grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
|
|
grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
"go.uber.org/zap/zaptest"
|
|
"google.golang.org/grpc"
|
|
)
|
|
|
|
// LogType indicates the output encoding of the log.
|
|
type LogType int
|
|
|
|
const (
|
|
// JSONLog encodes logs in JSON format.
|
|
JSONLog LogType = iota
|
|
// PlainLog encodes logs as human readable text.
|
|
PlainLog
|
|
)
|
|
|
|
// Logger is a wrapper for zap logger.
|
|
// The purpose is to provide a simple interface for logging with sensible defaults.
|
|
type Logger struct {
|
|
logger *zap.SugaredLogger
|
|
}
|
|
|
|
// New creates a new Logger.
|
|
// Set name to an empty string to create an unnamed logger.
|
|
func New(logType LogType, logLevel zapcore.Level) *Logger {
|
|
encoderCfg := zap.NewProductionEncoderConfig()
|
|
encoderCfg.StacktraceKey = zapcore.OmitKey
|
|
encoderCfg.EncodeLevel = zapcore.CapitalLevelEncoder
|
|
encoderCfg.EncodeTime = zapcore.RFC3339TimeEncoder
|
|
|
|
var encoder zapcore.Encoder
|
|
if logType == PlainLog {
|
|
encoder = zapcore.NewConsoleEncoder(encoderCfg)
|
|
} else {
|
|
encoder = zapcore.NewJSONEncoder(encoderCfg)
|
|
}
|
|
|
|
logCore := zapcore.NewCore(encoder, zapcore.Lock(os.Stderr), zap.NewAtomicLevelAt(logLevel))
|
|
|
|
logger := zap.New(
|
|
logCore,
|
|
zap.AddCaller(), // add the file and line number of the logging call
|
|
zap.AddCallerSkip(1), // skip the first caller so that we don't only see this package as the caller
|
|
)
|
|
|
|
return &Logger{logger: logger.Sugar()}
|
|
}
|
|
|
|
// NewTest creates a logger for unit / integration tests.
|
|
func NewTest(t *testing.T) *Logger {
|
|
return &Logger{
|
|
logger: zaptest.NewLogger(t).Sugar().Named(fmt.Sprintf("%q", t.Name())),
|
|
}
|
|
}
|
|
|
|
// Debugf logs a message at Debug level.
|
|
// Debug logs are typically voluminous, and contain detailed information on the flow of execution.
|
|
func (l *Logger) Debugf(format string, args ...any) {
|
|
l.logger.Debugf(format, args...)
|
|
}
|
|
|
|
// Infof logs a message at Info level.
|
|
// This is the default logging priority and should be used for all normal messages.
|
|
func (l *Logger) Infof(format string, args ...any) {
|
|
l.logger.Infof(format, args...)
|
|
}
|
|
|
|
// Warnf logs a message at Warn level.
|
|
// Warn logs are more important than Info, but they don't need human review or necessarily indicate an error.
|
|
func (l *Logger) Warnf(format string, args ...any) {
|
|
l.logger.Warnf(format, args...)
|
|
}
|
|
|
|
// Errorf logs a message at Error level.
|
|
// Error logs are high priority and indicate something has gone wrong.
|
|
func (l *Logger) Errorf(format string, args ...any) {
|
|
l.logger.Errorf(format, args...)
|
|
}
|
|
|
|
// Fatalf logs the message and then calls os.Exit(1).
|
|
// Use this to exit your program when a fatal error occurs.
|
|
func (l *Logger) Fatalf(format string, args ...any) {
|
|
l.logger.Fatalf(format, args...)
|
|
}
|
|
|
|
// Sync flushes any buffered log entries.
|
|
// Applications should take care to call Sync before exiting.
|
|
func (l *Logger) Sync() {
|
|
_ = l.logger.Sync()
|
|
}
|
|
|
|
// WithIncreasedLevel returns a logger with increased logging level.
|
|
func (l *Logger) WithIncreasedLevel(level zapcore.Level) *Logger {
|
|
return &Logger{logger: l.getZapLogger().WithOptions(zap.IncreaseLevel(level)).Sugar()}
|
|
}
|
|
|
|
// With returns a logger with structured context.
|
|
func (l *Logger) With(fields ...any) *Logger {
|
|
return &Logger{logger: l.logger.With(fields...)}
|
|
}
|
|
|
|
// Named returns a named logger.
|
|
func (l *Logger) Named(name string) *Logger {
|
|
return &Logger{logger: l.logger.Named(name)}
|
|
}
|
|
|
|
// ReplaceGRPCLogger replaces grpc's internal logger with the given logger.
|
|
func (l *Logger) ReplaceGRPCLogger() {
|
|
grpc_zap.ReplaceGrpcLoggerV2(l.logger.Desugar())
|
|
}
|
|
|
|
// GetServerUnaryInterceptor returns a gRPC server option for intercepting unary gRPC logs.
|
|
func (l *Logger) GetServerUnaryInterceptor() grpc.ServerOption {
|
|
return grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
|
|
grpc_ctxtags.UnaryServerInterceptor(),
|
|
grpc_zap.UnaryServerInterceptor(l.getZapLogger()),
|
|
))
|
|
}
|
|
|
|
// GetServerStreamInterceptor returns a gRPC server option for intercepting streaming gRPC logs.
|
|
func (l *Logger) GetServerStreamInterceptor() grpc.ServerOption {
|
|
return grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
|
|
grpc_ctxtags.StreamServerInterceptor(),
|
|
grpc_zap.StreamServerInterceptor(l.getZapLogger()),
|
|
))
|
|
}
|
|
|
|
// GetClientUnaryInterceptor returns a gRPC client option for intercepting unary gRPC logs.
|
|
func (l *Logger) GetClientUnaryInterceptor() grpc.DialOption {
|
|
return grpc.WithUnaryInterceptor(grpc_middleware.ChainUnaryClient(
|
|
grpc_zap.UnaryClientInterceptor(l.getZapLogger()),
|
|
))
|
|
}
|
|
|
|
// GetClientStreamInterceptor returns a gRPC client option for intercepting stream gRPC logs.
|
|
func (l *Logger) GetClientStreamInterceptor() grpc.DialOption {
|
|
return grpc.WithStreamInterceptor(grpc_middleware.ChainStreamClient(
|
|
grpc_zap.StreamClientInterceptor(l.getZapLogger()),
|
|
))
|
|
}
|
|
|
|
// getZapLogger returns the underlying zap logger.
|
|
func (l *Logger) getZapLogger() *zap.Logger {
|
|
return l.logger.Desugar()
|
|
}
|