Skip to content

Compliance-grade structured logging for Go — with JSON output, automatic secret redaction, trace propagation, tamper-evident hashing, and flexible hooks (file, Loki, Kafka, S3).

License

Notifications You must be signed in to change notification settings

LowerPlane/logx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LogX - High-Performance Go Logging Library

LogX is a fast, secure, and compliance-ready logging library for Go applications. Built with security-first, compliance-aware, developer-friendly, and performance-optimized principles, LogX is the ideal choice for modern production applications that need to protect sensitive data while maintaining exceptional performance.

Core Principles

LogX is built on four foundational pillars:

🔐 Security First

  • 🛡️ Built-in Sensitive Data Protection: Automatically detects and redacts passwords, API keys, credit cards, SSNs, AWS keys, and more
  • 🔒 Secret Wrappers: Type-safe wrappers that guarantee sensitive data is never exposed in logs
  • 🎯 Field & Message Redaction: Flexible redaction rules with custom patterns and regex support
  • ✅ Compliance-Ready: Pre-configured patterns for PCI-DSS, GDPR, HIPAA, and other regulatory requirements

📋 Compliance Aware

  • 🏛️ Regulatory Standards: Built-in support for PCI-DSS, GDPR, HIPAA, and SOC 2 compliance requirements
  • 📝 Audit Trail: Complete logging with trace/span IDs for forensic analysis and compliance auditing
  • 🔍 Data Masking: Selective field masking to meet data privacy regulations
  • ⚙️ Environment-Based Controls: Different redaction rules for development, staging, and production environments

👨‍💻 Developer Friendly

  • 📊 Structured Logging: Intuitive key-value fields and JSON output
  • 🔗 Context Integration: Seamless integration with Go context for distributed tracing
  • 🪝 Extensible Hooks: Built-in integrations for DataDog, New Relic, Loggly, Atatus, and custom endpoints
  • 🎨 Flexible Formatting: Multiple output formats (JSON, Console) with customizable encoders
  • 📦 Zero Config: Works out-of-the-box with sensible defaults, configure only what you need

⚡ Performance Optimized

  • 🚀 Minimal Allocations: Object pooling and lazy formatting reduce garbage collection pressure
  • ⏱️ Low Latency: Optimized for high-throughput, low-latency logging in production systems
  • 🔄 Concurrent Safe: Lock-free read paths with optimized concurrent performance
  • 📈 Battle-Tested: Benchmarked against popular alternatives (logrus, zerolog)

Features

  • 🎯 Multiple Log Levels: TRACE, DEBUG, INFO, WARN, ERROR, PANIC, FATAL
  • 🔄 Multiple Output Formats: JSON and human-readable console formats
  • 📦 Log Rotation: Integrated with lumberjack for automatic log rotation
  • 🔒 Thread-Safe: Safe for concurrent use across goroutines

Installation

go get github.com/LowerPlane/logx

Why LogX?

LogX was designed from the ground up for modern production environments where security, compliance, developer experience, and performance are all critical:

  • 🔐 Security by Default: Unlike other logging libraries, LogX automatically protects your sensitive data. Credit card numbers, API keys, passwords, and other secrets are detected and redacted automatically - no manual configuration required for common patterns.

  • 📋 Compliance Made Easy: Meet regulatory requirements (PCI-DSS, GDPR, HIPAA, SOC 2) out of the box. LogX's built-in redaction patterns are designed to help you avoid accidental data leaks that could result in compliance violations.

  • 👨‍💻 Developer Experience: Clean, intuitive API that feels natural to Go developers. From simple one-liners to complex structured logging with distributed tracing - LogX scales with your needs without complexity creep.

  • ⚡ Production-Ready Performance: Built for high-throughput systems. LogX uses object pooling, minimal allocations, and concurrent-safe patterns to deliver exceptional performance even under heavy load.

Use LogX when you need:

  • To protect sensitive data in logs (PII, credentials, financial information)
  • Compliance with data protection regulations
  • High-performance logging in production microservices
  • Distributed tracing with context propagation
  • Integration with observability platforms (DataDog, New Relic, etc.)

Quick Start

package main

import (
    "github.com/LowerPlane/logx"
)

func main() {
    // Simple logging
    logx.Info("Hello, LogX!")
    logx.Warn("This is a warning")
    logx.Error("Something went wrong")

    // Structured logging with fields
    logx.WithFields(logx.Fields{
        "user": "john",
        "action": "login",
        "ip": "192.168.1.1",
    }).Info("User logged in")
}

Usage Examples

Basic Configuration

package main

import (
    "github.com/LowerPlane/logx"
)

func main() {
    // Create a new logger
    logger := logx.New()

    // Set log level
    logger.SetLevel(logx.InfoLevel)

    // Use console formatter for human-readable output
    logger.SetEncoder(logx.ConsoleFormatter{
        FullTimestamp: true,
        WithColors: false,
    })

    // Enable caller information
    logger.SetReportCaller(true)

    logger.Info("Logger configured successfully")
}

Structured Logging

// Log with structured fields
logx.WithFields(logx.Fields{
    "component": "database",
    "operation": "connect",
    "duration": "150ms",
}).Info("Database connection established")

// Chain multiple field sets
logger := logx.WithFields(logx.Fields{"service": "api"})
logger.WithFields(logx.Fields{"endpoint": "/users"}).Info("Handling request")

Context Integration

import (
    "context"
    "github.com/LowerPlane/logx"
)

// Add trace/span IDs to context
ctx := logx.ContextWithTraceSpan(context.Background(), "trace-123", "span-456")

// Logger will automatically extract and include trace/span IDs
logger := logx.WithContext(ctx)
logger.Info("Processing request")
// Output: {"level":"INFO","msg":"Processing request","time":"...","fields":{"trace_id":"trace-123","span_id":"span-456"}}

File Logging with Rotation

import (
    "github.com/LowerPlane/logx"
)

func main() {
    logger := logx.New()

    // Add file rotation hook
    rotationHook := logx.NewRotationHook(
        "app.log",  // filename
        10,         // max size in MB
        5,          // max number of backups
        30,         // max age in days
    )
    logger.AddHook(rotationHook)

    logger.Info("This will be written to app.log with rotation")
}

HTTP Hook for Remote Logging

// Send logs to remote endpoint (e.g., Loki, ELK)
httpHook := logx.NewHTTPHook("https://logs.example.com/api/logs")
logger.AddHook(httpHook)

logger.Error("This log will be sent to remote endpoint")

DataDog Integration

// Send logs to DataDog
dataDogHook := logx.NewDataDogHook("your-api-key", "us") // regions: us, eu, us3, us5, ap1, gov
dataDogHook.Source = "my-app"
dataDogHook.Service = "user-service"
dataDogHook.Hostname = "server-01"
dataDogHook.Tags = "env:production,version:1.2.3"
logger.AddHook(dataDogHook)

logger.WithFields(logx.Fields{"user_id": 123}).Info("User logged in")

Loggly Integration

// Send logs to Loggly
logglyHook := logx.NewLogglyHook("your-token", "http") // token and tag
logger.AddHook(logglyHook)

logger.Error("This error will be sent to Loggly")

New Relic Integration

// Send logs to New Relic
newRelicHook := logx.NewNewRelicHook("your-license-key", "us") // regions: us, eu, gov
newRelicHook.Service = "payment-api"
newRelicHook.Hostname = "api-server-01"
logger.AddHook(newRelicHook)

logger.WithFields(logx.Fields{"transaction_id": "txn-123"}).Info("Payment processed")

Atatus Integration

// Send logs to Atatus
atatusHook := logx.NewAtatusHook("your-license-key", "my-app")
logger.AddHook(atatusHook)

logger.WithFields(logx.Fields{"request_id": "req-456"}).Warn("Slow database query")

Redaction & Sensitive Data Protection

LogX provides comprehensive data protection features to automatically detect and redact sensitive information in your logs.

Secret Wrappers

Always redact sensitive values using secret wrappers:

// These will always appear as [REDACTED] in logs
email := logx.NewSecretString("[email protected]")
password := logx.NewSecretString("supersecret123")

logx.WithFields(logx.Fields{
    "email":    email,
    "password": password,
}).Info("User registration")
// Output: {"email":"[REDACTED]","password":"[REDACTED]","msg":"User registration"}

Field-Based Redaction

Automatically redact sensitive field names:

// Add keys that should always be redacted
logx.AddKeyRedactor("password", "token", "api_key", "credit_card")

logx.WithFields(logx.Fields{
    "username":  "john",
    "password":  "secret123",      // Will be redacted
    "api_key":   "sk_12345",       // Will be redacted
}).Info("User login")

Message Redaction

Scan and redact sensitive data in log messages:

logx.EnableMessageRedaction(true)

// Built-in patterns automatically detect and redact:
logx.Info("Processing credit card 4111-1111-1111-1111")  // → "Processing credit card [REDACTED]"
logx.Info("User SSN: 123-45-6789")                       // → "User SSN: [REDACTED]"
logx.Info("Login with password=mysecret")                // → "Login with [REDACTED]"

Custom Redactors

Create custom redaction rules:

// Custom field redactor
logx.AddCustomRedactor(func(key string, val interface{}) interface{} {
    if key == "ssn" {
        return "[MASKED-SSN]"
    }
    return val
})

// Regex-based redaction
logx.AddRegexRedactor(`(?i)token=[A-Za-z0-9-_]+`)

Data Masking Helper

Selectively mask sensitive fields in complex data structures:

userData := map[string]interface{}{
    "username": "alice",
    "password": "secret123",
    "email":    "[email protected]",
}

maskedData := logx.Mask(userData, []string{"password", "email"})
logx.WithFields(logx.Fields{"user": maskedData}).Info("Profile update")
// Output: {"user":{"username":"alice","password":"[REDACTED]","email":"[REDACTED]"}}

Per-Logger Redaction Control

Enable/disable redaction per logger instance:

// Global setting
logx.EnableRedaction(true)   // Enable globally

// Per-logger override (useful for development)
devLogger := logger.WithRedaction(false)  // Disable for this logger
devLogger.WithFields(logx.Fields{
    "debug_token": "actual_token_value",   // Will show actual value
}).Info("Debug info")

// Regular logger still follows global setting
logger.WithFields(logx.Fields{
    "token": "secret_token",               // Will be redacted
}).Info("Production log")

Built-in Redaction Patterns

LogX automatically detects and redacts common sensitive data patterns:

  • Credit Card Numbers: 4111-1111-1111-1111
  • Social Security Numbers: 123-45-6789
  • Email Addresses: [email protected]
  • API Keys & Tokens: apikey=sk_12345, Bearer abc123
  • AWS Access Keys: AKIAIOSFODNN7EXAMPLE
  • Private Key Headers: -----BEGIN RSA PRIVATE KEY-----
  • Password Patterns: password=secret123

Environment-Based Configuration

Configure redaction based on your environment:

import "os"

func init() {
    // Enable redaction in production, disable in development
    if os.Getenv("ENV") == "production" {
        logx.EnableRedaction(true)
    } else {
        logx.EnableRedaction(false)
    }
}

Custom Formatters

// JSON formatter with custom timestamp
logger.SetEncoder(logx.JSONFormatter{
    TimestampFormat: "2006-01-02 15:04:05.000",
})

// Console formatter with full timestamps
logger.SetEncoder(logx.ConsoleFormatter{
    FullTimestamp: true,
    WithColors: true,
})

Log Levels

LogX supports the following log levels (in order of severity):

  • TRACE - Very detailed information, typically only of interest when diagnosing problems
  • DEBUG - Detailed information, typically only of interest when diagnosing problems
  • INFO - General information about program execution
  • WARN - Warning messages for potentially harmful situations
  • ERROR - Error events that might still allow the application to continue
  • PANIC - Severe error events that will cause the program to panic
  • FATAL - Very severe error events that will cause the program to exit
logger.SetLevel(logx.DebugLevel) // Only logs DEBUG and above will be output

logx.Trace("This won't be shown")
logx.Debug("This will be shown")
logx.Info("This will be shown")
logx.Error("This will be shown")

Performance

LogX is designed for high performance with:

  • Object Pooling: Reuses log entry objects to reduce garbage collection
  • Lazy Formatting: Messages are only formatted if they meet the log level threshold
  • Minimal Allocations: Optimized to reduce memory allocations during logging operations
  • Concurrent Safe: Uses read-write mutexes for optimal concurrent performance

Benchmarks

Run the included benchmarks to compare performance:

go test -bench=. -benchmem

Example results comparing LogX with popular alternatives:

BenchmarkLogxInfo-8      2000000    750 ns/op    120 B/op    3 allocs/op
BenchmarkLogrusInfo-8    1000000   1500 ns/op    280 B/op    8 allocs/op
BenchmarkZerologInfo-8   3000000    550 ns/op     96 B/op    2 allocs/op

API Reference

Logger Methods

// Logger creation
logger := logx.New()

// Configuration
logger.SetLevel(level Level)
logger.SetEncoder(encoder Encoder)
logger.SetOutput(w io.Writer)
logger.SetReportCaller(enabled bool)
logger.AddHook(hook Hook)

// Logging methods
logger.Trace(msg string)
logger.Debug(msg string)
logger.Info(msg string)
logger.Warn(msg string)
logger.Error(msg string)
logger.Panic(msg string)  // Calls panic() after logging
logger.Fatal(msg string)  // Calls os.Exit(1) after logging

// Formatted logging
logger.Infof(format string, args ...interface{})

// Structured logging
logger.WithFields(fields Fields) *Logger
logger.WithContext(ctx context.Context) *Logger

Global Functions

// Global logger functions (use default logger)
logx.SetLevel(level Level)
logx.SetEncoder(encoder Encoder)
logx.SetOutput(w io.Writer)
logx.SetReportCaller(enabled bool)
logx.AddHook(hook Hook)

logx.Info(msg string)
logx.WithFields(fields Fields) *Logger
logx.WithContext(ctx context.Context) *Logger

Fields Type

type Fields map[string]interface{}

// Usage
fields := logx.Fields{
    "user_id": 12345,
    "action": "login",
    "success": true,
    "duration": 150.5,
}

Built-in Hooks

File Hook

fileHook, err := logx.NewFileHook("/var/log/app.log")
if err != nil {
    log.Fatal(err)
}
logger.AddHook(fileHook)

Rotation Hook (with Lumberjack)

rotationHook := logx.NewRotationHook(
    "/var/log/app.log", // filename
    100,                // max size in MB
    10,                 // max backups
    30,                 // max age in days
)
logger.AddHook(rotationHook)

HTTP Hook

httpHook := logx.NewHTTPHook("https://logs.example.com/api/v1/logs")
logger.AddHook(httpHook)

DataDog Hook

dataDogHook := logx.NewDataDogHook("your-api-key", "us")
dataDogHook.Source = "my-app"
dataDogHook.Service = "user-service"
logger.AddHook(dataDogHook)

Loggly Hook

logglyHook := logx.NewLogglyHook("your-token", "production")
logger.AddHook(logglyHook)

New Relic Hook

newRelicHook := logx.NewNewRelicHook("your-license-key", "us")
newRelicHook.Service = "api-service"
logger.AddHook(newRelicHook)

Atatus Hook

atatusHook := logx.NewAtatusHook("your-license-key", "my-app")
logger.AddHook(atatusHook)

Migrating from Logrus to LogX

LogX provides a familiar API for logrus users, making migration straightforward. This guide will help you transition your existing logrus-based application to LogX while gaining enhanced security, compliance, and performance benefits.

Why Migrate?

  • 🔐 Built-in Security: Automatic sensitive data redaction (passwords, API keys, credit cards, SSNs)
  • 📋 Compliance: Meet PCI-DSS, GDPR, HIPAA requirements out of the box
  • ⚡ Better Performance: 2x faster than logrus with fewer allocations (see benchmarks)
  • 🔗 Modern Features: Context integration, distributed tracing, and enhanced hook system
  • 🛡️ Production-Ready: Security-first design prevents accidental data leaks

Quick Migration Guide

1. Basic Setup Migration

Logrus:

import "github.com/sirupsen/logrus"

func main() {
    logrus.SetLevel(logrus.InfoLevel)
    logrus.SetFormatter(&logrus.JSONFormatter{})
    logrus.Info("Application started")
}

LogX:

import "github.com/LowerPlane/logx"

func main() {
    logx.SetLevel(logx.InfoLevel)
    logx.SetEncoder(logx.JSONFormatter{})
    logx.Info("Application started")
}

2. Structured Logging Migration

Logrus:

logrus.WithFields(logrus.Fields{
    "user_id": 12345,
    "action": "login",
}).Info("User logged in")

LogX:

logx.WithFields(logx.Fields{
    "user_id": 12345,
    "action": "login",
}).Info("User logged in")

No changes needed - The API is identical!

3. Logger Instance Migration

Logrus:

logger := logrus.New()
logger.SetLevel(logrus.WarnLevel)
logger.SetFormatter(&logrus.JSONFormatter{})
logger.SetOutput(os.Stderr)

LogX:

logger := logx.New()
logger.SetLevel(logx.WarnLevel)
logger.SetEncoder(logx.JSONFormatter{})
logger.SetOutput(os.Stderr)

Key Differences:

  • SetFormatter()SetEncoder() (same concept, clearer naming)

4. Log Levels Migration

Logrus LogX Notes
logrus.TraceLevel logx.TraceLevel ✅ Same
logrus.DebugLevel logx.DebugLevel ✅ Same
logrus.InfoLevel logx.InfoLevel ✅ Same
logrus.WarnLevel logx.WarnLevel ✅ Same
logrus.ErrorLevel logx.ErrorLevel ✅ Same
logrus.FatalLevel logx.FatalLevel ✅ Same
logrus.PanicLevel logx.PanicLevel ✅ Same

5. Hooks Migration

Logrus:

import "github.com/sirupsen/logrus"

hook := &MyCustomHook{}
logrus.AddHook(hook)

LogX:

import "github.com/LowerPlane/logx"

// Built-in hooks (no custom hook needed for common use cases)
rotationHook := logx.NewRotationHook("app.log", 100, 10, 30)
logger.AddHook(rotationHook)

// Or for custom hooks, implement the Hook interface
type MyCustomHook struct{}

func (h *MyCustomHook) Fire(entry *logx.Entry) {
    // Your hook logic
}

logger.AddHook(&MyCustomHook{})

LogX provides built-in hooks for common scenarios:

  • File with Rotation: NewRotationHook() (replaces logrus file hooks + rotation)
  • HTTP/Remote: NewHTTPHook() for Loki, ELK, etc.
  • DataDog: NewDataDogHook()
  • New Relic: NewNewRelicHook()
  • Loggly: NewLogglyHook()
  • Atatus: NewAtatusHook()

6. Formatter/Encoder Migration

Logrus:

logrus.SetFormatter(&logrus.JSONFormatter{
    TimestampFormat: "2006-01-02 15:04:05",
})

// Or text formatter
logrus.SetFormatter(&logrus.TextFormatter{
    FullTimestamp: true,
})

LogX:

logx.SetEncoder(logx.JSONFormatter{
    TimestampFormat: "2006-01-02 15:04:05",
})

// Or console formatter (equivalent to TextFormatter)
logx.SetEncoder(logx.ConsoleFormatter{
    FullTimestamp: true,
    WithColors: true,
})

7. Context Integration (New in LogX)

Logrus doesn't have built-in context support. LogX makes it easy:

LogX:

import "context"

// Add trace/span IDs to context
ctx := logx.ContextWithTraceSpan(context.Background(), "trace-123", "span-456")

// Logger automatically extracts trace/span from context
logger := logx.WithContext(ctx)
logger.Info("Processing request")
// Output includes: "trace_id":"trace-123", "span_id":"span-456"

8. Sensitive Data Protection (New in LogX)

This is LogX's killer feature - automatic security that logrus doesn't provide:

Logrus (manual redaction required):

// You have to manually redact sensitive data
password := "[REDACTED]"
logrus.WithFields(logrus.Fields{
    "password": password,
}).Info("User login")

LogX (automatic protection):

// Secret wrappers ensure data is ALWAYS redacted
password := logx.NewSecretString("actual_password_123")
logx.WithFields(logx.Fields{
    "password": password,  // Automatically shows as [REDACTED]
}).Info("User login")

// Or use field-based redaction
logx.AddKeyRedactor("password", "api_key", "credit_card")
logx.WithFields(logx.Fields{
    "password": "secret123",  // Automatically redacted
    "username": "john",       // Not redacted
}).Info("User login")

// Or enable message redaction for automatic pattern detection
logx.EnableMessageRedaction(true)
logx.Info("User password is secret123")  // → "User password is [REDACTED]"
logx.Info("Credit card: 4111-1111-1111-1111")  // → "Credit card: [REDACTED]"

9. Complete Migration Example

Before (Logrus):

package main

import (
    "github.com/sirupsen/logrus"
    "os"
)

func main() {
    // Setup
    logrus.SetLevel(logrus.InfoLevel)
    logrus.SetFormatter(&logrus.JSONFormatter{})
    logrus.SetOutput(os.Stdout)

    // Basic logging
    logrus.Info("Application started")

    // Structured logging
    logrus.WithFields(logrus.Fields{
        "user": "john",
        "role": "admin",
    }).Info("User authenticated")

    // Error logging
    logrus.WithFields(logrus.Fields{
        "error": "connection timeout",
    }).Error("Database error")
}

After (LogX with Security):

package main

import (
    "github.com/LowerPlane/logx"
    "os"
)

func main() {
    // Setup (same as logrus)
    logx.SetLevel(logx.InfoLevel)
    logx.SetEncoder(logx.JSONFormatter{})
    logx.SetOutput(os.Stdout)

    // Enable security features (new!)
    logx.EnableRedaction(true)
    logx.EnableMessageRedaction(true)

    // Basic logging (same API)
    logx.Info("Application started")

    // Structured logging with automatic security
    logx.WithFields(logx.Fields{
        "user": "john",
        "role": "admin",
        "api_key": logx.NewSecretString("sk_live_123"),  // Automatically redacted
    }).Info("User authenticated")

    // Error logging
    logx.WithFields(logx.Fields{
        "error": "connection timeout",
    }).Error("Database error")
}

10. Migration Checklist

  • Replace imports: github.com/sirupsen/logrusgithub.com/LowerPlane/logx
  • Update formatter calls: SetFormatter()SetEncoder()
  • Update formatter types: JSONFormatter{}logx.JSONFormatter{}
  • Update formatter types: TextFormatter{}logx.ConsoleFormatter{}
  • Identify and wrap sensitive fields with logx.NewSecretString()
  • Add field redactors for known sensitive keys: logx.AddKeyRedactor()
  • Enable message redaction: logx.EnableMessageRedaction(true)
  • Replace custom hooks with built-in hooks where possible
  • Add context integration for distributed tracing (optional)
  • Run tests to verify logging behavior
  • Review logs to ensure sensitive data is redacted

Performance Comparison

Based on included benchmarks:

Operation          | Logrus      | LogX        | Improvement
-------------------|-------------|-------------|------------
Info logging       | 1500 ns/op  | 750 ns/op   | 2x faster
Memory per op      | 280 B/op    | 120 B/op    | 57% less
Allocations per op | 8 allocs/op | 3 allocs/op | 62% fewer

Need Help?

  • API is 95% compatible with logrus - most code works unchanged
  • Main change: SetFormatter()SetEncoder()
  • Added benefit: Automatic security and compliance features
  • Performance: 2x faster with better memory efficiency

Requirements

  • Go 1.19 or later

Dependencies

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Compliance-grade structured logging for Go — with JSON output, automatic secret redaction, trace propagation, tamper-evident hashing, and flexible hooks (file, Loki, Kafka, S3).

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages