feat: Add structured logging with logrus and configurable output formats

- Add sirupsen/logrus v1.9.4 dependency to go.mod
- Add logging package with global Logger instance
- Add Config struct with Level, Format, and Output fields
- Add DefaultConfig with LOG_LEVEL, LOG_FORMAT, and LOG_OUTPUT environment variables
- Add Init function with level parsing, JSON/text formatter selection, and stdout/stderr output
- Add InitWithDefaults helper function
- Add WithField, WithFields, and WithError helper
This commit is contained in:
nutcas3
2026-04-25 06:19:48 +03:00
parent b714fa8382
commit 715417c0eb
3 changed files with 144 additions and 0 deletions
+1
View File
@@ -154,6 +154,7 @@ require (
github.com/quic-go/qpack v0.6.0 // indirect
github.com/quic-go/quic-go v0.59.0 // indirect
github.com/rabbitmq/amqp091-go v1.11.0
github.com/sirupsen/logrus v1.9.4
github.com/stripe/stripe-go/v82 v82.5.1
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.3.1 // indirect
+2
View File
@@ -391,6 +391,8 @@ github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/sosodev/duration v1.4.0 h1:35ed0KiVFriGHHzZZJaZLgmTEEICIyt8Sx0RQfj9IjE=
github.com/sosodev/duration v1.4.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
+141
View File
@@ -0,0 +1,141 @@
package logging
import (
"os"
"time"
"github.com/sirupsen/logrus"
)
var Logger *logrus.Logger
// Config holds logging configuration
type Config struct {
Level string
Format string // "json" or "text"
Output string // "stdout" or "stderr"
}
// DefaultConfig returns default logging configuration
func DefaultConfig() Config {
return Config{
Level: os.Getenv("LOG_LEVEL"),
Format: os.Getenv("LOG_FORMAT"),
Output: os.Getenv("LOG_OUTPUT"),
}
}
// Init initializes the global logger with the given configuration
func Init(config Config) error {
Logger = logrus.New()
// Set log level
if config.Level == "" {
config.Level = "info"
}
level, err := logrus.ParseLevel(config.Level)
if err != nil {
level = logrus.InfoLevel
}
Logger.SetLevel(level)
// Set log format
if config.Format == "" {
config.Format = "json"
}
if config.Format == "json" {
Logger.SetFormatter(&logrus.JSONFormatter{
TimestampFormat: time.RFC3339,
FieldMap: logrus.FieldMap{
logrus.FieldKeyTime: "timestamp",
logrus.FieldKeyLevel: "level",
logrus.FieldKeyMsg: "message",
logrus.FieldKeyFunc: "function",
},
})
} else {
Logger.SetFormatter(&logrus.TextFormatter{
TimestampFormat: time.RFC3339,
FullTimestamp: true,
})
}
// Set output
if config.Output == "" || config.Output == "stdout" {
Logger.SetOutput(os.Stdout)
} else {
Logger.SetOutput(os.Stderr)
}
return nil
}
// InitWithDefaults initializes the global logger with default configuration
func InitWithDefaults() error {
return Init(DefaultConfig())
}
// WithField returns a logger with a single field
func WithField(key string, value interface{}) *logrus.Entry {
return Logger.WithField(key, value)
}
// WithFields returns a logger with multiple fields
func WithFields(fields logrus.Fields) *logrus.Entry {
return Logger.WithFields(fields)
}
// WithError returns a logger with an error field
func WithError(err error) *logrus.Entry {
return Logger.WithError(err)
}
// Info logs an info message
func Info(args ...interface{}) {
Logger.Info(args...)
}
// Infof logs a formatted info message
func Infof(format string, args ...interface{}) {
Logger.Infof(format, args...)
}
// Warn logs a warning message
func Warn(args ...interface{}) {
Logger.Warn(args...)
}
// Warnf logs a formatted warning message
func Warnf(format string, args ...interface{}) {
Logger.Warnf(format, args...)
}
// Error logs an error message
func Error(args ...interface{}) {
Logger.Error(args...)
}
// Errorf logs a formatted error message
func Errorf(format string, args ...interface{}) {
Logger.Errorf(format, args...)
}
// Fatal logs a fatal message and exits
func Fatal(args ...interface{}) {
Logger.Fatal(args...)
}
// Fatalf logs a formatted fatal message and exits
func Fatalf(format string, args ...interface{}) {
Logger.Fatalf(format, args...)
}
// Debug logs a debug message
func Debug(args ...interface{}) {
Logger.Debug(args...)
}
// Debugf logs a formatted debug message
func Debugf(format string, args ...interface{}) {
Logger.Debugf(format, args...)
}