Skip to main content
Kratos provides a structured logging system that supports multiple output targets, log levels, and context integration.

Logger Interface

log/log.go:12-14
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:
log/log.go:34-48
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:
log/log.go:52-65
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

log/level.go
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:
log/helper.go:45-56
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/Debugf/Debugw
LevelDebug
Debug-level logging for detailed debugging information
Info/Infof/Infow
LevelInfo
Info-level logging for general informational messages
Warn/Warnf/Warnw
LevelWarn
Warn-level logging for warning messages
Error/Errorf/Errorw
LevelError
Error-level logging for error messages
Fatal/Fatalf/Fatalw
LevelFatal
Fatal-level logging - logs message and calls os.Exit(1)

Context-Aware Helper

log/helper.go:58-67
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.
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

Errors

Error handling

Transport

Access transport info in logs

Build docs developers (and LLMs) love