Skip to content

Proposal: Enable Timestamps by Default in log.New() #191

@jamesainslie

Description

@jamesainslie

Problem

log.New() omits timestamps while log.Default() includes them. This inconsistency surprises users.

// log.Default() includes timestamps
log.Info("Hello world!")
// Output: 2023/01/23 14:23:45 INFO Hello world!

// log.New() does not
logger := log.New(os.Stderr)
logger.Info("Hello world!")
// Output: INFO Hello world!

Solution

Enable timestamps by default in log.New():

func New(w io.Writer) *Logger {
    return NewWithOptions(w, Options{
        ReportTimestamp: true,
    })
}

This uses DefaultTimeFormat ("2006/01/02 15:04:05"), matching log.Default() behavior.

Users can disable via NewWithOptions():

logger := log.NewWithOptions(os.Stderr, log.Options{
    ReportTimestamp: false,
})

Impact

Breaking change: Existing code using log.New() will now include timestamps.

Benefits:

  • Consistent with log.Default()
  • Matches user expectations
  • Aligns with standard library behavior

API Compatibility with log/slog

The *Logger type already implements slog.Handler:

handler := log.NewWithOptions(os.Stderr, log.Options{
    ReportTimestamp: true,
    Level:           log.DebugLevel,
})
logger := slog.New(handler)

For a familiar slog-style API, add:

// HandlerOptions provides slog-style configuration.
type HandlerOptions struct {
    AddSource bool
    Level     Level
}

// NewTextHandler returns a Handler with text formatting.
// Timestamps are enabled by default.
func NewTextHandler(w io.Writer, opts *HandlerOptions) *Logger {
    if opts == nil {
        opts = &HandlerOptions{}
    }
    return NewWithOptions(w, Options{
        ReportTimestamp: true,
        Formatter:       TextFormatter,
        Level:           opts.Level,
        ReportCaller:    opts.AddSource,
    })
}

// NewJSONHandler returns a Handler with JSON formatting.
// Timestamps are enabled by default.
func NewJSONHandler(w io.Writer, opts *HandlerOptions) *Logger {
    if opts == nil {
        opts = &HandlerOptions{}
    }
    return NewWithOptions(w, Options{
        ReportTimestamp: true,
        Formatter:       JSONFormatter,
        Level:           opts.Level,
        ReportCaller:    opts.AddSource,
    })
}

Usage:

handler := log.NewTextHandler(os.Stderr, &log.HandlerOptions{
    Level: log.DebugLevel,
})
logger := slog.New(handler)

Implementation

  • Update New() to set ReportTimestamp: true
  • Add HandlerOptions, NewTextHandler(), NewJSONHandler()
  • Update tests
  • Document breaking change in release notes

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions