log

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 24, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

README

log

A logging package for Go.

Installation

go get -u github.com/tfoertsch123/log

What is it?

Classical logging with log levels and messages. No structured logging.

The following log levels are defined:

  • NOTICE - printed always
  • PANIC - print + exit(1)
  • ERROR
  • WARN
  • INFO
  • DEBUG
  • DEBG2
  • DEBG3
  • DEBG4
  • DEBG5

The log target is an io.Writer, by default os.Stderr.

A logger can have a topic or subsystem.

Log messages look like so:

TIMESTAMP LEVEL [TOPIC] (CODE LOCATION) MESSAGE

Topic and code location are optional.

Examples:

2026-10-05 09:02:05.987654 INFO message without a topic
2026-10-05 09:02:05.987654 DEBUG (log/exmpl01_log_test.go:21) with code location
2026-10-05 09:02:05.987654 DEBUG [TPC] (log/exmpl01_log_test.go:27) with topic and location

The timestamp can be configured. Default precision is microseconds.

The code location is printed for a certain log level and above. The file name is printed with a specific number of directory components. This can also be configured.

The package allows you to construct a tree of loggers. Any configuration change with the exception of the topic propagates to all of its kids recursively.

That allows you for instance to set up static loggers with different topics and later modify the log level for all of them.

var base *log.Logger = log.NewR(log.WithOutput(...))
var tpc1 *log.Logger = base.New(log.WithTopic("TOPIC1"))
var tpc2 *log.Logger = base.New(log.WithTopic("TOPIC2"))

func subsys1() {
    tpc1.Info(`message`)
}

func subsys2() {
    tpc2.Info(`message`)
}

func main() {
    base.SetLevel(log.DEBUG)
    ...
}

Alternatively, you can rely on the default logger:

func subsys1() {
    log.NewC(log.WithTopic(`TOPIC1`))
    defer log.Close()

    log.Info(`message`)
}

func subsys2() {
    log.NewC(log.WithTopic(`TOPIC2`))
    defer log.Close()

    log.Info(`message`)
}

func main() {
    log.SetLevel(log.DEBUG)
    log.SetOutput(...)
}

Documentation

Overview

Package log implements a simple logging package with a hierarchical logger tree. Each logger can have children, and configuration changes propagate to descendants. The package is thread-safe; all exported methods except SetNow() are safe for concurrent use.

Each logger has an optional topic. The idea is that this is the main distinction between loggers. Think of the topic as subsystem or part of the code.

Please check out the provided examples to get a better understanding.

A log message consists of a timestamp, a log level, an optional topic, an optional code location and the actual message.

The package defines the following log levels: NOTICE (printed always), PANIC (print and exit 1), ERROR, WARN, INFO, DEBUG, DEBG2, DEBG3, DEBG4, DEBG5

The root logger comes with the folowing properties: log level = WARN (a message logged with a higher level will NOT be printed); no topic; the output is sent to os.Stderr; the timeformat is 2006-01-02 15:04:05.000000; code locations are included in DEBUG and above; the location contains the fully qualified file name and multiline mode is turned off.

At the beginning the only existing logger is the root logger. Derived loggers can be created using New(). Options passed to New() allow to configure the child logger.

Another concept is that of the current logger. It is created using the package level New() function or using the SetCurrent() function. The current logger is used by all package level functions.

All properties of a logger except the topic can be changed after creation. A property change is propagated to all derived loggers recursively. So, if you change the log level of the root logger, this change is inherited by all other loggers.

Example (Lazy)
package main

import (
	"github.com/tfoertsch123/log"
	"math"
	"os"
	"time"
)

func main() {
	// Use SetNow() to generate a fixed timestamp. This is only needed
	// to have this pass as a test so that go doc includes the example.
	defer func(orig func() time.Time) { log.SetNow(orig) }(log.SetNow(func() time.Time {
		return time.Date(2026, 10, 5, 9, 2, 5, 987654321, time.UTC)
	}))
	log.SetOutput(os.Stdout)
	defer log.Root().Close() // reset/close all loggers

	complex_work := func() string {
		time.Sleep(100 * time.Millisecond)
		return "done"
	}

	ms := time.Millisecond

	// The log level is WARN. So, nothing will be printed.
	// Yet it still takes time.
	now := time.Now()

	log.Infof("complex_work: %s", complex_work())

	log.Warnf("complex_work took %vms +/- 20ms",
		20*math.Round(float64(time.Now().Sub(now))/float64(20*ms)),
	)

	now = time.Now()

	// Now with lazy execution. This should take almost no time
	// since complex_work() is not executed.
	log.Infol("complex_work: %s",
		log.Lazy(func() interface{} { return complex_work() }))

	log.Warnf("complex_work with lazy execution took %vms +/- 20ms",
		20*math.Round(float64(time.Now().Sub(now))/float64(20*ms)),
	)

	// Now let's raise the log level and repeat the previous.
	// It should take ~100ms
	log.SetLevel(log.INFO)

	now = time.Now()

	log.Infol("complex_work: %s",
		log.Lazy(func() interface{} { return complex_work() }))

	log.Warnf("complex_work if actually done took %vms +/- 20ms",
		20*math.Round(float64(time.Now().Sub(now))/float64(20*ms)),
	)

}
Output:
2026-10-05 09:02:05.987654 WARN complex_work took 100ms +/- 20ms
2026-10-05 09:02:05.987654 WARN complex_work with lazy execution took 0ms +/- 20ms
2026-10-05 09:02:05.987654 NOTICE Setting log level from WARN to INFO
2026-10-05 09:02:05.987654 INFO complex_work: done
2026-10-05 09:02:05.987654 WARN complex_work if actually done took 100ms +/- 20ms
Example (Multiline)
package main

