Kratos provides a structured logging system that supports multiple output targets, log levels, and context integration.
Logger Interface
type Logger interface {
Log ( level Level , keyvals ... any ) error
}
The logger interface is intentionally simple - it accepts a log level and key-value pairs for structured logging.
Creating a Logger
Standard Logger
Uses Go’s standard log package:
import " github.com/go-kratos/kratos/v2/log "
logger := log . NewStdLogger ( os . Stdout )
With Fields
Add persistent fields to logger:
import " github.com/go-kratos/kratos/v2/log "
logger := log . With (
log . NewStdLogger ( os . Stdout ),
"service" , "user-service" ,
"version" , "v1.0.0" ,
)
// All logs will include these fields
logger . Log ( log . LevelInfo , "msg" , "server started" )
// Output: level=info service=user-service version=v1.0.0 msg="server started"
With Context
Attach logger to context:
import " github.com/go-kratos/kratos/v2/log "
logger := log . NewStdLogger ( os . Stdout )
ctxLogger := log . WithContext ( ctx , logger )
// Logger is now context-aware
ctxLogger . Log ( log . LevelInfo , "msg" , "processing request" )
Log Levels
const (
LevelDebug Level = - 1
LevelInfo Level = 0
LevelWarn Level = 1
LevelError Level = 2
LevelFatal Level = 3
)
Level Filtering
Filter logs by minimum level:
import " github.com/go-kratos/kratos/v2/log "
logger := log . NewStdLogger ( os . Stdout )
filteredLogger := log . NewFilter ( logger , log . FilterLevel ( log . LevelWarn ))
// Only warnings, errors, and fatal logs will be output
filteredLogger . Log ( log . LevelInfo , "msg" , "not shown" )
filteredLogger . Log ( log . LevelWarn , "msg" , "shown" )
Helper
The Helper provides convenient methods for different log levels:
import " github.com/go-kratos/kratos/v2/log "
logger := log . NewStdLogger ( os . Stdout )
helper := log . NewHelper ( logger )
// String formatting
helper . Debug ( "Debug message" )
helper . Info ( "Info message" )
helper . Warn ( "Warning message" )
helper . Error ( "Error message" )
// Printf-style formatting
helper . Infof ( "User %s logged in" , username )
helper . Errorf ( "Failed to connect: %v " , err )
// Structured logging (key-value pairs)
helper . Infow ( "msg" , "user logged in" , "user_id" , 123 , "ip" , "127.0.0.1" )
Helper Methods
Debug-level logging for detailed debugging information
Info-level logging for general informational messages
Warn-level logging for warning messages
Error-level logging for error messages
Fatal-level logging - logs message and calls os.Exit(1)
Context-Aware Helper
helper := log . NewHelper ( logger )
// Create context-aware helper
ctxHelper := helper . WithContext ( ctx )
// Logs include context values
ctxHelper . Info ( "Processing request" )
Global Logger
Kratos provides a global logger for convenience:
import " github.com/go-kratos/kratos/v2/log "
// Set global logger
logger := log . NewStdLogger ( os . Stdout )
log . SetLogger ( logger )
// Use global helper functions
log . Info ( "Application started" )
log . Infof ( "Server listening on %s " , addr )
log . Errorw ( "msg" , "failed to connect" , "error" , err )
Global Helper Functions
log . Debug ( a ... any )
log . Debugf ( format string , a ... any )
log . Debugw ( keyvals ... any )
log . Info ( a ... any )
log . Infof ( format string , a ... any )
log . Infow ( keyvals ... any )
log . Warn ( a ... any )
log . Warnf ( format string , a ... any )
log . Warnw ( keyvals ... any )
log . Error ( a ... any )
log . Errorf ( format string , a ... any )
log . Errorw ( keyvals ... any )
log . Fatal ( a ... any )
log . Fatalf ( format string , a ... any )
log . Fatalw ( keyvals ... any )
Custom Logger Implementation
Implement the Logger interface for custom backends:
import (
" github.com/go-kratos/kratos/v2/log "
" go.uber.org/zap "
)
type ZapLogger struct {
logger * zap . Logger
}
func ( l * ZapLogger ) Log ( level log . Level , keyvals ... interface {}) error {
if len ( keyvals ) == 0 {
return nil
}
if len ( keyvals ) % 2 != 0 {
keyvals = append ( keyvals , "" )
}
fields := make ([] zap . Field , 0 , len ( keyvals ) / 2 )
for i := 0 ; i < len ( keyvals ); i += 2 {
fields = append ( fields , zap . Any ( fmt . Sprint ( keyvals [ i ]), keyvals [ i + 1 ]))
}
switch level {
case log . LevelDebug :
l . logger . Debug ( "" , fields ... )
case log . LevelInfo :
l . logger . Info ( "" , fields ... )
case log . LevelWarn :
l . logger . Warn ( "" , fields ... )
case log . LevelError :
l . logger . Error ( "" , fields ... )
case log . LevelFatal :
l . logger . Fatal ( "" , fields ... )
}
return nil
}
// Usage
zapLogger , _ := zap . NewProduction ()
logger := & ZapLogger { logger : zapLogger }
log . SetLogger ( logger )
Valuer Functions
Dynamic values computed at log time:
import " github.com/go-kratos/kratos/v2/log "
// Create a valuer that returns current timestamp
timestampValuer := func ( ctx context . Context ) interface {} {
return time . Now (). Format ( time . RFC3339 )
}
logger := log . With (
log . NewStdLogger ( os . Stdout ),
"ts" , log . Valuer ( timestampValuer ),
"caller" , log . DefaultCaller ,
)
// Each log will have fresh timestamp and caller info
Filtering
Level Filter
import " github.com/go-kratos/kratos/v2/log "
logger := log . NewFilter (
log . NewStdLogger ( os . Stdout ),
log . FilterLevel ( log . LevelInfo ), // Only Info and above
)
Key Filter
Filter out specific keys from logs:
import " github.com/go-kratos/kratos/v2/log "
logger := log . NewFilter (
log . NewStdLogger ( os . Stdout ),
log . FilterKey ( "password" , "secret" ), // Remove these keys
)
// password and secret fields won't appear in logs
logger . Log ( log . LevelInfo , "username" , "admin" , "password" , "***" )
// Output: level=info username=admin
Custom Filter
import " github.com/go-kratos/kratos/v2/log "
func myFilter ( level log . Level , keyvals ... interface {}) bool {
// Custom filtering logic
return level >= log . LevelWarn
}
logger := log . NewFilter (
log . NewStdLogger ( os . Stdout ),
log . FilterFunc ( myFilter ),
)
Complete Example
package main
import (
" context "
" os "
" github.com/go-kratos/kratos/v2/log "
)
func main () {
// Create base logger
logger := log . NewStdLogger ( os . Stdout )
// Add persistent fields
logger = log . With ( logger ,
"service" , "my-service" ,
"version" , "v1.0.0" ,
"env" , "production" ,
)
// Apply filtering
logger = log . NewFilter ( logger ,
log . FilterLevel ( log . LevelInfo ),
log . FilterKey ( "password" , "token" ),
)
// Set as global logger
log . SetLogger ( logger )
// Create helper
helper := log . NewHelper ( logger )
// Use helper for logging
helper . Info ( "Application started" )
helper . Infof ( "Server listening on %s " , ":8000" )
// Structured logging
helper . Infow (
"msg" , "user logged in" ,
"user_id" , 123 ,
"ip" , "127.0.0.1" ,
)
// Context-aware logging
ctx := context . Background ()
ctxHelper := helper . WithContext ( ctx )
ctxHelper . Info ( "Processing request" )
// Error logging
if err := doSomething (); err != nil {
helper . Errorw ( "msg" , "operation failed" , "error" , err )
}
}
func doSomething () error {
return nil
}
Integration with Middleware
import (
" github.com/go-kratos/kratos/v2/log "
" github.com/go-kratos/kratos/v2/middleware/logging "
)
logger := log . NewStdLogger ( os . Stdout )
// HTTP Server
httpSrv := http . NewServer (
http . Middleware (
logging . Server ( logger ),
),
)
// gRPC Server
grpcSrv := grpc . NewServer (
grpc . Middleware (
logging . Server ( logger ),
),
)
Best Practices
Prefer key-value pairs over formatted strings for better parsing and searching.
Use DEBUG for detailed debugging, INFO for general messages, WARN for warnings, ERROR for errors.
Use log.With() to add persistent fields like service name, version, environment.
Use key filters to prevent logging passwords, tokens, and other sensitive information.
Use Helper for Convenience
The Helper provides convenient methods while maintaining structured logging.
Only use Fatal in main application code, never in libraries.
Middleware Logging middleware
Config Configure log levels
Transport Access transport info in logs