CtxZap is a Go library that seamlessly integrates Uber's Zap logger with context.Context, allowing you to attach structured logging fields to contexts and automatically include them in all subsequent log entries.
- π Thread-Safe: Safe for concurrent use across goroutines
- π― Clean API: Intuitive methods that follow Go idioms
- π§ Flexible: Compatible with existing Zap loggers and middleware
go get github.com/algobardo/ctxzappackage main
import (
"context"
"github.com/algobardo/ctxzap"
"go.uber.org/zap"
)
func main() {
// Create a context-aware logger
logger := ctxzap.New(zap.NewProduction())
// Add fields to context
ctx := context.Background()
ctx = ctxzap.WithFields(ctx,
zap.String("request_id", "abc123"),
zap.String("user_id", "user456"),
)
// Log with context - fields are automatically included
logger.Info(ctx, "Processing user request",
zap.String("action", "update_profile"),
)
// Output: {"level":"info","msg":"Processing user request","request_id":"abc123","user_id":"user456","action":"update_profile"}
}// Create a new context-aware logger from existing zap logger
logger := ctxzap.New(zapLogger)// Add fields to context
ctx = ctxzap.WithFields(ctx,
zap.String("key", "value"),
zap.Int("count", 42),
)
// Fields are cumulative - add more fields later
ctx = ctxzap.WithFields(ctx, zap.Bool("authenticated", true))// All standard log levels are supported
logger.Debug(ctx, "Debug message", extraFields...)
logger.Info(ctx, "Info message", extraFields...)
logger.Warn(ctx, "Warning message", extraFields...)
logger.Error(ctx, "Error message", extraFields...)// Get all fields from context (useful for middleware)
fields := ctxzap.FieldsFromContext(ctx)| Feature | CtxZap | Zax |
|---|---|---|
| Store fields in context | β | β |
| Logger wrapper methods | β | β |
| Direct zap integration | β | β |
| Field deduplication | β | β |
| Zero allocation for empty ctx | β | β |
When to use CtxZap over Zax:
- You prefer methods like
logger.Info(ctx, msg)overlogger.With(zax.Get(ctx)...).Info(msg)
| Feature | CtxZap | grpc-ecosystem/ctxzap |
|---|---|---|
| Store fields only | β | β (stores logger) |
| gRPC integration | β | β |
| Standalone usage | β | β |
| Field management | Advanced | Basic |
When to use CtxZap over grpc-ecosystem/ctxzap:
- You're not using gRPC or don't need gRPC-specific features
- You need more control over field management
func LoggingMiddleware(logger *ctxzap.Logger) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Add request metadata to context
ctx := r.Context()
ctx = ctxzap.WithFields(ctx,
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.String("request_id", generateRequestID()),
)
// Log request
logger.Info(ctx, "Handling request")
// Pass context to next handler
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}type UserService struct {
logger *ctxzap.Logger
db *sql.DB
}
func (s *UserService) GetUser(ctx context.Context, userID string) (*User, error) {
// Add service-specific fields
ctx = ctxzap.WithFields(ctx,
zap.String("service", "user"),
zap.String("operation", "get_user"),
)
s.logger.Debug(ctx, "Fetching user from database")
user, err := s.db.QueryUser(ctx, userID)
if err != nil {
s.logger.Error(ctx, "Failed to fetch user", zap.Error(err))
return nil, err
}
s.logger.Info(ctx, "Successfully fetched user")
return user, nil
}- Add fields early: Add common fields (request ID, user ID) at the entry point of your application
- Use field keys consistently: Establish naming conventions for field keys
- Don't store sensitive data: Avoid putting passwords or tokens in context fields
- Keep contexts short-lived: Don't store contexts longer than necessary
This project uses golangci-lint to ensure code quality and consistency. Before committing your changes, make sure to run the following:
# Install golangci-lint
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# Make sure it's in your PATH
export PATH=$PATH:$HOME/go/bin# Run all linters
golangci-lint run
# Automatically fix some issues
golangci-lint run --fixThe project is configured with multiple linters including:
gofmt- Go formattinggoimports- Import formatting and organizationgovet- Go vet reports suspicious constructsstaticcheck- Advanced static analysis- And many more (see
.golangci.ymlfor full configuration)
To ensure code is always formatted before committing, you can set up a git pre-commit hook:
# Create pre-commit hook
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
# Run golangci-lint before commit
golangci-lint run
# Exit with non-zero status if linting fails
if [ $? -ne 0 ]; then
echo "Linting failed. Please fix the issues before committing."
exit 1
fi
EOF
# Make it executable
chmod +x .git/hooks/pre-commitContributions are welcome! Please ensure your code passes all linting checks before submitting a Pull Request.
MIT License - see LICENSE file for details