import (
	"github.com/tfoertsch123/log"
	"os"
	"time"
)

func main() {
	// Use SetNow() to generate a fixed timestamp. This is only needed
	// to have this pass as a test so that go doc includes the example.
	defer func(orig func() time.Time) { log.SetNow(orig) }(log.SetNow(func() time.Time {
		return time.Date(2026, 10, 5, 9, 2, 5, 987654321, time.UTC)
	}))
	log.SetOutput(os.Stdout)
	defer log.Root().Close() // reset/close all loggers

	log.Notice("this\nis a\nmultiline\nmessage")

	log.NewC(log.WithMultiLine(true))

	log.Notice("this\nis a\nmultiline\nmessage")

	mlprefix := ">"
	log.NewC(log.WithMultiLinePrefix(&mlprefix))

	log.Notice("this\nis a\nmultiline\nmessage")
	log.Warn("and another\nmessage")
}
Output:
2026-10-05 09:02 NOTICE this
is a
multiline
message
2026-10-05 09:02 NOTICE this
2026-10-05 09:02 NOTICE is a
2026-10-05 09:02 NOTICE multiline
2026-10-05 09:02 NOTICE message
2026-10-05 09:02 NOTICE this
>                       is a
>                       multiline
>                       message
2026-10-05 09:02 WARN and another
>                     message

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrInvalidFormat error = errors.New(`invalid format`)

ErrInvalidFormat is an error returned by ParseURL indicating there is something wrong with the URL.

View Source
var ErrInvalidLevel error = errors.New(`invalid log level`)

ErrInvalidLevel is returned by ParseLevel when the input string does not match any known log level.

Functions

func Close

func Close()

Close closes the current logger and all its descendants.

func Debg2

func Debg2(m string)

Debg2 logs a debug message at level 2 using the current logger.

func Debg2f

func Debg2f(f string, p ...interface{})

Debg2f logs a formatted debug message at level 2 using the current logger.

func Debg2l

func Debg2l(f string, p ...interface{})

Debg2l logs a message with late evaluation at debug level 2 using the current logger.

func Debg3

func Debg3(m string)

Debg3 logs a debug message at level 3 using the current logger.

func Debg3f

func Debg3f(f string, p ...interface{})

Debg3f logs a formatted debug message at level 3 using the current logger.

func Debg3l

func Debg3l(f string, p ...interface{})

Debg3l logs a message with late evaluation at debug level 3 using the current logger.

func Debg4

func Debg4(m string)

Debg4 logs a debug message at level 4 using the current logger.

func Debg4f

func Debg4f(f string, p ...interface{})

Debg4f logs a formatted debug message at level 4 using the current logger.

func Debg4l

func Debg4l(f string, p ...interface{})

Debg4l logs a message with late evaluation at debug level 4 using the current logger.

func Debg5

func Debg5(m string)

Debg5 logs a debug message at level 5 using the current logger.

func Debg5f

func Debg5f(f string, p ...interface{})

Debg5f logs a formatted debug message at level 5 using the current logger.

func Debg5l

func Debg5l(f string, p ...interface{})

Debg5l logs a message with late evaluation at debug level 5 using the current logger.

func Debug

func Debug(m string)

Debug logs a debug message using the current logger.

func Debugf

func Debugf(f string, p ...interface{})

Debugf logs a formatted debug message using the current logger.

func Debugl

func Debugl(f string, p ...interface{})

Debugl logs a message with late evaluation at debug level using the current logger.

func Error

func Error(m string)

Error logs an error message using the current logger.

func Errorf

func Errorf(f string, p ...interface{})

Errorf logs a formatted error message using the current logger.

func Errorl

func Errorl(f string, p ...interface{})

Errorl logs a message with late evaluation at error level using the current logger.

func GetLocDirectories

func GetLocDirectories() int

GetLocDirectories returns the current logger’s directory component count.

func GetMultiLine

func GetMultiLine() bool

GetMultiLine returns true if multiline mode is on for the current logger.

func GetMultiLinePrefix added in v0.2.0

func GetMultiLinePrefix() *string

GetMultiLinePrefix returns the MultiLinePrefix for the current logger.

func GetOutput

func GetOutput() io.Writer

GetOutput returns the current logger’s output writer.

func GetTimeFmt

func GetTimeFmt() string

GetTimeFmt returns the current logger’s time format string.

func Info

func Info(m string)

Info logs an info message using the current logger.

func Infof

func Infof(f string, p ...interface{})

Infof logs a formatted info message using the current logger.

func Infol

func Infol(f string, p ...interface{})

Infol logs a message with late evaluation at info level using the current logger.

func Log

func Log(lvl Level, m string)

Log outputs a message at the given level using the current logger. See Log above.

func Logf

func Logf(lvl Level, f string, p ...interface{})

Logf outputs a formatted message at the given level using the current logger.

func Logl

func Logl(lvl Level, f string, p ...interface{})

Logl outputs a formatted message with late evaluation using the current logger.

func Notice

func Notice(m string)

Notice logs a notice message using the current logger.

func Noticef

func Noticef(f string, p ...interface{})

Noticef logs a formatted notice message using the current logger.

func Noticel

func Noticel(f string, p ...interface{})

Noticel logs a message with late evaluation at notice level using the current logger.

func Panic

func Panic(m string)

Panic logs a panic message using the current logger and exits with code 1.

func Panicf

func Panicf(f string, p ...interface{})

Panicf logs a formatted panic message using the current logger and exits with code 1.

func Panicl

func Panicl(f string, p ...interface{})

Panicl logs a message with late evaluation at panic level using the current logger and exits with code 1.

func SetLevel

func SetLevel(lvl Level)

SetLevel sets the minimum log level on the current logger and all its descendants.

func SetLocDirectories

func SetLocDirectories(n int)

SetLocDirectories sets the directory component count on the current logger and its descendants.

func SetMinLocation

func SetMinLocation(lvl Level)

SetMinLocation sets the minimum location level on the current logger and its descendants.

func SetMultiLine

func SetMultiLine(ml bool)

SetMultiLine turns multiline mode on or off for the current logger and all its descendants.

func SetMultiLinePrefix added in v0.2.0

func SetMultiLinePrefix(x *string)

SetMultiLinePrefix sets the MultiLinePrefix for the current logger and all its descendants.

func SetNow

func SetNow(now_f func() time.Time) func() time.Time

SetNow allows to change this package's notion of now. It's intended to be used mainly for testing and debugging purposes. The default value is time.Now. SetNow is not thread-safe. If you need to modify it from different go routines, make sure to prevent all concurrent logging.

func SetOutput

func SetOutput(out io.Writer)

SetOutput sets the output writer on the current logger and its descendants.

func SetTimeFmt

func SetTimeFmt(f string)

SetTimeFmt sets the time format string on the current logger and its descendants.

func Warn

func Warn(m string)

Warn logs a warning message using the current logger.

func Warnf

func Warnf(f string, p ...interface{})

Warnf logs a formatted warning message using the current logger.

func Warnl

func Warnl(f string, p ...interface{})

Warnl logs a message with late evaluation at warning level using the current logger.

Types

type Deferred added in v0.3.0

type Deferred func() interface{}

Deferred is a type representing a function wrapped for lazy execution. See Logl for more details.

func Lazy added in v0.3.0

func Lazy(fn func() interface{}) Deferred

Lazy() wraps a function for lazy evaluation. See Logl for more details.

type Level

type Level int8

Level represents a log severity level. Lower values indicate higher severity. The zero value of Level is PANIC. Use ToLevel or ParseLevel to obtain a valid Level.

const (
	// NOTICE is a special level that always prints, regardless of the
	// logger's threshold. It is the only level that can be lower than PANIC.
	NOTICE Level = iota - 1
	// PANIC is the highest severity. Logging at this level will also call
	// os.Exit(1).
	PANIC
	// ERROR indicates an error condition.
	ERROR
	// WARN indicates a warning condition.
	WARN
	// INFO indicates an informational message.
	INFO
	// DEBUG indicates a debug message.
	DEBUG
	// DEBG2 is a more verbose debug level.
	DEBG2
	// DEBG3 is an even more verbose debug level.
	DEBG3
	// DEBG4 is a highly verbose debug level.
	DEBG4
	// DEBG5 is the most verbose debug level.
	DEBG5
)

func GetLevel

func GetLevel() Level

GetLevel returns the current logger’s minimum log level.

func GetMinLocation

func GetMinLocation() Level

GetMinLocation returns the current logger’s minimum location level.

func ParseLevel

func ParseLevel(s string) (Level, error)

ParseLevel parses a string into a Level. It accepts case-insensitive names: "notice", "panic", "error", "warn"/"warning", "info", "debug", "debug2"/"debg2", "debug3"/"debg3", "debug4"/"debg4", "debug5"/"debg5", or the numeric strings "0" through "8". Returns ErrInvalidLevel if the string does not match.

func ToLevel

func ToLevel(i int) Level

ToLevel converts an integer to a Level, clamping it to the valid range. Values above DEBG5 are clamped to DEBG5; values below PANIC are clamped to PANIC.

func (Level) String

func (l Level) String() string

String returns the human-readable name of the level. It returns one of: "NOTICE", "PANIC", "ERROR", "WARN", "INFO", "DEBUG", "DEBG2", "DEBG3", "DEBG4", "DEBG5".

type LogOpts

type LogOpts struct {
	// contains filtered or unexported fields
}

LogOpts holds optional configuration for creating a new Logger via New.

type Logger

type Logger struct {
	// contains filtered or unexported fields
}

Logger represents a node in a hierarchical logger tree.

func L

func L() *Logger

L returns the current package-level logger. The current logger is used by all top-level logging functions (e.g. Log, Debug). It is protected by a global mutex; use this function to obtain a consistent snapshot.

func NewC

func NewC(opts ...Opt) *Logger

New creates and returns a new logger as a child of the current logger and sets it as the new current logger. Shortcut for lg=log.L().New(); lg.SetCurrent()

Example
package main

import (
	"github.com/tfoertsch123/log"
	"os"
	"time"
)

func main() {
	// Use SetNow() to generate a fixed timestamp. This is only needed
	// to have this pass as a test so that go doc includes the example.
	defer func(orig func() time.Time) { log.SetNow(orig) }(log.SetNow(func() time.Time {
		return time.Date(2026, 10, 5, 9, 2, 5, 987654321, time.UTC)
	}))

	// This example uses the current logger.
	log.SetLevel(log.DEBUG)  // change the log level from WARN to DEBUG
	log.SetOutput(os.Stdout) // change the output from Stderr to Stdout
	log.SetLocDirectories(1) // we want 1 directory component in the location output
	log.Info(`message without a topic`)
	log.Debug(`with code location`)
	log.Debg2(`not printed`) // because DEBUG < DEBG2

	// Create a new logger and make it the current one.
	// Everything but the topic is inherited from the root.
	log.NewC(log.WithTopic(`TPC`))
	log.Debug(`with topic and location`)

	// Close the current logger. The root logger becomes current again.
	log.Close()
	log.Warn(`get back the old logger`)

	// Close the root logger. This reinits it.
	log.Close()
}
Output:
2026-10-05 09:02:05.987654 INFO message without a topic
2026-10-05 09:02:05.987654 DEBUG (log/exmpl01_log_test.go:21) with code location
2026-10-05 09:02:05.987654 DEBUG [TPC] (log/exmpl01_log_test.go:27) with topic and location
2026-10-05 09:02:05.987654 WARN get back the old logger

func NewK

func NewK(opts ...Opt) *Logger

New creates and returns a new logger as a child of the current logger without making it the current logger. Shortcut for log.L().New().

Example
package main

import (
	"github.com/tfoertsch123/log"
	"os"
	"time"
)

func main() {
	// Use SetNow() to generate a fixed timestamp. This is only needed
	// to have this pass as a test so that go doc includes the example.
	defer func(orig func() time.Time) { log.SetNow(orig) }(log.SetNow(func() time.Time {
		return time.Date(2026, 10, 5, 9, 2, 5, 987654321, time.UTC)
	}))

	var lg1 *log.Logger
	var lg2 *log.Logger

	fn1 := func() {
		lg1.Infof(`info in fn%d`, 1)
		lg1.Warnf(`info in fn%d`, 1)
	}

	fn2 := func() {
		lg2.Infof(`info in fn%d`, 2)
		lg2.Warnf(`info in fn%d`, 2)
	}

	// Create 2 loggers with different topics. Both are children of the
	// current logger. The current logger does not change. So, they are
	// also direct kids of the root logger.
	// Since at this point the root and current loggers are the same,
	// NewR() and NewK() are basically so too.
	lg1 = log.NewK(log.WithTopic(`TOPIC1`))
	lg2 = log.NewR(log.WithTopic(`TOPIC2`))

	// these changes propagate from the root/current logger to all other
	log.SetOutput(os.Stdout)
	log.SetTimeFmt("2006-01-02 15:04")

	fn1()
	fn2()

	// change the log level from WARN to INFO for all loggers
	log.SetLevel(log.DEBUG)

	fn1()
	fn2()

}
Output:
2026-10-05 09:02 WARN [TOPIC1] info in fn1
2026-10-05 09:02 WARN [TOPIC2] info in fn2
2026-10-05 09:02 NOTICE Setting log level from WARN to DEBUG
2026-10-05 09:02 INFO [TOPIC1] info in fn1
2026-10-05 09:02 WARN [TOPIC1] info in fn1
2026-10-05 09:02 INFO [TOPIC2] info in fn2
2026-10-05 09:02 WARN [TOPIC2] info in fn2

func NewR

func NewR(opts ...Opt) *Logger

New creates and returns a new logger as a child of the root logger without making it the current logger. Shortcut for log.Root().New().

func Root

func Root() *Logger

Root returns a pointer to the global root logger. The root logger cannot be closed and is always available.

func (*Logger) Close

func (l *Logger) Close() *Logger

Close closes the logger and all its descendants. After closing, the logger and its subtree are marked as closed and cannot be used. The returned pointer is the previous parent (or nil for the root). Once a logger has been closed, it will not send any messages anymore. The root logger cannot be closed. If closed, it will be reinitialized with the default values.

func (*Logger) Debg2

func (l *Logger) Debg2(m string)

Debg2 logs a debug message at level 2.

func (*Logger) Debg2f

func (l *Logger) Debg2f(f string, p ...interface{})

Debg2f logs a formatted debug message at level 2.

func (*Logger) Debg2l

func (l *Logger) Debg2l(f string, p ...interface{})

Debg2l logs a message with late evaluation at debug level 2.

func (*Logger) Debg3

func (l *Logger) Debg3(m string)

Debg3 logs a debug message at level 3.

func (*Logger) Debg3f

func (l *Logger) Debg3f(f string, p ...interface{})

Debg3f logs a formatted debug message at level 3.

func (*Logger) Debg3l

func (l *Logger) Debg3l(f string, p ...interface{})

Debg3l logs a message with late evaluation at debug level 3.

func (*Logger) Debg4

func (l *Logger) Debg4(m string)

Debg4 logs a debug message at level 4.

func (*Logger) Debg4f

func (l *Logger) Debg4f(f string, p ...interface{})

Debg4f logs a formatted debug message at level 4.

func (*Logger) Debg4l

func (l *Logger) Debg4l(f string, p ...interface{})

Debg4l logs a message with late evaluation at debug level 4.

func (*Logger) Debg5

func (l *Logger) Debg5(m string)

Debg5 logs a debug message at level 5.

func (*Logger) Debg5f

func (l *Logger) Debg5f(f string, p ...interface{})

Debg5f logs a formatted debug message at level 5.

func (*Logger) Debg5l

func (l *Logger) Debg5l(f string, p ...interface{})

Debg5l logs a message with late evaluation at debug level 5.

func (*Logger) Debug

func (l *Logger) Debug(m string)

Debug logs a debug message.

func (*Logger) Debugf

func (l *Logger) Debugf(f string, p ...interface{})

Debugf logs a formatted debug message.

func (*Logger) Debugl

func (l *Logger) Debugl(f string, p ...interface{})

Debugl logs a message with late evaluation at debug level.

func (*Logger) Error

func (l *Logger) Error(m string)

Error logs an error message.

func (*Logger) Errorf

func (l *Logger) Errorf(f string, p ...interface{})

Errorf logs a formatted error message.

func (*Logger) Errorl

func (l *Logger) Errorl(f string, p ...interface{})

Errorl logs a message with late evaluation at error level.

func (*Logger) GetLevel

func (l *Logger) GetLevel() Level

GetLevel returns the logger’s current minimum log level.

func (*Logger) GetLocDirectories

func (l *Logger) GetLocDirectories() int

GetLocDirectories returns the number of directory components shown in source locations.

func (*Logger) GetMinLocation

func (l *Logger) GetMinLocation() Level

GetMinLocation returns the logger’s current minimum location level.

func (*Logger) GetMultiLine

func (l *Logger) GetMultiLine() bool

GetMultiLine returns true if multiline mode is on for this logger.

func (*Logger) GetMultiLinePrefix added in v0.2.0

func (l *Logger) GetMultiLinePrefix() *string

GetMultiLinePrefix returns the MultiLinePrefix for this logger.

func (*Logger) GetOutput

func (l *Logger) GetOutput() io.Writer

GetOutput returns the logger’s output writer.

func (*Logger) GetTimeFmt

func (l *Logger) GetTimeFmt() string

GetTimeFmt returns the logger’s time format string.

func (*Logger) Info

func (l *Logger) Info(m string)

Info logs an info message.

func (*Logger) Infof

func (l *Logger) Infof(f string, p ...interface{})

Infof logs a formatted info message.

func (*Logger) Infol

func (l *Logger) Infol(f string, p ...interface{})

Infol logs a message with late evaluation at info level.

func (*Logger) IsClosed

func (l *Logger) IsClosed() bool

IsClosed reports whether the logger has been closed.

func (*Logger) IsCurrent

func (l *Logger) IsCurrent() bool

IsCurrent reports whether the logger is the current package-level logger.

func (*Logger) IsRoot

func (l *Logger) IsRoot() bool

IsRoot reports whether the logger is the root logger.

func (*Logger) Kids

func (l *Logger) Kids(recursive bool) []*Logger

Kids returns a list of this logger’s direct children. If recursive is true, it also includes all descendants (depth-first).

func (*Logger) Log

func (l *Logger) Log(lvl Level, m string)

Log outputs a message at the given level if it meets the logger’s threshold. The output includes a timestamp, level, optional topic, optional source location, and message. In multiline mode, the message is split into lines and each line is prefixed as if it was a log message on its own.

func (*Logger) Logf

func (l *Logger) Logf(lvl Level, f string, p ...interface{})

Logf outputs a formatted message at the given level.

func (*Logger) Logl

func (l *Logger) Logl(lvl Level, f string, p ...interface{})

Logl outputs a formatted message similar to Logf with late evaluation of arguments. Arguments that are functions of type Deferred are called to obtain their value.

Example:

 fib := func(yield func(uint64) bool) {
	    var x, y uint64 = 1, 1
     for {
	         if !yield(x) {return}
	         x, y = y, x+y
	    }
 }

 // the sum will only be calculated if loglevel is >= log.DEBUG
 logger.Logl(
     log.DEBUG,
     `sum of first 1000 fibonacci numbers is %v`,
     log.Lazy(func() interface{} {
	        var sum uint64
	        i := 0
	        for fb := range fib {
	            sum += fb
	            i++
	            if i >= 1000 {break}
	        }
	        return sum
     }),    // log.Lazy() returns a log.Deferred object
 )

func (*Logger) New

func (l *Logger) New(_opts ...Opt) *Logger

New creates a new child logger by copying the current logger’s configuration and applying the given options. The new logger is added to this logger’s children set.

func (*Logger) Notice

func (l *Logger) Notice(m string)

Notice logs a notice message. Notice messages are always printed.

func (*Logger) Noticef

func (l *Logger) Noticef(f string, p ...interface{})

Noticef logs a formatted notice message.

func (*Logger) Noticel

func (l *Logger) Noticel(f string, p ...interface{})

Noticel logs a message with late evaluation at notice level.

func (*Logger) Panic

func (l *Logger) Panic(m string)

Panic logs a panic message and exits with code 1.

func (*Logger) Panicf

func (l *Logger) Panicf(f string, p ...interface{})

Panicf logs a formatted panic message and exits with code 1.

func (*Logger) Panicl

func (l *Logger) Panicl(f string, p ...interface{})

Panicl logs a message with late evaluation at panic level and exits with code 1.

func (*Logger) SetCurrent

func (l *Logger) SetCurrent()

SetCurrent makes this logger the current package-level logger. If l is nil, the root logger becomes current.

func (*Logger) SetLevel

func (l *Logger) SetLevel(lvl Level)

SetLevel sets the minimum log level on the current logger and all its descendants.

func (*Logger) SetLocDirectories

func (l *Logger) SetLocDirectories(n int)

SetLocDirectories sets the number of directory components shown in source locations for this logger and all its descendants.

func (*Logger) SetMinLocation

func (l *Logger) SetMinLocation(lvl Level)

SetMinLocation sets the minimum log level for printing the caller’s source location on this logger and all its descendants. Levels outside the valid range disable location printing.

func (*Logger) SetMultiLine

func (l *Logger) SetMultiLine(ml bool)

SetMultiLine turns multiline mode on or off for this logger and all its descendants.

func (*Logger) SetMultiLinePrefix added in v0.2.0

func (l *Logger) SetMultiLinePrefix(x *string)

SetMultiLinePrefix sets the MultiLinePrefix for this logger and all its descendants.

func (*Logger) SetOutput

func (l *Logger) SetOutput(out io.Writer)

SetOutput sets the output writer for this logger and all its descendants.

func (*Logger) SetTimeFmt

func (l *Logger) SetTimeFmt(f string)

SetTimeFmt sets the time format string for this logger and all its descendants.

func (*Logger) String

func (l *Logger) String() string

String satisfies the Stringer interface.

func (*Logger) Warn

func (l *Logger) Warn(m string)

Warn logs a warning message.

func (*Logger) Warnf

func (l *Logger) Warnf(f string, p ...interface{})

Warnf logs a formatted warning message.

func (*Logger) Warnl

func (l *Logger) Warnl(f string, p ...interface{})

Warnl logs a message with late evaluation at warning level.

type Opt

type Opt func(*LogOpts)

Opt is a function type used to apply optional settings to a LogOpts.

func ParseURL added in v0.2.0

func ParseURL(s string, hnd func(error)) ([]Opt, error)

ParseURL parses an URL-like string into a set of options that can be passed to one of the New functions. The URL is defined like so:

  • the scheme is either omitted or must be "file:"

  • the user part can be the log level, "INFO@"

  • the host part is either empty or a single dot to signify a relative path name

  • if a relative or absolute path name is specified, a rotate object is created as output. ParseURL itself only creates a promise to create such an object when any of the New functions is called. If the actual creation fails, New will return nil. The "hnd" parameter should be used in this case to catch any error.

  • the host part can also be either "stderr", "stdout" or a number. In that case either *os.Stderr, *os.Stdout or an *os.File connected to the file descriptor passed as the number is used. This allows commands like

    program 5>logfile --logurl=//DEBUG@5?multiline=true

    Note, in the FD form, the file descriptor will be attached to an *os.File object. Once that object becomes inaccessible and is garbage collected, the file will be closed. If you need the file descriptor elsewhere, dup() it.

Here are some URL examples:

# [rotate] objects with absolute paths

file://LEVEL@/absolute/path/to/file?KEY=VALUE&KEY=VALUE...
//LEVEL@/absolute/path/to/file?KEY=VALUE&KEY=VALUE...
file:///absolute/path/to/file?level=LEVEL&KEY=VALUE&KEY=VALUE...
file:/absolute/path/to/file?level=LEVEL&KEY=VALUE&KEY=VALUE...
/absolute/path/to/file?level=LEVEL&KEY=VALUE&KEY=VALUE...

# [rotate] objects with relative paths

file://LEVEL@./relative/path/to/file?KEY=VALUE&KEY=VALUE...
//LEVEL@./relative/path/to/file?KEY=VALUE&KEY=VALUE...
file://LEVEL@/./relative/path/to/file?KEY=VALUE&KEY=VALUE...
//LEVEL@/./relative/path/to/file?KEY=VALUE&KEY=VALUE...
file:/./relative/path/to/file?level=LEVEL&KEY=VALUE&KEY=VALUE...
/./relative/path/to/file?level=LEVEL&KEY=VALUE&KEY=VALUE...
relative/path/to/file?level=LEVEL&KEY=VALUE&KEY=VALUE...

# stderr, stdout, fd

file://LEVEL@stderr?KEY=VALUE...
//LEVEL@stdout?KEY=VALUE...
//5?level=LEVEL&KEY=VALUE...

Known query parameters:

URL parsing fails for various reasons. In particular it fails if any of the log levels cannot be interpreted or the "LEVEL@" part is given but the "level=LEVEL" query parameter specifies a different value (that's ambiguous). It also fails if a query parameter is given multiple times or if an unknown query parameter is given. Query parameters are case-sensitive. Furthermore, it does not make sense to specify a "maxsize" for instance for a non-rotate destination. So, that will also fail.

Example usage:

var err error
opts, err := log.ParseURL(url, func(e error) {err = e})
if err != nil {
    // handle ParseURL error
}
lg := log.L().New(append(opts, log.WithTopic("OVERRIDE-TOPIC"))...)
if lg == nil {
    // err now contains the error generated by rotate.New()
}
Example (Fd)
package main

import (
	"fmt"
	"github.com/tfoertsch123/log"
	"os"
	"syscall"
	"time"
)

func main() {
	// Use SetNow() to generate a fixed timestamp. This is only needed
	// to have this pass as a test so that go doc includes the example.
	defer func(orig func() time.Time) { log.SetNow(orig) }(log.SetNow(func() time.Time {
		return time.Date(2026, 10, 5, 9, 2, 5, 987654321, time.UTC)
	}))
	defer log.Root().Close() // reset/close all loggers

	// This example demonstrates the use of an open file descriptor as
	// the log destination. In Bash, that could be achieved like so:
	//
	//   program 5>logfile --logurl="file://5?timeformat&..."
	//
	// Here we just dup() stdout. We have to dup() it because the file
	// descriptor is internally assigned to an *os.File which has a cleanup
	// function attached so that the file will be closed by the next
	// run of the garbage collector when the logger becomes unreachable.
	fd, err := syscall.Dup(int(os.Stdout.Fd()))
	if err != nil {
		panic("unexpected error in syscall.Dup()")
	}
	defer syscall.Close(fd)

	url := fmt.Sprintf(
		"//%d?"+
			"timeformat=2006-01-02%2015%3A04&"+
			"locdirs=1&"+
			"topic=EXAMPLE&"+
			"level=debug",
		fd,
	)
	log.Root().Noticef("Using URL %q", url)

	if opts, e := log.ParseURL(url, nil); e == nil {
		log.NewC(opts...)
	} else {
		panic(fmt.Sprintf("ParseURL: %v", e))
	}

	log.Info("Info Message")
	log.Debug("Debug Message") // this is line 51
	log.Debg2("Debg2 Message")

	log.NewC(log.WithTopic("MAIN"))

	log.Info("Info Message")
	log.Debug("Debug Message") // this is line 57
	log.Debg2("Debg2 Message")

}
Output:
2026-10-05:02 INFO [EXAMPLE] Info Message
2026-10-05:02 DEBUG [EXAMPLE] (log/exmpl07_URL_fd_test.go:51) Debug Message
2026-10-05:02 INFO [MAIN] Info Message
2026-10-05:02 DEBUG [MAIN] (log/exmpl07_URL_fd_test.go:57) Debug Message
Example (Rotate)
package main

import (
	"fmt"
	"github.com/tfoertsch123/log"
	"os"
	"path/filepath"
	"time"
)

func main() {
	// Use SetNow() to generate a fixed timestamp. This is only needed
	// to have this pass as a test so that go doc includes the example.
	defer func(orig func() time.Time) { log.SetNow(orig) }(log.SetNow(func() time.Time {
		return time.Date(2026, 10, 5, 9, 2, 5, 987654321, time.UTC)
	}))

	// Setup a temp directory for log files
	dir, err := os.MkdirTemp("", "Example_ParseURL_rotate")
	if err != nil {
		panic(err)
	}
	defer os.RemoveAll(dir) // cleanup

	cat := func(fn string) {
		data, err := os.ReadFile(filepath.Join(dir, fn))
		if err != nil {
			panic(err)
		}
		fmt.Printf("file %s, len %d:\n%s\n", fn, len(data), string(data))
	}

	log.Root().Noticef("logfile is in %q", dir)
	defer log.Root().Close() // reset/close all loggers

	logf := "test.log"
	url := "//DEBUG@" + dir + "/" + logf + "?" +
		"maxsize=100&" +
		"nbackups=5&" +
		"timeformat=2006-01-02%2015%3A04&" +
		"locdirs=1&" +
		"topic=EXAMPLE"

	if opts, e := log.ParseURL(url, nil); e == nil {
		log.NewC(opts...)
	} else {
		panic(fmt.Sprintf("ParseURL: %v", e))
	}

	log.Info("Info Message")
	log.Debug("Debug Message") // this is line 29
	log.Debg2("Debg2 Message")

	// give it some time to rotate
	time.Sleep(100 * time.Millisecond)

	log.NewC(log.WithTopic("MAIN"))

	log.Info("Info Message")
	log.Debug("Debug Message") // this is line 35
	log.Debg2("Debg2 Message")

	// We should have triggered a 2nd rotation, maxsize=100
	time.Sleep(100 * time.Millisecond)

	cat(logf)
	cat(logf + "~")
	cat(logf + "~2")

}
Output:
file test.log, len 0:

file test.log~, len 122:
2026-10-05 09:02 INFO [MAIN] Info Message
2026-10-05 09:02 DEBUG [MAIN] (log/exmpl06_URL_rotate_test.go:60) Debug Message

file test.log~2, len 128:
2026-10-05 09:02 INFO [EXAMPLE] Info Message
2026-10-05 09:02 DEBUG [EXAMPLE] (log/exmpl06_URL_rotate_test.go:51) Debug Message
Example (Stdout)
package main

import (
	"fmt"
	"github.com/tfoertsch123/log"
	"time"
)

func main() {
	// Use SetNow() to generate a fixed timestamp. This is only needed
	// to have this pass as a test so that go doc includes the example.
	defer func(orig func() time.Time) { log.SetNow(orig) }(log.SetNow(func() time.Time {
		return time.Date(2026, 10, 5, 9, 2, 5, 987654321, time.UTC)
	}))
	defer log.Root().Close() // reset/close all loggers

	// This URL sends the log output to Stdout. It configures os.Stdout
	// as output. Instead of stdout, stderr can also be used.
	url := "//DEBUG@stdout?" +
		"timeformat=2006-01-02%2015%3A04&" +
		"locdirs=1&" +
		"topic=EXAMPLE"

	if opts, e := log.ParseURL(url, nil); e == nil {
		log.NewC(opts...)
	} else {
		panic(fmt.Sprintf("ParseURL: %v", e))
	}

	log.Info("Info Message")
	log.Debug("Debug Message") // this is line 31
	log.Debg2("Debg2 Message")

	log.NewC(log.WithTopic("MAIN"))

	log.Info("Info Message")
	log.Debug("Debug Message") // this is line 37
	log.Debg2("Debg2 Message")

}
Output:
2026-10-05 09:02 INFO [EXAMPLE] Info Message
2026-10-05 09:02 DEBUG [EXAMPLE] (log/exmpl05_URL_stdout_test.go:31) Debug Message
2026-10-05 09:02 INFO [MAIN] Info Message
2026-10-05 09:02 DEBUG [MAIN] (log/exmpl05_URL_stdout_test.go:37) Debug Message

func WithLevel

func WithLevel(lv Level) Opt

WithLevel returns an Opt that sets the minimum log level for output.

func WithLocDirectories

func WithLocDirectories(n int) Opt

WithLocDirectories returns an Opt that sets the number of directory components to include in the printed source location. Negative values print the full path.

func WithMinLocation

func WithMinLocation(lv Level) Opt

WithMinLocation returns an Opt that sets the minimum log level for printing the caller’s source location. Levels outside [NOTICE+1, DEBG5] disable location printing.

func WithMultiLine

func WithMultiLine(x bool) Opt

WithMultiLine returns an Opt that turns on/off multiline mode. In multiline mode, line breaks in the log message are detected and each line is prefixed with the normal line prefix or the MultiLinePrefix if set.

func WithMultiLinePrefix added in v0.2.0

func WithMultiLinePrefix(x *string) Opt

WithMLPrefix returns an Opt that sets the MultiLinePrefix. This is used in combination with MultiLineMode. By default, the multiline message "this\nis a\nmultiline\nmessage" will be rendered like so:

2026-10-05 09:02 NOTICE this
2026-10-05 09:02 NOTICE is a
2026-10-05 09:02 NOTICE multiline
2026-10-05 09:02 NOTICE message

If the MultiLinePrefix is set to "+", it becomes

2026-10-05 09:02 NOTICE this
+                       is a
+                       multiline
+                       message

The empty string is also accepted. If nil is passed, the default behavior is restored.

func WithOutput

func WithOutput(out io.Writer) Opt

WithOutput returns an Opt that sets the output writer.

func WithOutputFactory added in v0.2.0

func WithOutputFactory(c OutputFactory, hnd OutputFactoryErrorHandler) Opt

WithOutputFactory returns an Opt that allows delayed creation of the output writer. The main intend of this to work in combination with ParseURL. An OutputFactory is a function returning an io.Writer and an error. The callback function is called as part of [New]. If the returned error is nil, the produced io.writer becomes the output of the new logger. If the error is different from nil, the OutputFactoryErrorHandler is called with the error as the sole parameter. The resulting logger is then nil. If both, WithOutput and WithOutputFactory, are used, WithOutputFactory is ignored.

func WithTimeFmt

func WithTimeFmt(f string) Opt

WithTimeFmt returns an Opt that sets the time format string. The string is passed to time.Format in order to format the time stamp.

func WithTopic

func WithTopic(tp string) Opt

WithTopic returns an Opt that sets the log topic string. The topic is prepended in square brackets (e.g. " [mytopic]"). An empty topic disables the topic prefix.

type OutputFactory added in v0.2.0

type OutputFactory func() (io.Writer, error)

type OutputFactoryErrorHandler added in v0.2.0

type OutputFactoryErrorHandler func(error)

Directories

Path Synopsis
examples
ex1 command
ex2 command
Package rotate implements a size-based log file rotator.
Package rotate implements a size-based log file rotator.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL