Skip to content

a command-line tool that automatically generates LogValue() methods for Go structs to integrate with Go's log/slog package

License

Notifications You must be signed in to change notification settings

stuckinforloop/oak

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Oak - Go Structured Logging Code Generator

Oak is a command-line tool that automatically generates LogValue() methods for Go structs to integrate with Go's log/slog package. It provides structured logging with built-in support for sensitive data redaction and field exclusion.

Features

  • 🚀 Seamless Integration: Works with go generate workflow
  • 🔒 Security First: Automatic redaction of sensitive fields
  • ⚙️ Configurable: YAML-based configuration for flexible field handling
  • 🎯 Type-Aware: Intelligent mapping to appropriate slog functions
  • 📦 Package-Friendly: Processes entire packages or individual files
  • 🔧 Pointer Safe: Handles nil pointers gracefully
  • 🏷️ Tag Support: Respects struct tags for field control

Installation

go install github.com/stuckinforloop/oak/cmd/oak@latest

Quick Start

  1. Create an oak.yaml configuration file in your project root:
packages:
  - ./internal/booking
redactKeys:
  - password
  - secret
  - creditcard
redactMessage: "[REDACTED]"
  1. Add the generate directive to your Go structs:
package booking

import "time"

//go:generate oak
type Reservation struct {
    ID          int
    GuestName   string
    Email       string
    Password    string           // Will be redacted (matches redactKeys)
    CreditCard  string `log:"redact"` // Will be redacted (explicit tag)
    CheckIn     time.Time
    Notes       string `log:"-"`      // Will be excluded from logs
    IsConfirmed bool
    Amount      float64
    ContactInfo *ContactInfo     // Pointer handled safely
}

//go:generate oak
type ContactInfo struct {
    Phone   string
    Address string
}
  1. Run code generation:
go generate ./...
# or
oak ./...
  1. Use the generated LogValue methods:
reservation := Reservation{
    ID: 123,
    GuestName: "John Doe",
    Email: "[email protected]",
    Password: "secret123",
    CreditCard: "4111-1111-1111-1111",
    CheckIn: time.Now(),
    Notes: "Private notes",
    IsConfirmed: true,
    Amount: 299.99,
    ContactInfo: &ContactInfo{
        Phone: "+1-555-0123",
        Address: "123 Main St",
    },
}

slog.Info("Processing reservation", "reservation", reservation)

Output:

Processing reservation reservation.ID=123 reservation.GuestName="John Doe" reservation.Email="[email protected]" reservation.Password="[REDACTED]" reservation.CreditCard="[REDACTED]" reservation.CheckIn="2024-01-15T10:30:00Z" reservation.IsConfirmed=true reservation.Amount=299.99 reservation.ContactInfo.Phone="+1-555-0123" reservation.ContactInfo.Address="123 Main St"

Note: The Notes field is completely excluded, and sensitive fields are redacted.

Usage

Command Line Options

# Process current directory based on oak.yaml
oak

# Process all packages recursively
oak ./...

# Process specific package
oak ./internal/booking
oak --package ./internal/booking

# Process specific file
oak --source ./internal/booking/booking.go

# Show help
oak --help

# Show version
oak --version

Configuration

Oak uses an oak.yaml file in your project root for configuration:

# List of packages to scan for //go:generate oak directives
packages:
  - ./internal/booking
  - ./pkg/user
  - ./cmd/server

# List of field names to automatically redact (case-insensitive)
redactKeys:
  - password
  - secret
  - token
  - apikey
  - api_key
  - privatekey
  - private_key
  - creditcard
  - ssn

# Message to use for redacted fields
redactMessage: "[REDACTED]"

Struct Tags

Oak supports struct tags for fine-grained control:

type User struct {
    ID       int
    Username string
    Password string `log:"redact"`  // Explicitly redact this field
    Notes    string `log:"-"`       // Exclude this field from logs
    Email    string                 // Normal logging
}

Supported Types

Oak intelligently maps Go types to appropriate slog functions:

  • Integers (int, int8, int16, int32, int64, uint, etc.) → slog.Int64
  • Strings (string) → slog.String
  • Booleans (bool) → slog.Bool
  • Floats (float32, float64) → slog.Float64
  • Complex types (structs, slices, maps, interfaces) → slog.Any
  • Pointers → Handled with nil checks, logging "null" for nil values

Generated Code Example

For the struct above, Oak generates:

// Code generated by oak. DO NOT EDIT.
package booking

import "log/slog"

// LogValue implements slog.LogValuer for Reservation
func (r Reservation) LogValue() slog.Value {
    return slog.GroupValue(
        slog.Int64("ID", int64(r.ID)),
        slog.String("GuestName", r.GuestName),
        slog.String("Email", r.Email),
        slog.String("Password", "[REDACTED]"),
        slog.String("CreditCard", "[REDACTED]"),
        slog.Any("CheckIn", r.CheckIn),
        slog.Bool("IsConfirmed", r.IsConfirmed),
        slog.Float64("Amount", r.Amount),
        func() slog.Attr {
            if r.ContactInfo == nil {
                return slog.String("ContactInfo", "null")
            }
            return slog.Any("ContactInfo", *r.ContactInfo)
        }(),
    )
}

Integration with go generate

Oak works seamlessly with Go's go generate tool:

  1. Add //go:generate oak comments to your structs
  2. Run go generate ./... as part of your build process
  3. Generated files are automatically created/updated

Requirements

  • Go 1.21+ (for log/slog support)
  • oak.yaml configuration file in project root

License

MIT License - see LICENSE file for details.

About

a command-line tool that automatically generates LogValue() methods for Go structs to integrate with Go's log/slog package

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages