Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
module github.com/nutcase/gomian

go 1.24

require go.uber.org/zap v1.27.0

require go.uber.org/multierr v1.10.0 // indirect
14 changes: 14 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
88 changes: 88 additions & 0 deletions logging/cb_logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package logging

import (
"go.uber.org/zap"
"time"
)

type CircuitBreakerLogger struct {
logger *zap.Logger
}

func NewCircuitBreakerLogger() *CircuitBreakerLogger {
return &CircuitBreakerLogger{
logger: Logger().With(zap.String("component", "circuit_breaker")),
}
}

func (l *CircuitBreakerLogger) LogStateChange(name string, from, to string) {
l.logger.Info("circuit breaker state changed",
zap.String("circuit", name),
zap.String("from_state", from),
zap.String("to_state", to),
zap.Time("timestamp", time.Now()),
)
}

func (l *CircuitBreakerLogger) LogTrip(name string, err error) {
fields := []zap.Field{
zap.String("circuit", name),
zap.Time("timestamp", time.Now()),
}

if err != nil {
fields = append(fields, zap.Error(err))
}

l.logger.Warn("circuit breaker tripped", fields...)
}

func (l *CircuitBreakerLogger) LogReset(name string) {
l.logger.Info("circuit breaker reset",
zap.String("circuit", name),
zap.Time("timestamp", time.Now()),
)
}

func (l *CircuitBreakerLogger) LogSuccess(name string) {
l.logger.Debug("circuit breaker request succeeded",
zap.String("circuit", name),
zap.Time("timestamp", time.Now()),
)
}

func (l *CircuitBreakerLogger) LogFailure(name string, err error) {
fields := []zap.Field{
zap.String("circuit", name),
zap.Time("timestamp", time.Now()),
}

if err != nil {
fields = append(fields, zap.Error(err))
}

l.logger.Debug("circuit breaker request failed", fields...)
}

func (l *CircuitBreakerLogger) LogRejection(name string) {
l.logger.Debug("circuit breaker request rejected",
zap.String("circuit", name),
zap.Time("timestamp", time.Now()),
)
}

func (l *CircuitBreakerLogger) LogMetrics(name string, state string, totalRequests uint64,
totalFailures uint64, consecutiveFailures uint64, consecutiveSuccesses uint64,
timeInState time.Duration) {

l.logger.Debug("circuit breaker metrics",
zap.String("circuit", name),
zap.String("state", state),
zap.Uint64("total_requests", totalRequests),
zap.Uint64("total_failures", totalFailures),
zap.Uint64("consecutive_failures", consecutiveFailures),
zap.Uint64("consecutive_successes", consecutiveSuccesses),
zap.Duration("time_in_state", timeInState),
zap.Time("timestamp", time.Now()),
)
}
128 changes: 128 additions & 0 deletions logging/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package logging

import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"sync"
)

var (
defaultLogger *zap.Logger
loggerMu sync.RWMutex
initialized bool
)

type LogLevel string

const (
LogLevelDebug LogLevel = "debug"
LogLevelInfo LogLevel = "info"
LogLevelWarn LogLevel = "warn"
LogLevelError LogLevel = "error"
)

type Config struct {
Level LogLevel

Development bool

Encoding string
}

func DefaultConfig() Config {
return Config{
Level: LogLevelInfo,
Development: false,
Encoding: "json",
}
}

func Initialize(config Config) error {
loggerMu.Lock()
defer loggerMu.Unlock()

var level zapcore.Level
switch config.Level {
case LogLevelDebug:
level = zapcore.DebugLevel
case LogLevelInfo:
level = zapcore.InfoLevel
case LogLevelWarn:
level = zapcore.WarnLevel
case LogLevelError:
level = zapcore.ErrorLevel
default:
level = zapcore.InfoLevel
}

zapConfig := zap.Config{
Level: zap.NewAtomicLevelAt(level),
Development: config.Development,
Encoding: config.Encoding,
EncoderConfig: zap.NewProductionEncoderConfig(),
OutputPaths: []string{"stdout"},
ErrorOutputPaths: []string{"stderr"},
}

if config.Development {
zapConfig.EncoderConfig = zap.NewDevelopmentEncoderConfig()
} else {
zapConfig.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
}

logger, err := zapConfig.Build()
if err != nil {
return err
}

defaultLogger = logger
initialized = true
return nil
}

func ensureInitialized() {
loggerMu.RLock()
init := initialized
loggerMu.RUnlock()

if !init {
_ = Initialize(DefaultConfig())
}
}

func Logger() *zap.Logger {
ensureInitialized()
loggerMu.RLock()
defer loggerMu.RUnlock()
return defaultLogger
}

func With(fields ...zap.Field) *zap.Logger {
return Logger().With(fields...)
}

func Debug(msg string, fields ...zap.Field) {
Logger().Debug(msg, fields...)
}

func Info(msg string, fields ...zap.Field) {
Logger().Info(msg, fields...)
}

func Warn(msg string, fields ...zap.Field) {
Logger().Warn(msg, fields...)
}

func Error(msg string, fields ...zap.Field) {
Logger().Error(msg, fields...)
}

func Sync() error {
loggerMu.RLock()
defer loggerMu.RUnlock()

if defaultLogger != nil {
return defaultLogger.Sync()
}
return nil
}
Loading