log

package module
v1.0.75 Latest Latest
Warning

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

Go to latest
Published: May 8, 2024 License: MIT Imports: 28 Imported by: 28

README

phuslog - Fastest structured logging

godoc goreport build stability-stable

Features

  • Dependency Free
  • Simple and Clean Interface
  • Consistent Writer
    • IOWriter, io.Writer wrapper
    • ConsoleWriter, colorful & formatting
    • FileWriter, rotating & effective
    • MultiLevelWriter, multiple level dispatch
    • SyslogWriter, memory efficient syslog
    • JournalWriter, linux systemd logging
    • EventlogWriter, windows system event
    • AsyncWriter, asynchronously writing
  • Stdlib Log Adapter
    • Logger.Std, transform to std log instances
    • Logger.Slog, transform to log/slog instances
  • Third-party Logger Interceptor
    • logr, logr interceptor
    • gin, gin logging middleware
    • gorm, gorm logger interface
    • fiber, fiber logging handler
    • grpc, grpc logger interceptor
    • grpcgateway, grpcgateway logger interceptor
  • Useful utility function
    • Goid(), the goroutine id matches stack trace
    • NewXID(), create a tracing id
    • Fastrandn(n uint32), fast pseudorandom uint32 in [0,n)
    • IsTerminal(fd uintptr), isatty for golang
    • Printf(fmt string, a ...interface{}), printf logging
  • High Performance

Interfaces

Logger
// DefaultLogger is the global logger.
var DefaultLogger = Logger{
	Level:      DebugLevel,
	Caller:     0,
	TimeField:  "",
	TimeFormat: "",
	Writer:     &IOWriter{os.Stderr},
}

// Logger represents an active logging object that generates lines of JSON output to an io.Writer.
type Logger struct {
	// Level defines log levels.
	Level Level

	// Caller determines if adds the file:line of the "caller" key.
	// If Caller is negative, adds the full /path/to/file:line of the "caller" key.
	Caller int

	// TimeField defines the time field name in output.  It uses "time" in if empty.
	TimeField string

	// TimeFormat specifies the time format in output. Uses RFC3339 with millisecond if empty.
	// If set to `TimeFormatUnix/TimeFormatUnixMs`, timestamps will be formatted.
	TimeFormat string

	// TimeLocation specifices that the location of TimeFormat used. Uses time.Local if empty.
	TimeLocation *time.Location

	// Writer specifies the writer of output. It uses a wrapped os.Stderr Writer in if empty.
	Writer Writer
}
ConsoleWriter
// ConsoleWriter parses the JSON input and writes it in a colorized, human-friendly format to Writer.
// IMPORTANT: Don't use ConsoleWriter on critical path of a high concurrency and low latency application.
//
// Default output format:
//     {Time} {Level} {Goid} {Caller} > {Message} {Key}={Value} {Key}={Value}
type ConsoleWriter struct {
	// ColorOutput determines if used colorized output.
	ColorOutput bool

	// QuoteString determines if quoting string values.
	QuoteString bool

	// EndWithMessage determines if output message in the end of line.
	EndWithMessage bool

	// Writer is the output destination. using os.Stderr if empty.
	Writer io.Writer

	// Formatter specifies an optional text formatter for creating a customized output,
	// If it is set, ColorOutput, QuoteString and EndWithMessage will be ignored.
	Formatter func(w io.Writer, args *FormatterArgs) (n int, err error)
}

// FormatterArgs is a parsed sturct from json input
type FormatterArgs struct {
	Time      string // "2019-07-10T05:35:54.277Z"
	Message   string // "a structure message"
	Level     string // "info"
	Caller    string // "main.go:123"
	Goid      string // "1"
	Stack     string // "<stack string>"
	KeyValues []struct {
		Key       string // "foo"
		Value     string // "bar"
	}
}
FileWriter
// FileWriter is an Writer that writes to the specified filename.
type FileWriter struct {
	// Filename is the file to write logs to.  Backup log files will be retained
	// in the same directory.
	Filename string

	// FileMode represents the file's mode and permission bits.  The default
	// mode is 0644
	FileMode os.FileMode

	// MaxSize is the maximum size in bytes of the log file before it gets rotated.
	MaxSize int64

	// MaxBackups is the maximum number of old log files to retain.  The default
	// is to retain all old log files
	MaxBackups int

	// TimeFormat specifies the time format of filename, uses `2006-01-02T15-04-05` as default format.
	// If set with `TimeFormatUnix`, `TimeFormatUnixMs`, times are formated as UNIX timestamp.
	TimeFormat string

	// LocalTime determines if the time used for formatting the timestamps in
	// log files is the computer's local time.  The default is to use UTC time.
	LocalTime bool

	// HostName determines if the hostname used for formatting in log files.
	HostName bool

	// ProcessID determines if the pid used for formatting in log files.
	ProcessID bool

	// EnsureFolder ensures the file directory creation before writing.
	EnsureFolder bool

	// Header specifies an optional header function of log file after rotation,
	Header func(fileinfo os.FileInfo) []byte

	// Cleaner specifies an optional cleanup function of log backups after rotation,
	// if not set, the default behavior is to delete more than MaxBackups log files.
	Cleaner func(filename string, maxBackups int, matches []os.FileInfo)
}

Highlights:

  • FileWriter implements log.Writer and io.Writer interfaces both, it is a recommended alternative to lumberjack.
  • FileWriter creates a symlink to the current logging file, it requires administrator privileges on Windows.
  • FileWriter does not rotate if you define a broad TimeFormat value(daily or monthly) until reach its MaxSize.

Getting Started

Simple Logging Example

An out of box example. playground

package main

import (
	"github.com/phuslu/log"
)

func main() {
	log.Info().Str("foo", "bar").Int("number", 42).Msg("hi, phuslog")
	log.Info().Msgf("foo=%s number=%d error=%+v", "bar", 42, "an error")
}

// Output:
//   {"time":"2020-03-22T09:58:41.828Z","level":"info","foo":"bar","number":42,"message":"hi, phuslog"}
//   {"time":"2020-03-22T09:58:41.828Z","level":"info","message":"foo=bar number=42 error=an error"}

Note: By default log writes to os.Stderr

Customize the configuration and formatting:

To customize logger filed name and format. playground

package main

import (
	"github.com/phuslu/log"
)

func main() {
	log.DefaultLogger = log.Logger{
		Level:      log.InfoLevel,
		Caller:     1,
		TimeField:  "date",
		TimeFormat: "2006-01-02",
		Writer:     &log.IOWriter{os.Stdout},
	}

	log.Info().Str("foo", "bar").Msgf("hello %s", "world")

	logger := log.Logger{
		Level:      log.InfoLevel,
		TimeField:  "ts",
		TimeFormat: log.TimeFormatUnixMs,
	}

	logger.Log().Str("foo", "bar").Msg("")
}

// Output:
//    {"date":"2019-07-04","level":"info","caller":"prog.go:16","foo":"bar","message":"hello world"}
//    {"ts":1257894000000,"foo":"bar"}
Customize the log writer

To allow the use of ordinary functions as log writers, use WriterFunc.

logger := log.Logger{
	Writer: log.WriterFunc(func(e *log.Entry) (int, error) {
		if e.Level >= log.ErrorLevel {
			return os.Stderr.Write(e.Value())
		} else {
			return os.Stdout.Write(e.Value())
		}
	}),
}

logger.Info().Msg("a stdout entry")
logger.Error().Msg("a stderr entry")
Pretty Console Writer

To log a human-friendly, colorized output, use ConsoleWriter. playground

if log.IsTerminal(os.Stderr.Fd()) {
	log.DefaultLogger = log.Logger{
		TimeFormat: "15:04:05",
		Caller:     1,
		Writer: &log.ConsoleWriter{
			ColorOutput:    true,
			QuoteString:    true,
			EndWithMessage: true,
		},
	}
}

log.Debug().Int("everything", 42).Str("foo", "bar").Msg("hello world")
log.Info().Int("everything", 42).Str("foo", "bar").Msg("hello world")
log.Warn().Int("everything", 42).Str("foo", "bar").Msg("hello world")
log.Error().Err(errors.New("an error")).Msg("hello world")

Pretty logging

Note: pretty logging also works on windows console

Formatting Console Writer

To log with user-defined format(e.g. glog), using ConsoleWriter.Formatter. playground

package main

import (
	"fmt"
	"io"

	"github.com/phuslu/log"
)

type Glog struct {
	Logger log.Logger
}

func (l *Glog) Infof(fmt string, a ...any) { l.Logger.Info().Msgf(fmt, a...) }

func (l *Glog) Warnf(fmt string, a ...any) { l.Logger.Warn().Msgf(fmt, a...) }

func (l *Glog) Errorf(fmt string, a ...any) { l.Logger.Error().Msgf(fmt, a...) }

var glog = &Glog{log.Logger{
	Level:      log.InfoLevel,
	Caller:     2,
	TimeFormat: "0102 15:04:05.999999",
	Writer: &log.ConsoleWriter{Formatter: func(w io.Writer, a *log.FormatterArgs) (int, error) {
		return fmt.Fprintf(w, "%c%s %s %s] %s\n%s", a.Level[0]-32, a.Time, a.Goid, a.Caller, a.Message, a.Stack)
	}},
}}

func main() {
	glog.Infof("hello glog %s", "Info")
	glog.Warnf("hello glog %s", "Warn")
	glog.Errorf("hello glog %s", "Error")
}

// Output:
// I0725 09:59:57.503246 19 console_test.go:183] hello glog Info
// W0725 09:59:57.504247 19 console_test.go:184] hello glog Warn
// E0725 09:59:57.504247 19 console_test.go:185] hello glog Error
Formatting Logfmt output

To log with logfmt format, also using ConsoleWriter.Formatter. playground

package main

import (
	"io"
	"os"

	"github.com/phuslu/log"
)

func main() {
	log.DefaultLogger = log.Logger{
		Level:      log.InfoLevel,
		Caller:     1,
		TimeField:  "ts",
		TimeFormat: log.TimeFormatUnixWithMs,
		Writer: &log.ConsoleWriter{
			Formatter: log.LogfmtFormatter{"ts"}.Formatter,
			Writer:    io.MultiWriter(os.Stdout, os.Stderr),
		},
	}

	log.Info().Str("foo", "bar").Int("no", 42).Msgf("a logfmt %s", "info")
}

// Output:
// ts=1257894000.000 level=info goid=1 caller="prog.go:20" foo="bar" no=42 "a logfmt info"
// ts=1257894000.000 level=info goid=1 caller="prog.go:20" foo="bar" no=42 "a logfmt info"
Rotating File Writer

To log to a daily-rotating file, use FileWriter. playground

package main

import (
	"os"
	"path/filepath"
	"time"

	"github.com/phuslu/log"
	"github.com/robfig/cron/v3"
)

func main() {
	logger := log.Logger{
		Level: log.ParseLevel("info"),
		Writer: &log.FileWriter{
			Filename:     "logs/main.log",
			FileMode:     0600,
			MaxSize:      100 * 1024 * 1024,
			MaxBackups:   7,
			EnsureFolder: true,
			LocalTime:    true,
		},
	}

	runner := cron.New(cron.WithLocation(time.Local))
	runner.AddFunc("0 0 * * *", func() { logger.Writer.(*log.FileWriter).Rotate() })
	go runner.Run()

	for {
		time.Sleep(time.Second)
		logger.Info().Msg("hello world")
	}
}
Rotating File Writer within a total size

To rotating log file hourly and keep in a total size, use FileWriter.Cleaner.

package main

import (
	"os"
	"path/filepath"
	"time"

	"github.com/phuslu/log"
	"github.com/robfig/cron/v3"
)

func main() {
	logger := log.Logger{
		Level: log.ParseLevel("info"),
		Writer: &log.FileWriter{
			Filename: "main.log",
			MaxSize:  500 * 1024 * 1024,
			Cleaner:  func(filename string, maxBackups int, matches []os.FileInfo) {
				var dir = filepath.Dir(filename)
				var total int64
				for i := len(matches) - 1; i >= 0; i-- {
					total += matches[i].Size()
					if total > 5*1024*1024*1024 {
						os.Remove(filepath.Join(dir, matches[i].Name()))
					}
				}
			},
		},
	}

	runner := cron.New(cron.WithLocation(time.UTC))
	runner.AddFunc("0 * * * *", func() { logger.Writer.(*log.FileWriter).Rotate() })
	go runner.Run()

	for {
		time.Sleep(time.Second)
		logger.Info().Msg("hello world")
	}
}
Rotating File Writer with compression

To rotating log file hourly and compressing after rotation, use FileWriter.Cleaner.

package main

import (
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"github.com/phuslu/log"
	"github.com/robfig/cron/v3"
)

func main() {
	logger := log.Logger{
		Level: log.ParseLevel("info"),
		Writer: &log.FileWriter{
			Filename: "main.log",
			MaxSize:  500 * 1024 * 1024,
			Cleaner:  func(filename string, maxBackups int, matches []os.FileInfo) {
				var dir = filepath.Dir(filename)
				for i, fi := range matches {
					filename := filepath.Join(dir, fi.Name())
					switch {
					case i > maxBackups:
						os.Remove(filename)
					case !strings.HasSuffix(filename, ".gz"):
						go exec.Command("nice", "gzip", filename).Run()
					}
				}
			},
		},
	}

	runner := cron.New(cron.WithLocation(time.UTC))
	runner.AddFunc("0 * * * *", func() { logger.Writer.(*log.FileWriter).Rotate() })
	go runner.Run()

	for {
		time.Sleep(time.Second)
		logger.Info().Msg("hello world")
	}
}
Random Sample Logger:

To logging only 5% logs, use below idiom.

if log.Fastrandn(100) < 5 {
	log.Log().Msg("hello world")
}
Multiple Dispatching Writer

To log to different writers by different levels, use MultiLevelWriter.

log.DefaultLogger.Writer = &log.MultiLevelWriter{
	InfoWriter:    &log.FileWriter{Filename: "main.INFO", MaxSize: 100<<20},
	WarnWriter:    &log.FileWriter{Filename: "main.WARNING", MaxSize: 100<<20},
	ErrorWriter:   &log.FileWriter{Filename: "main.ERROR", MaxSize: 100<<20},
	ConsoleWriter: &log.ConsoleWriter{ColorOutput: true},
	ConsoleLevel:  log.ErrorLevel,
}

log.Info().Int("number", 42).Str("foo", "bar").Msg("a info log")
log.Warn().Int("number", 42).Str("foo", "bar").Msg("a warn log")
log.Error().Int("number", 42).Str("foo", "bar").Msg("a error log")
Multiple Entry Writer

To log to different writers, use MultiEntryWriter.

log.DefaultLogger.Writer = &log.MultiEntryWriter{
	&log.ConsoleWriter{ColorOutput: true},
	&log.FileWriter{Filename: "main.log", MaxSize: 100<<20},
	&log.EventlogWriter{Source: ".NET Runtime", ID: 1000},
}

log.Info().Int("number", 42).Str("foo", "bar").Msg("a info log")
Multiple IO Writer

To log to multiple io writers like io.MultiWriter, use below idiom. playground

log.DefaultLogger.Writer = &log.MultiIOWriter{
	os.Stdout,
	&log.FileWriter{Filename: "main.log", MaxSize: 100<<20},
}

log.Info().Int("number", 42).Str("foo", "bar").Msg("a info log")
Multiple Combined Logger:

To logging to different logger as you want, use below idiom. playground

package main

import (
	"github.com/phuslu/log"
)

var logger = struct {
	Console log.Logger
	Access  log.Logger
	Data    log.Logger
}{
	Console: log.Logger{
		TimeFormat: "15:04:05",
		Caller:     1,
		Writer: &log.ConsoleWriter{
			ColorOutput:    true,
			EndWithMessage: true,
		},
	},
	Access: log.Logger{
		Level: log.InfoLevel,
		Writer: &log.FileWriter{
			Filename:   "access.log",
			MaxSize:    50 * 1024 * 1024,
			MaxBackups: 7,
			LocalTime:  false,
		},
	},
	Data: log.Logger{
		Level: log.InfoLevel,
		Writer: &log.FileWriter{
			Filename:   "data.log",
			MaxSize:    50 * 1024 * 1024,
			MaxBackups: 7,
			LocalTime:  false,
		},
	},
}

func main() {
	logger.Console.Info().Msgf("hello world")
	logger.Access.Log().Msgf("handle request")
	logger.Data.Log().Msgf("some data")
}
SyslogWriter

SyslogWriter is a memory-efficient, cross-platform, dependency-free syslog writer, outperforms all other structured logging libraries.

package main

import (
	"net"
	"time"

	"github.com/phuslu/log"
)

func main() {
	go func() {
		ln, _ := net.Listen("tcp", "127.0.0.1:1601")
		for {
			conn, _ := ln.Accept()
			go func(c net.Conn) {
				b := make([]byte, 8192)
				n, _ := conn.Read(b)
				println(string(b[:n]))
			}(conn)
		}
	}()

	syslog := log.Logger{
		Level:      log.InfoLevel,
		TimeField:  "ts",
		TimeFormat: log.TimeFormatUnixMs,
		Writer: &log.SyslogWriter{
			Network: "tcp",            // "unixgram",
			Address: "127.0.0.1:1601", // "/run/systemd/journal/syslog",
			Tag:     "",
			Marker:  "@cee:",
			Dial:    net.Dial,
		},
	}

	syslog.Info().Str("foo", "bar").Int("an", 42).Msg("a syslog info")
	syslog.Warn().Str("foo", "bar").Int("an", 42).Msg("a syslog warn")
	time.Sleep(2)
}

// Output:
// <6>2022-07-24T18:48:15+08:00 127.0.0.1:59277 [11516]: @cee:{"ts":1658659695428,"level":"info","foo":"bar","an":42,"message":"a syslog info"}
// <4>2022-07-24T18:48:15+08:00 127.0.0.1:59277 [11516]: @cee:{"ts":1658659695429,"level":"warn","foo":"bar","an":42,"message":"a syslog warn"}
JournalWriter

To log to linux systemd journald, using JournalWriter.

log.DefaultLogger.Writer = &log.JournalWriter{
	JournalSocket: "/run/systemd/journal/socket",
}

log.Info().Int("number", 42).Str("foo", "bar").Msg("hello world")
EventlogWriter

To log to windows system event, using EventlogWriter.

log.DefaultLogger.Writer = &log.EventlogWriter{
	Source: ".NET Runtime",
	ID:     1000,
}

log.Info().Int("number", 42).Str("foo", "bar").Msg("hello world")
AsyncWriter

To logging asynchronously for performance stability, use AsyncWriter.

logger := log.Logger{
	Level:  log.InfoLevel,
	Writer: &log.AsyncWriter{
		ChannelSize: 100,
		Writer:      &log.FileWriter{
			Filename:   "main.log",
			FileMode:   0600,
			MaxSize:    50*1024*1024,
			MaxBackups: 7,
			LocalTime:  false,
		},
	},
}

logger.Info().Int("number", 42).Str("foo", "bar").Msg("a async info log")
logger.Warn().Int("number", 42).Str("foo", "bar").Msg("a async warn log")
logger.Writer.(io.Closer).Close()

Note: To flush data and quit safely, call AsyncWriter.Close() explicitly.

Stdlib Log Adapter

Using wrapped loggers for stdlog. playground

package main

import (
	stdlog "log"
	"os"

	"github.com/phuslu/log"
)

func main() {
	var logger *stdlog.Logger = (&log.Logger{
		Level:      log.InfoLevel,
		TimeField:  "date",
		TimeFormat: "2006-01-02",
		Caller:     1,
		Context:    log.NewContext(nil).Str("logger", "mystdlog").Int("myid", 42).Value(),
		Writer:     &log.IOWriter{os.Stdout},
	}).Std("", 0)

	logger.Print("hello from stdlog Print")
	logger.Println("hello from stdlog Println")
	logger.Printf("hello from stdlog %s", "Printf")
}
slog Adapter

Using wrapped loggers for slog. playground

package main

import (
	"log/slog"

	"github.com/phuslu/log"
)

func main() {
	var logger *slog.Logger = (&log.Logger{
		Level:      log.InfoLevel,
		TimeField:  "date",
		TimeFormat: "2006-01-02",
		Caller:     1,
	}).Slog()

	logger = logger.With("logger", "a_test_slog").With("everything", 42)

	logger.Info("hello from slog Info")
	logger.Warn("hello from slog Warn")
	logger.Error("hello from slog Error")
}
Third-party Logger Interceptor
Logger Interceptor
logr https://github.com/phuslu/log-contrib/tree/master/logr
gin https://github.com/phuslu/log-contrib/tree/master/gin
fiber https://github.com/phuslu/log-contrib/tree/master/fiber
gorm https://github.com/phuslu/log-contrib/tree/master/gorm
grpc https://github.com/phuslu/log-contrib/tree/master/grpc
grpcgateway https://github.com/phuslu/log-contrib/tree/master/grpcgateway
User-defined Data Structure

To log with user-defined struct effectively, implements MarshalObject. playground

package main

import (
	"github.com/phuslu/log"
)

type User struct {
	ID   int
	Name string
	Pass string
}

func (u *User) MarshalObject(e *log.Entry) {
	e.Int("id", u.ID).Str("name", u.Name).Str("password", "***")
}

func main() {
	log.Info().Object("user", &User{1, "neo", "123456"}).Msg("")
	log.Info().EmbedObject(&User{2, "john", "abc"}).Msg("")
}

// Output:
//   {"time":"2020-07-12T05:03:43.949Z","level":"info","user":{"id":1,"name":"neo","password":"***"}}
//   {"time":"2020-07-12T05:03:43.949Z","level":"info","id":2,"name":"john","password":"***"}
Contextual Fields

To add preserved key:value pairs to each entry, use NewContext. playground

logger := log.Logger{
	Level:   log.InfoLevel,
	Context: log.NewContext(nil).Str("ctx", "some_ctx").Value(),
}

logger.Debug().Int("no0", 0).Msg("zero")
logger.Info().Int("no1", 1).Msg("first")
logger.Info().Int("no2", 2).Msg("second")

// Output:
//   {"time":"2020-07-12T05:03:43.949Z","level":"info","ctx":"some_ctx","no1":1,"message":"first"}
//   {"time":"2020-07-12T05:03:43.949Z","level":"info","ctx":"some_ctx","no2":2,"message":"second"}

You can make a copy of log and add contextual fields. playground

package main

import (
	"github.com/phuslu/log"
)

func main() {
	sublogger := log.DefaultLogger
	sublogger.Level = log.InfoLevel
	sublogger.Context = log.NewContext(nil).Str("ctx", "some_ctx").Value()

	sublogger.Debug().Int("no0", 0).Msg("zero")
	sublogger.Info().Int("no1", 1).Msg("first")
	sublogger.Info().Int("no2", 2).Msg("second")
	log.Debug().Int("no3", 3).Msg("no context")
}

// Output:
//   {"time":"2021-06-14T06:36:42.904+02:00","level":"info","ctx":"some_ctx","no1":1,"message":"first"}
//   {"time":"2021-06-14T06:36:42.905+02:00","level":"info","ctx":"some_ctx","no2":2,"message":"second"}
//   {"time":"2021-06-14T06:36:42.906+02:00","level":"debug","no3":3,"message":"no context"}
High Performance
The most common benchmarks(disable/normal/caller/printf/interface) against slog/zap/zerolog
// go test -v -cpu=4 -run=none -bench=. -benchtime=10s -benchmem bench_test.go
package main

import (
	"io"
	"log"
	"log/slog"
	"testing"

	phuslog "github.com/phuslu/log"
	"github.com/rs/zerolog"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

const msg = "The quick brown fox jumps over the lazy dog"
var obj = struct {Rate string; Low int; High float32}{"15", 16, 123.2}

func BenchmarkSlogDisable(b *testing.B) {
	logger := slog.New(slog.NewJSONHandler(io.Discard, nil))
	for i := 0; i < b.N; i++ {
		logger.Debug(msg, "rate", "15", "low", 16, "high", 123.2)
	}
}

func BenchmarkSlogNormal(b *testing.B) {
	logger := slog.New(slog.NewJSONHandler(io.Discard, nil))
	for i := 0; i < b.N; i++ {
		logger.Info(msg, "rate", "15", "low", 16, "high", 123.2)
	}
}

func BenchmarkSlogPrintf(b *testing.B) {
	slog.SetDefault(slog.New(slog.NewJSONHandler(io.Discard, nil)))
	for i := 0; i < b.N; i++ {
		log.Printf("rate=%s low=%d high=%f msg=%s", "15", 16, 123.2, msg)
	}
}

func BenchmarkSlogCaller(b *testing.B) {
	logger := slog.New(slog.NewJSONHandler(io.Discard, &slog.HandlerOptions{AddSource: true}))
	for i := 0; i < b.N; i++ {
		logger.Info(msg, "rate", "15", "low", 16, "high", 123.2)
	}
}

func BenchmarkSlogInterface(b *testing.B) {
	logger := slog.New(slog.NewJSONHandler(io.Discard, nil))
	for i := 0; i < b.N; i++ {
		logger.Info(msg, "object", &obj)
	}
}

func BenchmarkZapDisable(b *testing.B) {
	logger := zap.New(zapcore.NewCore(
		zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
		zapcore.AddSync(io.Discard),
		zapcore.InfoLevel,
	)).Sugar()
	for i := 0; i < b.N; i++ {
		logger.Debugw(msg, "rate", "15", "low", 16, "high", 123.2)
	}
}

func BenchmarkZapNormal(b *testing.B) {
	logger := zap.New(zapcore.NewCore(
		zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
		zapcore.AddSync(io.Discard),
		zapcore.InfoLevel,
	)).Sugar()
	for i := 0; i < b.N; i++ {
		logger.Infow(msg, "rate", "15", "low", 16, "high", 123.2)
	}
}

func BenchmarkZapPrintf(b *testing.B) {
	logger := zap.New(zapcore.NewCore(
		zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
		zapcore.AddSync(io.Discard),
		zapcore.InfoLevel,
	)).Sugar()
	for i := 0; i < b.N; i++ {
		logger.Infof("rate=%s low=%d high=%f msg=%s", "15", 16, 123.2, msg)
	}
}

func BenchmarkZapCaller(b *testing.B) {
	logger := zap.New(zapcore.NewCore(
		zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
		zapcore.AddSync(io.Discard),
		zapcore.InfoLevel),
		zap.AddCaller(),
	).Sugar()
	for i := 0; i < b.N; i++ {
		logger.Infow(msg, "rate", "15", "low", 16, "high", 123.2)
	}
}

func BenchmarkZapInterface(b *testing.B) {
	logger := zap.New(zapcore.NewCore(
		zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
		zapcore.AddSync(io.Discard),
		zapcore.InfoLevel,
	)).Sugar()
	for i := 0; i < b.N; i++ {
		logger.Infow(msg, "object", &obj)
	}
}

func BenchmarkZeroLogDisable(b *testing.B) {
	zerolog.SetGlobalLevel(zerolog.InfoLevel)
	logger := zerolog.New(io.Discard).With().Timestamp().Logger()
	for i := 0; i < b.N; i++ {
		logger.Debug().Str("rate", "15").Int("low", 16).Float32("high", 123.2).Msg(msg)
	}
}

func BenchmarkZeroLogNormal(b *testing.B) {
	logger := zerolog.New(io.Discard).With().Timestamp().Logger()
	for i := 0; i < b.N; i++ {
		logger.Info().Str("rate", "15").Int("low", 16).Float32("high", 123.2).Msg(msg)
	}
}

func BenchmarkZeroLogPrintf(b *testing.B) {
	logger := zerolog.New(io.Discard).With().Timestamp().Logger()
	for i := 0; i < b.N; i++ {
		logger.Info().Msgf("rate=%s low=%d high=%f msg=%s", "15", 16, 123.2, msg)
	}
}

func BenchmarkZeroLogCaller(b *testing.B) {
	logger := zerolog.New(io.Discard).With().Caller().Timestamp().Logger()
	for i := 0; i < b.N; i++ {
		logger.Info().Str("rate", "15").Int("low", 16).Float32("high", 123.2).Msg(msg)
	}
}

func BenchmarkZeroLogInterface(b *testing.B) {
	logger := zerolog.New(io.Discard).With().Timestamp().Logger()
	for i := 0; i < b.N; i++ {
		logger.Info().Interface("object", &obj).Msg(msg)
	}
}

func BenchmarkPhusLogDisable(b *testing.B) {
	logger := phuslog.Logger{Level: phuslog.InfoLevel, Writer: phuslog.IOWriter{io.Discard}}
	for i := 0; i < b.N; i++ {
		logger.Debug().Str("rate", "15").Int("low", 16).Float32("high", 123.2).Msg(msg)
	}
}

func BenchmarkPhusLogNormal(b *testing.B) {
	logger := phuslog.Logger{Writer: phuslog.IOWriter{io.Discard}}
	for i := 0; i < b.N; i++ {
		logger.Info().Str("rate", "15").Int("low", 16).Float32("high", 123.2).Msg(msg)
	}
}

func BenchmarkPhusLogPrintf(b *testing.B) {
	logger := phuslog.Logger{Writer: phuslog.IOWriter{io.Discard}}
	for i := 0; i < b.N; i++ {
		logger.Info().Msgf("rate=%s low=%d high=%f msg=%s", "15", 16, 123.2, msg)
	}
}

func BenchmarkPhusLogCaller(b *testing.B) {
	logger := phuslog.Logger{Caller: 1, Writer: phuslog.IOWriter{io.Discard}}
	for i := 0; i < b.N; i++ {
		logger.Info().Str("rate", "15").Int("low", 16).Float32("high", 123.2).Msg(msg)
	}
}

func BenchmarkPhusLogInterface(b *testing.B) {
	logger := phuslog.Logger{Writer: phuslog.IOWriter{io.Discard}}
	for i := 0; i < b.N; i++ {
		logger.Info().Interface("object", &obj).Msg(msg)
	}
}

A Performance result as below, for daily benchmark results see github actions

goos: linux
goarch: amd64
cpu: AMD EPYC 7763 64-Core Processor

BenchmarkSlogDisable-4        	1000000000	         8.404 ns/op	       0 B/op	       0 allocs/op
BenchmarkSlogNormal-4         	 9004674	      1332 ns/op	     120 B/op	       3 allocs/op
BenchmarkSlogPrintf-4         	11932806	      1011 ns/op	      80 B/op	       1 allocs/op
BenchmarkSlogCaller-4         	 5491897	      2184 ns/op	     688 B/op	       9 allocs/op
BenchmarkSlogInterface-4      	 9200828	      1299 ns/op	     112 B/op	       2 allocs/op

BenchmarkZapDisable-4         	1000000000	         8.099 ns/op	       0 B/op	       0 allocs/op
BenchmarkZapNormal-4          	13027324	       912.5 ns/op	     384 B/op	       1 allocs/op
BenchmarkZapPrintf-4          	12789286	       949.7 ns/op	      80 B/op	       1 allocs/op
BenchmarkZapCaller-4          	 7093309	      1681 ns/op	     632 B/op	       3 allocs/op
BenchmarkZapInterface-4       	11350916	      1046 ns/op	     224 B/op	       2 allocs/op

BenchmarkZeroLogDisable-4     	1000000000	         9.929 ns/op	       0 B/op	       0 allocs/op
BenchmarkZeroLogNormal-4      	36481122	       327.4 ns/op	       0 B/op	       0 allocs/op
BenchmarkZeroLogPrintf-4      	17880010	       664.8 ns/op	      80 B/op	       1 allocs/op
BenchmarkZeroLogCaller-4      	 9288362	      1293 ns/op	     304 B/op	       4 allocs/op
BenchmarkZeroLogInterface-4   	19508446	       614.7 ns/op	      48 B/op	       1 allocs/op

BenchmarkPhusLogDisable-4     	1000000000	         9.610 ns/op	       0 B/op	       0 allocs/op
BenchmarkPhusLogNormal-4      	51244849	       236.8 ns/op	       0 B/op	       0 allocs/op
BenchmarkPhusLogPrintf-4      	23559231	       509.0 ns/op	       0 B/op	       0 allocs/op
BenchmarkPhusLogCaller-4      	23906091	       508.0 ns/op	       0 B/op	       0 allocs/op
BenchmarkPhusLogInterface-4   	21407361	       558.8 ns/op	       0 B/op	       0 allocs/op

PASS
ok  	bench	246.926s
As slog handlers, comparing with stdlib/zap/zerolog implementations
// go test -v -cpu=1 -run=none -bench=. -benchtime=10s -benchmem bench_test.go
package bench

import (
	"io"
	"log/slog"
	"testing"

	"github.com/phsym/zeroslog"
	phuslog "github.com/phuslu/log"
	"go.uber.org/zap"
	"go.uber.org/zap/exp/zapslog"
	"go.uber.org/zap/zapcore"
)

const msg = "The quick brown fox jumps over the lazy dog"

func BenchmarkSlogNormalStd(b *testing.B) {
	logger := slog.New(slog.NewJSONHandler(io.Discard, nil))
	for i := 0; i < b.N; i++ {
		logger.Info(msg, "rate", "15", "low", 16, "high", 123.2)
	}
}

func BenchmarkSlogGroupStd(b *testing.B) {
	logger := slog.New(slog.NewJSONHandler(io.Discard, nil)).With("a", 1).WithGroup("g").With("b", 2)
	for i := 0; i < b.N; i++ {
		logger.Info(msg, "rate", "15", "low", 16, "high", 123.2)
	}
}

func BenchmarkSlogNormalZap(b *testing.B) {
	logcore := zapcore.NewCore(
		zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
		zapcore.AddSync(io.Discard),
		zapcore.InfoLevel,
	)
	logger := slog.New(zapslog.NewHandler(logcore, nil))
	for i := 0; i < b.N; i++ {
		logger.Info(msg, "rate", "15", "low", 16, "high", 123.2)
	}
}

func BenchmarkSlogGroupZap(b *testing.B) {
	logcore := zapcore.NewCore(
		zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
		zapcore.AddSync(io.Discard),
		zapcore.InfoLevel,
	)
	logger := slog.New(zapslog.NewHandler(logcore, nil)).With("a", 1).WithGroup("g").With("b", 2)
	for i := 0; i < b.N; i++ {
		logger.Info(msg, "rate", "15", "low", 16, "high", 123.2)
	}
}

func BenchmarkSlogNormalZerolog(b *testing.B) {
	logger := slog.New(zeroslog.NewJsonHandler(io.Discard, &zeroslog.HandlerOptions{Level: slog.LevelInfo}))
	for i := 0; i < b.N; i++ {
		logger.Info(msg, "rate", "15", "low", 16, "high", 123.2)
	}
}

func BenchmarkSlogGroupZerolog(b *testing.B) {
	logger := slog.New(zeroslog.NewJsonHandler(io.Discard, &zeroslog.HandlerOptions{Level: slog.LevelInfo})).With("a", 1).WithGroup("g").With("b", 2)
	for i := 0; i < b.N; i++ {
		logger.Info(msg, "rate", "15", "low", 16, "high", 123.2)
	}
}

func BenchmarkSlogNormalPhuslog(b *testing.B) {
	logger := slog.New((&phuslog.Logger{Writer: phuslog.IOWriter{io.Discard}}).Slog().Handler())
	for i := 0; i < b.N; i++ {
		logger.Info(msg, "rate", "15", "low", 16, "high", 123.2)
	}
}

func BenchmarkSlogGroupPhuslog(b *testing.B) {
	logger := slog.New((&phuslog.Logger{Writer: phuslog.IOWriter{io.Discard}}).Slog().Handler()).With("a", 1).WithGroup("g").With("b", 2)
	for i := 0; i < b.N; i++ {
		logger.Info(msg, "rate", "15", "low", 16, "high", 123.2)
	}
}

func BenchmarkSlogNormalPhuslogStd(b *testing.B) {
	logger := slog.New(phuslog.SlogNewJSONHandler(io.Discard, nil))
	for i := 0; i < b.N; i++ {
		logger.Info(msg, "rate", "15", "low", 16, "high", 123.2)
	}
}

func BenchmarkSlogGroupPhuslogStd(b *testing.B) {
	logger := slog.New(phuslog.SlogNewJSONHandler(io.Discard, nil)).With("a", 1).WithGroup("g").With("b", 2)
	for i := 0; i < b.N; i++ {
		logger.Info(msg, "rate", "15", "low", 16, "high", 123.2)
	}
}

A Performance result as below, for daily benchmark results see github actions

goos: linux
goarch: amd64
cpu: AMD EPYC 7763 64-Core Processor

BenchmarkSlogNormalStd        	 4408033	      1383 ns/op	     120 B/op	       3 allocs/op
BenchmarkSlogGroupStd         	 4298301	      1398 ns/op	     120 B/op	       3 allocs/op

BenchmarkSlogNormalZap        	 4753046	      1273 ns/op	     192 B/op	       1 allocs/op
BenchmarkSlogGroupZap         	 4724052	      1257 ns/op	     192 B/op	       1 allocs/op

BenchmarkSlogNormalZerolog    	 7548705	       789.2 ns/op	       0 B/op	       0 allocs/op
BenchmarkSlogGroupZerolog     	 5592763	      1076 ns/op	     288 B/op	       1 allocs/op

BenchmarkSlogNormalPhuslog    	 8318289	       720.1 ns/op	       0 B/op	       0 allocs/op
BenchmarkSlogGroupPhuslog     	 8175591	       737.8 ns/op	       0 B/op	       0 allocs/op

BenchmarkSlogNormalPhuslogStd 	 7978171	       755.0 ns/op	       0 B/op	       0 allocs/op
BenchmarkSlogGroupPhuslogStd  	 7728466	       775.4 ns/op	       0 B/op	       0 allocs/op

PASS
ok  	bench	70.366s

In summary, phuslog offers a blend of low latency, minimal memory usage, and efficient logging across various scenarios, making it an excellent option for high-performance logging in Go applications.

A Real World Example

The example starts a geoip http server which supports change log level dynamically

package main

import (
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"os"

	"github.com/phuslu/iploc"
	"github.com/phuslu/log"
)

type Config struct {
	Listen struct {
		Tcp string
	}
	Log struct {
		Level   string
		Maxsize int64
		Backups int
	}
}

type Handler struct {
	Config       *Config
	AccessLogger log.Logger
}

func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	reqID := log.NewXID()
	remoteIP, _, _ := net.SplitHostPort(req.RemoteAddr)
	geo := iploc.Country(net.ParseIP(remoteIP))

	h.AccessLogger.Log().
		Xid("req_id", reqID).
		Str("host", req.Host).
		Bytes("geo", geo).
		Str("remote_ip", remoteIP).
		Str("request_uri", req.RequestURI).
		Str("user_agent", req.UserAgent()).
		Str("referer", req.Referer()).
		Msg("access log")

	switch req.RequestURI {
	case "/debug", "/info", "/warn", "/error":
		log.DefaultLogger.SetLevel(log.ParseLevel(req.RequestURI[1:]))
	default:
		fmt.Fprintf(rw, `{"req_id":"%s","ip":"%s","geo":"%s"}`, reqID, remoteIP, geo)
	}
}

func main() {
	config := new(Config)
	err := json.Unmarshal([]byte(`{
		"listen": {
			"tcp": ":8080"
		},
		"log": {
			"level": "debug",
			"maxsize": 1073741824,
			"backups": 5
		}
	}`), config)
	if err != nil {
		log.Fatal().Msgf("json.Unmarshal error: %+v", err)
	}

	handler := &Handler{
		Config: config,
		AccessLogger: log.Logger{
			Writer: &log.FileWriter{
				Filename:   "access.log",
				MaxSize:    config.Log.Maxsize,
				MaxBackups: config.Log.Backups,
				LocalTime:  true,
			},
		},
	}

	if log.IsTerminal(os.Stderr.Fd()) {
		log.DefaultLogger = log.Logger{
			Level:      log.ParseLevel(config.Log.Level),
			Caller:     1,
			TimeFormat: "15:04:05",
			Writer: &log.ConsoleWriter{
				ColorOutput:    true,
				EndWithMessage: true,
			},
		}
		handler.AccessLogger = log.DefaultLogger
	} else {
		log.DefaultLogger = log.Logger{
			Level: log.ParseLevel(config.Log.Level),
			Writer: &log.FileWriter{
				Filename:   "main.log",
				MaxSize:    config.Log.Maxsize,
				MaxBackups: config.Log.Backups,
				LocalTime:  true,
			},
		}
	}

	server := &http.Server{
		Addr:     config.Listen.Tcp,
		ErrorLog: log.DefaultLogger.Std(log.ErrorLevel, nil, "", 0),
		Handler:  handler,
	}

	log.Fatal().Err(server.ListenAndServe()).Msg("listen failed")
}

Acknowledgment

This log is heavily inspired by zerolog, glog, gjson and lumberjack.

Documentation

Index

Constants

View Source
const TimeFormatUnix = "\x01"

TimeFormatUnix defines a time format that makes time fields to be serialized as Unix timestamp integers.

View Source
const TimeFormatUnixMs = "\x02"

TimeFormatUnixMs defines a time format that makes time fields to be serialized as Unix timestamp integers in milliseconds.

View Source
const TimeFormatUnixWithMs = "\x03"

TimeFormatUnixWithMs defines a time format that makes time fields to be serialized as Unix timestamp timestamp floats.

Variables

View Source
var (
	// Epoch is set to the twitter snowflake epoch of Nov 04 2010 01:42:54 UTC in milliseconds
	// You may customize this to set a different epoch for your application.
	Epoch int64 = 1288834974657

	// NodeBits holds the number of bits to use for Node
	// Remember, you have a total 22 bits to share between Node/Step
	NodeBits uint8 = 10

	// StepBits holds the number of bits to use for Step
	// Remember, you have a total 22 bits to share between Node/Step
	StepBits uint8 = 12
)
View Source
var DefaultLogger = Logger{
	Level:         DebugLevel,
	LogNode:       true,
	EnableTracing: true,
	TraceIDField:  "trace_id",
	Caller:        0,
	TimeField:     "",
	TimeFormat:    "",
	Writer:        IOWriter{os.Stderr},
}

DefaultLogger is the global logger.

View Source
var ErrInvalidBase32 = errors.New("invalid base32")

ErrInvalidBase32 is returned by ParseBase32 when given an invalid []byte

View Source
var ErrInvalidBase58 = errors.New("invalid base58")

ErrInvalidBase58 is returned by ParseBase58 when given an invalid []byte

Functions

func Fastrandn

func Fastrandn(x uint32) uint32

Fastrandn returns a pseudorandom uint32 in [0,n).

func Goid

func Goid() int64

Goid returns the current goroutine id. It exactly matches goroutine id of the stack trace.

func IsTerminal

func IsTerminal(fd uintptr) bool

IsTerminal returns whether the given file descriptor is a terminal.

func Printf

func Printf(format string, v ...interface{})

Printf sends a log entry without extra field. Arguments are handled in the manner of fmt.Printf.

func SlogNewJSONHandler

func SlogNewJSONHandler(writer io.Writer, options *slog.HandlerOptions) slog.Handler

Types

type AsyncWriter

type AsyncWriter struct {
	// ChannelSize is the size of the data channel, the default size is 1.
	ChannelSize uint

	// Writer specifies the writer of output.
	Writer Writer
	// contains filtered or unexported fields
}

AsyncWriter is an Writer that writes asynchronously.

func (*AsyncWriter) Close

func (w *AsyncWriter) Close() (err error)

Close implements io.Closer, and closes the underlying Writer.

func (*AsyncWriter) WriteEntry

func (w *AsyncWriter) WriteEntry(e *Entry) (int, error)

WriteEntry implements Writer.

type ConsoleWriter

type ConsoleWriter struct {
	// ColorOutput determines if used colorized output.
	ColorOutput bool

	// QuoteString determines if quoting string values.
	QuoteString bool

	// EndWithMessage determines if output message in the end.
	EndWithMessage bool

	// Formatter specifies an optional text formatter for creating a customized output,
	// If it is set, ColorOutput, QuoteString and EndWithMessage will be ignore.
	Formatter func(w io.Writer, args *FormatterArgs) (n int, err error)

	// Writer is the output destination. using os.Stderr if empty.
	Writer io.Writer
}

ConsoleWriter parses the JSON input and writes it in a colorized, human-friendly format to Writer. IMPORTANT: Don't use ConsoleWriter on critical path of a high concurrency and low latency application.

Default output format:

{Time} {Level} {Goid} {Caller} > {Message} {Key}={Value} {Key}={Value}

Note: The performance of ConsoleWriter is not good enough, because it will parses JSON input into structured records, then output in a specific order. Roughly 2x faster than logrus.TextFormatter, 0.8x fast as zap.ConsoleEncoder, and 5x faster than zerolog.ConsoleWriter.

func (*ConsoleWriter) Close

func (w *ConsoleWriter) Close() (err error)

Close implements io.Closer, will closes the underlying Writer if not empty.

func (*ConsoleWriter) WriteEntry

func (w *ConsoleWriter) WriteEntry(e *Entry) (int, error)

WriteEntry implements Writer.

type Context

type Context []byte

Context represents contextual fields.

type Entry

type Entry struct {
	Level Level
	// contains filtered or unexported fields
}

Entry represents a log entry. It is instanced by one of the level method of Logger and finalized by the Msg or Msgf method.

func Debug

func Debug() (e *Entry)

Debug starts a new message with debug level.

func Error

func Error() (e *Entry)

Error starts a new message with error level.

func Fatal

func Fatal() (e *Entry)

Fatal starts a new message with fatal level.

func Info

func Info() (e *Entry)

Info starts a new message with info level.

func NewContext

func NewContext(dst []byte) (e *Entry)

NewContext starts a new contextual entry.

func Panic

func Panic() (e *Entry)

Panic starts a new message with panic level.

func Trace

func Trace() (e *Entry)

Trace starts a new message with trace level.

func Warn

func Warn() (e *Entry)

Warn starts a new message with warning level.

func (*Entry) AnErr

func (e *Entry) AnErr(key string, err error) *Entry

AnErr adds the field key with serialized err to the logger context.

func (*Entry) Any

func (e *Entry) Any(key string, value interface{}) *Entry

Any adds the field key with f as an Any value to the entry.

func (*Entry) Bool

func (e *Entry) Bool(key string, b bool) *Entry

Bool append the val as a bool to the entry.

func (*Entry) Bools

func (e *Entry) Bools(key string, b []bool) *Entry

Bools adds the field key with val as a []bool to the entry.

func (*Entry) Byte

func (e *Entry) Byte(key string, val byte) *Entry

Byte adds the field key with val as a byte to the entry.

func (*Entry) Bytes

func (e *Entry) Bytes(key string, val []byte) *Entry

Bytes adds the field key with val as a string to the entry.

func (*Entry) BytesOrNil

func (e *Entry) BytesOrNil(key string, val []byte) *Entry

BytesOrNil adds the field key with val as a string or nil to the entry.

func (*Entry) Caller

func (e *Entry) Caller(depth int) *Entry

Caller adds the file:line of the "caller" key. If depth is negative, adds the full /path/to/file:line of the "caller" key.

func (*Entry) Context

func (e *Entry) Context(ctx Context) *Entry

Context sends the contextual fields to entry.

func (*Entry) Dict

func (e *Entry) Dict(key string, ctx Context) *Entry

Dict sends the contextual fields with key to entry.

func (*Entry) Discard

func (e *Entry) Discard() *Entry

Discard disables the entry so Msg(f) won't print it.

func (*Entry) Dur

func (e *Entry) Dur(key string, d time.Duration) *Entry

Dur adds the field key with duration d to the entry.

func (*Entry) Durs

func (e *Entry) Durs(key string, d []time.Duration) *Entry

Durs adds the field key with val as a []time.Duration to the entry.

func (*Entry) EmbedObject

func (e *Entry) EmbedObject(obj ObjectMarshaler) *Entry

EmbedObject marshals and Embeds an object that implement the ObjectMarshaler interface.

func (*Entry) Enabled

func (e *Entry) Enabled() bool

Enabled return false if the entry is going to be filtered out by log level.

func (*Entry) Encode

func (e *Entry) Encode(key string, val []byte, enc interface {
	AppendEncode(dst, src []byte) []byte
}) *Entry

Encode encodes bytes using enc.AppendEncode to the entry.

func (*Entry) Err

func (e *Entry) Err(err error) *Entry

Err adds the field "error" with serialized err to the entry.

func (*Entry) Errs

func (e *Entry) Errs(key string, errs []error) *Entry

Errs adds the field key with errs as an array of serialized errors to the entry.

func (*Entry) Fields

func (e *Entry) Fields(fields Fields) *Entry

Fields is a helper function to use a map to set fields using type assertion.

func (*Entry) Float32

func (e *Entry) Float32(key string, f float32) *Entry

Float32 adds the field key with f as a float32 to the entry.

func (*Entry) Float64

func (e *Entry) Float64(key string, f float64) *Entry

Float64 adds the field key with f as a float64 to the entry.

func (*Entry) Floats32

func (e *Entry) Floats32(key string, f []float32) *Entry

Floats32 adds the field key with f as a []float32 to the entry.

func (*Entry) Floats64

func (e *Entry) Floats64(key string, f []float64) *Entry

Floats64 adds the field key with f as a []float64 to the entry.

func (*Entry) Func

func (e *Entry) Func(f func(e *Entry)) *Entry

Func allows an anonymous func to run only if the entry is enabled.

func (*Entry) GoStringer

func (e *Entry) GoStringer(key string, val fmt.GoStringer) *Entry

GoStringer adds the field key with val.GoStringer() to the entry.

func (*Entry) Hex

func (e *Entry) Hex(key string, val []byte) *Entry

Hex adds the field key with val as a hex string to the entry.

func (*Entry) IPAddr

func (e *Entry) IPAddr(key string, ip net.IP) *Entry

IPAddr adds IPv4 or IPv6 Address to the entry.

func (*Entry) IPPrefix

func (e *Entry) IPPrefix(key string, pfx net.IPNet) *Entry

IPPrefix adds IPv4 or IPv6 Prefix (address and mask) to the entry.

func (*Entry) Int

func (e *Entry) Int(key string, i int) *Entry

Int adds the field key with i as a int to the entry.

func (*Entry) Int16

func (e *Entry) Int16(key string, i int16) *Entry

Int16 adds the field key with i as a int16 to the entry.

func (*Entry) Int32

func (e *Entry) Int32(key string, i int32) *Entry

Int32 adds the field key with i as a int32 to the entry.

func (*Entry) Int64

func (e *Entry) Int64(key string, i int64) *Entry

Int64 adds the field key with i as a int64 to the entry.

func (*Entry) Int8

func (e *Entry) Int8(key string, i int8) *Entry

Int8 adds the field key with i as a int8 to the entry.

func (*Entry) Interface

func (e *Entry) Interface(key string, i interface{}) *Entry

Interface adds the field key with i marshaled using reflection.

func (*Entry) Ints

func (e *Entry) Ints(key string, a []int) *Entry

Ints adds the field key with i as a []int to the entry.

func (*Entry) Ints16

func (e *Entry) Ints16(key string, a []int16) *Entry

Ints16 adds the field key with i as a []int16 to the entry.

func (*Entry) Ints32

func (e *Entry) Ints32(key string, a []int32) *Entry

Ints32 adds the field key with i as a []int32 to the entry.

func (*Entry) Ints64

func (e *Entry) Ints64(key string, a []int64) *Entry

Ints64 adds the field key with i as a []int64 to the entry.

func (*Entry) Ints8

func (e *Entry) Ints8(key string, a []int8) *Entry

Ints8 adds the field key with i as a []int8 to the entry.

func (*Entry) KeysAndValues

func (e *Entry) KeysAndValues(keysAndValues ...interface{}) *Entry

KeysAndValues sends keysAndValues to Entry

func (*Entry) MACAddr

func (e *Entry) MACAddr(key string, ha net.HardwareAddr) *Entry

MACAddr adds MAC address to the entry.

func (*Entry) Map

func (e *Entry) Map(data any) *Entry

func (*Entry) Msg

func (e *Entry) Msg(msg string)

Msg sends the entry with msg added as the message field if not empty.

func (*Entry) Msgf

func (e *Entry) Msgf(format string, v ...interface{})

Msgf sends the entry with formatted msg added as the message field if not empty.

func (*Entry) Msgs

func (e *Entry) Msgs(args ...interface{})

Msgs sends the entry with msgs added as the message field if not empty.

func (*Entry) NetIPAddr

func (e *Entry) NetIPAddr(key string, ip netip.Addr) *Entry

NetIPAddr adds IPv4 or IPv6 Address to the entry.

func (*Entry) NetIPAddrPort

func (e *Entry) NetIPAddrPort(key string, ipPort netip.AddrPort) *Entry

NetIPAddrPort adds IPv4 or IPv6 with Port Address to the entry.

func (*Entry) NetIPPrefix

func (e *Entry) NetIPPrefix(key string, pfx netip.Prefix) *Entry

NetIPPrefix adds IPv4 or IPv6 Prefix (address and mask) to the entry.

func (*Entry) Object

func (e *Entry) Object(key string, obj ObjectMarshaler) *Entry

Object marshals an object that implement the ObjectMarshaler interface.

func (*Entry) RawJSON

func (e *Entry) RawJSON(key string, b []byte) *Entry

RawJSON adds already encoded JSON to the log line under key.

func (*Entry) RawJSONStr

func (e *Entry) RawJSONStr(key string, s string) *Entry

RawJSONStr adds already encoded JSON String to the log line under key.

func (*Entry) Stack

func (e *Entry) Stack() *Entry

Stack enables stack trace printing for the error passed to Err().

func (*Entry) Str

func (e *Entry) Str(key string, val string) *Entry

Str adds the field key with val as a string to the entry.

func (*Entry) StrInt

func (e *Entry) StrInt(key string, val int64) *Entry

StrInt adds the field key with integer val as a string to the entry.

func (*Entry) Stringer

func (e *Entry) Stringer(key string, val fmt.Stringer) *Entry

Stringer adds the field key with val.String() to the entry.

func (*Entry) Strs

func (e *Entry) Strs(key string, vals []string) *Entry

Strs adds the field key with vals as a []string to the entry.

func (*Entry) Time

func (e *Entry) Time(key string, t time.Time) *Entry

Time append t formatted as string using time.RFC3339Nano.

func (*Entry) TimeDiff

func (e *Entry) TimeDiff(key string, t time.Time, start time.Time) *Entry

TimeDiff adds the field key with positive duration between time t and start. If time t is not greater than start, duration will be 0. Duration format follows the same principle as Dur().

func (*Entry) TimeFormat

func (e *Entry) TimeFormat(key string, timefmt string, t time.Time) *Entry

TimeFormat append t formatted as string using timefmt.

func (*Entry) Times

func (e *Entry) Times(key string, a []time.Time) *Entry

Times append a formatted as string array using time.RFC3339Nano.

func (*Entry) TimesFormat

func (e *Entry) TimesFormat(key string, timefmt string, a []time.Time) *Entry

TimesFormat append a formatted as string array using timefmt.

func (*Entry) Type

func (e *Entry) Type(key string, v interface{}) *Entry

Type adds type of the key using reflection to the entry.

func (*Entry) Uint

func (e *Entry) Uint(key string, i uint) *Entry

Uint adds the field key with i as a uint to the entry.

func (*Entry) Uint16

func (e *Entry) Uint16(key string, i uint16) *Entry

Uint16 adds the field key with i as a uint16 to the entry.

func (*Entry) Uint32

func (e *Entry) Uint32(key string, i uint32) *Entry

Uint32 adds the field key with i as a uint32 to the entry.

func (*Entry) Uint64

func (e *Entry) Uint64(key string, i uint64) *Entry

Uint64 adds the field key with i as a uint64 to the entry.

func (*Entry) Uint8

func (e *Entry) Uint8(key string, i uint8) *Entry

Uint8 adds the field key with i as a uint8 to the entry.

func (*Entry) Uints

func (e *Entry) Uints(key string, a []uint) *Entry

Uints adds the field key with i as a []uint to the entry.

func (*Entry) Uints16

func (e *Entry) Uints16(key string, a []uint16) *Entry

Uints16 adds the field key with i as a []uint16 to the entry.

func (*Entry) Uints32

func (e *Entry) Uints32(key string, a []uint32) *Entry

Uints32 adds the field key with i as a []uint32 to the entry.

func (*Entry) Uints64

func (e *Entry) Uints64(key string, a []uint64) *Entry

Uints64 adds the field key with i as a []uint64 to the entry.

func (*Entry) Uints8

func (e *Entry) Uints8(key string, a []uint8) *Entry

Uints8 adds the field key with i as a []uint8 to the entry.

func (*Entry) Value

func (e *Entry) Value() Context

Value builds the contextual fields.

func (*Entry) WithContext

func (e *Entry) WithContext(ctx context.Context) *Entry

WithContext use context

func (*Entry) Xid

func (e *Entry) Xid(key string, id int64) *Entry

Xid adds the field key with xid.ID as a base32 string to the entry.

type Fields

type Fields map[string]interface{}

Fields type, used to pass to `Fields`.

type FileWriter

type FileWriter struct {
	// Filename is the file to write logs to.  Backup log files will be retained
	// in the same directory.
	Filename string

	// MaxSize is the maximum size in bytes of the log file before it gets rotated.
	MaxSize int64

	// MaxBackups is the maximum number of old log files to retain.  The default
	// is to retain all old log files
	MaxBackups int

	// FileMode represents the file's mode and permission bits.  The default
	// mode is 0644
	FileMode os.FileMode

	// TimeFormat specifies the time format of filename, uses `2006-01-02T15-04-05` as default format.
	// If set with `TimeFormatUnix`, `TimeFormatUnixMs`, times are formated as UNIX timestamp.
	TimeFormat string

	// LocalTime determines if the time used for formatting the timestamps in
	// log files is the computer's local time.  The default is to use UTC time.
	LocalTime bool

	// HostName determines if the hostname used for formatting in log files.
	HostName bool

	// ProcessID determines if the pid used for formatting in log files.
	ProcessID bool

	// EnsureFolder ensures the file directory creation before writing.
	EnsureFolder bool

	// Header specifies an optional header function of log file after rotation,
	Header func(fileinfo os.FileInfo) []byte

	// Cleaner specifies an optional cleanup function of log backups after rotation,
	// if not set, the default behavior is to delete more than MaxBackups log files.
	Cleaner func(filename string, maxBackups int, matches []os.FileInfo)
	// contains filtered or unexported fields
}

FileWriter is an Writer that writes to the specified filename.

Backups use the log file name given to FileWriter, in the form `name.timestamp.ext` where name is the filename without the extension, timestamp is the time at which the log was rotated formatted with the time.Time format of `2006-01-02T15-04-05` and the extension is the original extension. For example, if your FileWriter.Filename is `/var/log/foo/server.log`, a backup created at 6:30pm on Nov 11 2016 would use the filename `/var/log/foo/server.2016-11-04T18-30-00.log`

Cleaning Up Old Log Files

Whenever a new logfile gets created, old log files may be deleted. The most recent files according to filesystem modified time will be retained, up to a number equal to MaxBackups (or all of them if MaxBackups is 0). Note that the time encoded in the timestamp is the rotation time, which may differ from the last time that file was written to .

func (*FileWriter) Close

func (w *FileWriter) Close() (err error)

Close implements io.Closer, and closes the current logfile.

func (*FileWriter) Rotate

func (w *FileWriter) Rotate() (err error)

Rotate causes Logger to close the existing log file and immediately create a new one. This is a helper function for applications that want to initiate rotations outside of the normal rotation rules, such as in response to SIGHUP. After rotating, this initiates compression and removal of old log files according to the configuration.

func (*FileWriter) Write

func (w *FileWriter) Write(p []byte) (n int, err error)

Write implements io.Writer. If a write would cause the log file to be larger than MaxSize, the file is closed, rotate to include a timestamp of the current time, and update symlink with log name file to the new file.

func (*FileWriter) WriteEntry

func (w *FileWriter) WriteEntry(e *Entry) (n int, err error)

WriteEntry implements Writer. If a write would cause the log file to be larger than MaxSize, the file is closed, rotate to include a timestamp of the current time, and update symlink with log name file to the new file.

type FormatterArgs

type FormatterArgs struct {
	Time      string // "2019-07-10T05:35:54.277Z"
	Level     string // "info"
	Caller    string // "prog.go:42"
	Goid      string // "123"
	Stack     string // "<stack string>"
	Message   string // "a structure message"
	KeyValues []struct {
		Key       string // "foo"
		Value     string // "bar"
		ValueType byte   // 's'
	}
}

FormatterArgs is a parsed sturct from json input

func (*FormatterArgs) Get

func (args *FormatterArgs) Get(key string) (value string)

Get gets the value associated with the given key.

type ID

type ID int64

An ID is a custom type used for a snowflake ID. This is used so we can attach methods onto the ID.

func New

func New() ID

func ParseBase2

func ParseBase2(id string) (ID, error)

ParseBase2 converts a Base2 string into a snowflake ID

func ParseBase32

func ParseBase32(b []byte) (ID, error)

ParseBase32 parses a base32 []byte into a snowflake ID NOTE: There are many different base32 implementations so becareful when doing Any interoperation.

func ParseBase36

func ParseBase36(id string) (ID, error)

ParseBase36 converts a Base36 string into a snowflake ID

func ParseBase58

func ParseBase58(b []byte) (ID, error)

ParseBase58 parses a base58 []byte into a snowflake ID

func ParseBase64

func ParseBase64(id string) (ID, error)

ParseBase64 converts a base64 string into a snowflake ID

func ParseBytes

func ParseBytes(id []byte) (ID, error)

ParseBytes converts a byte slice into a snowflake ID

func ParseInt64

func ParseInt64(id int64) ID

ParseInt64 converts an int64 into a snowflake ID

func ParseIntBytes

func ParseIntBytes(id [8]byte) ID

ParseIntBytes converts an array of bytes encoded as big endian integer as a snowflake ID

func ParseString

func ParseString(id string) (ID, error)

ParseString converts a string into a snowflake ID

func (ID) Base2

func (f ID) Base2() string

Base2 returns a string base2 of the snowflake ID

func (ID) Base32

func (f ID) Base32() string

Base32 uses the z-base-32 character set but encodes and decodes similar to base58, allowing it to create an even smaller result string. NOTE: There are many different base32 implementations so becareful when doing Any interoperation.

func (ID) Base36

func (f ID) Base36() string

Base36 returns a base36 string of the snowflake ID

func (ID) Base58

func (f ID) Base58() string

Base58 returns a base58 string of the snowflake ID

func (ID) Base64

func (f ID) Base64() string

Base64 returns a base64 string of the snowflake ID

func (ID) Bytes

func (f ID) Bytes() []byte

Bytes returns a byte slice of the snowflake ID

func (ID) Int64

func (f ID) Int64() int64

Int64 returns an int64 of the snowflake ID

func (ID) IntBytes

func (f ID) IntBytes() [8]byte

IntBytes returns an array of bytes of the snowflake ID, encoded as a big endian integer.

func (ID) MarshalJSON

func (f ID) MarshalJSON() ([]byte, error)

MarshalJSON returns a json byte array string of the snowflake ID.

func (ID) Node

func (f ID) Node() int64

Node returns an int64 of the snowflake ID node number DEPRECATED: the below function will be removed in a future release.

func (ID) Step

func (f ID) Step() int64

Step returns an int64 of the snowflake step (or sequence) number DEPRECATED: the below function will be removed in a future release.

func (ID) String

func (f ID) String() string

String returns a string of the snowflake ID

func (ID) Time

func (f ID) Time() int64

Time returns an int64 unix timestamp in milliseconds of the snowflake ID time DEPRECATED: the below function will be removed in a future release.

func (*ID) UnmarshalJSON

func (f *ID) UnmarshalJSON(b []byte) error

UnmarshalJSON converts a json byte array of a snowflake ID into an ID type .

type IOWriteCloser

type IOWriteCloser struct {
	io.WriteCloser
}

IOWriteCloser wraps an io.IOWriteCloser to Writer.

func (IOWriteCloser) Close

func (w IOWriteCloser) Close() (err error)

Close implements Writer.

func (IOWriteCloser) WriteEntry

func (w IOWriteCloser) WriteEntry(e *Entry) (n int, err error)

WriteEntry implements Writer.

type IOWriter

type IOWriter struct {
	io.Writer
}

IOWriter wraps an io.Writer to Writer.

func (IOWriter) WriteEntry

func (w IOWriter) WriteEntry(e *Entry) (n int, err error)

WriteEntry implements Writer.

type JSONSyntaxError

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

A JSONSyntaxError is returned from UnmarshalJSON if an invalid ID is provided.

func (JSONSyntaxError) Error

func (j JSONSyntaxError) Error() string

type JournalWriter

type JournalWriter struct {
	// JournalSocket specifies socket name, using `/run/systemd/journal/socket` if empty.
	JournalSocket string
	// contains filtered or unexported fields
}

JournalWriter is an Writer that writes logs to journald.

func (*JournalWriter) Close

func (w *JournalWriter) Close() (err error)

Close implements io.Closer.

func (*JournalWriter) WriteEntry

func (w *JournalWriter) WriteEntry(e *Entry) (n int, err error)

WriteEntry implements Writer.

type Level

type Level uint32

Level defines log levels.

const (
	// TraceLevel defines trace log level.
	TraceLevel Level = 1
	// DebugLevel defines debug log level.
	DebugLevel Level = 2
	// InfoLevel defines info log level.
	InfoLevel Level = 3
	// WarnLevel defines warn log level.
	WarnLevel Level = 4
	// ErrorLevel defines error log level.
	ErrorLevel Level = 5
	// FatalLevel defines fatal log level.
	FatalLevel Level = 6
	// PanicLevel defines panic log level.
	PanicLevel Level = 7
)

func ParseLevel

func ParseLevel(s string) (level Level)

ParseLevel converts a level string into a log Level value.

func (Level) String

func (l Level) String() (s string)

String return lowe case string of Level

type LogfmtFormatter

type LogfmtFormatter struct {
	TimeField string
}

func (LogfmtFormatter) Formatter

func (f LogfmtFormatter) Formatter(out io.Writer, args *FormatterArgs) (n int, err error)

type Logger

type Logger struct {
	// Level defines log levels.
	Level Level

	LogNode bool

	EnableTracing bool

	TraceIDField string

	// Caller determines if adds the file:line of the "caller" key.
	// If Caller is negative, adds the full /path/to/file:line of the "caller" key.
	Caller int

	// TimeField defines the time field name in output.  It uses "time" in if empty.
	TimeField string

	// TimeFormat specifies the time format in output. It uses time.RFC3339 with milliseconds if empty.
	// If set with `TimeFormatUnix`, `TimeFormatUnixMs`, times are formated as UNIX timestamp.
	TimeFormat string

	// TimeLocation specifices that the location which TimeFormat used. It uses time.Local if empty.
	TimeLocation *time.Location

	// Context specifies an optional context of logger.
	Context Context

	// Writer specifies the writer of output. It uses a wrapped os.Stderr Writer in if empty.
	Writer Writer
}

A Logger represents an active logging object that generates lines of JSON output to an io.Writer.

func (*Logger) Debug

func (l *Logger) Debug() (e *Entry)

Debug starts a new message with debug level.

func (*Logger) Err

func (l *Logger) Err(err error) (e *Entry)

Err starts a new message with error level with err as a field if not nil or with info level if err is nil.

func (*Logger) Error

func (l *Logger) Error() (e *Entry)

Error starts a new message with error level.

func (*Logger) Fatal

func (l *Logger) Fatal() (e *Entry)

Fatal starts a new message with fatal level.

func (*Logger) Info

func (l *Logger) Info() (e *Entry)

Info starts a new message with info level.

func (*Logger) Log

func (l *Logger) Log() (e *Entry)

Log starts a new message with no level.

func (*Logger) Panic

func (l *Logger) Panic() (e *Entry)

Panic starts a new message with panic level.

func (*Logger) Printf

func (l *Logger) Printf(format string, v ...interface{})

Printf sends a log entry without extra field. Arguments are handled in the manner of fmt.Printf.

func (*Logger) SetLevel

func (l *Logger) SetLevel(level Level)

SetLevel changes logger default level.

func (*Logger) Slog

func (l *Logger) Slog() *slog.Logger

Slog wraps the Logger to provide *slog.Logger

func (*Logger) Std

func (l *Logger) Std(prefix string, flag int) *stdLog.Logger

Std wraps the Logger to provide *stdLog.Logger

func (*Logger) Trace

func (l *Logger) Trace() (e *Entry)

Trace starts a new message with trace level.

func (*Logger) Warn

func (l *Logger) Warn() (e *Entry)

Warn starts a new message with warning level.

func (*Logger) WithLevel

func (l *Logger) WithLevel(level Level) (e *Entry)

WithLevel starts a new message with level.

type MultiEntryWriter

type MultiEntryWriter []Writer

MultiEntryWriter is an array Writer that log to different writers

func (*MultiEntryWriter) Close

func (w *MultiEntryWriter) Close() (err error)

Close implements io.Closer, and closes the underlying MultiEntryWriter.

func (*MultiEntryWriter) WriteEntry

func (w *MultiEntryWriter) WriteEntry(e *Entry) (n int, err error)

WriteEntry implements entryWriter.

type MultiIOWriter

type MultiIOWriter []io.Writer

MultiIOWriter is an array io.Writer that log to different writers

func (*MultiIOWriter) Close

func (w *MultiIOWriter) Close() (err error)

Close implements io.Closer, and closes the underlying MultiIOWriter.

func (*MultiIOWriter) WriteEntry

func (w *MultiIOWriter) WriteEntry(e *Entry) (n int, err error)

WriteEntry implements entryWriter.

type MultiLevelWriter

type MultiLevelWriter struct {
	// InfoWriter specifies all the level logs writes to
	InfoWriter Writer

	// WarnWriter specifies the level greater than or equal to WarnLevel writes to
	WarnWriter Writer

	// WarnWriter specifies the level greater than or equal to ErrorLevel writes to
	ErrorWriter Writer

	// ConsoleWriter specifies the console writer
	ConsoleWriter Writer

	// ConsoleLevel specifies the level greater than or equal to it also writes to
	ConsoleLevel Level
}

MultiLevelWriter is an Writer that log to different writers by different levels

func (*MultiLevelWriter) Close

func (w *MultiLevelWriter) Close() (err error)

Close implements io.Closer, and closes the underlying LeveledWriter.

func (*MultiLevelWriter) WriteEntry

func (w *MultiLevelWriter) WriteEntry(e *Entry) (n int, err error)

WriteEntry implements entryWriter.

type MultiWriter

type MultiWriter = MultiLevelWriter

MultiWriter is an alias for MultiLevelWriter

type Node

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

A Node struct holds the basic information needed for a snowflake generator node

func NewNode

func NewNode(node int64) (*Node, error)

NewNode returns a new snowflake node that can be used to generate snowflake IDs

func (*Node) New

func (n *Node) New() ID

New creates and returns a unique snowflake ID To help guarantee uniqueness - Make sure your system is keeping accurate system time - Make sure you never have multiple nodes running with the same node ID

type ObjectMarshaler

type ObjectMarshaler interface {
	MarshalObject(e *Entry)
}

ObjectMarshaler provides a strongly-typed and encoding-agnostic interface to be implemented by types used with Entry's Object methods.

type SyslogWriter

type SyslogWriter struct {
	// Network specifies network of the syslog server
	Network string

	// Address specifies address of the syslog server
	Address string

	// Hostname specifies hostname of the syslog message
	Hostname string

	// Tag specifies tag of the syslog message
	Tag string

	// Marker specifies prefix of the syslog message, e.g. `@cee:`
	Marker string

	// Dial specifies the dial function for creating TCP/TLS connections.
	Dial func(network, addr string) (net.Conn, error)
	// contains filtered or unexported fields
}

SyslogWriter is an Writer that writes logs to a syslog server..

func (*SyslogWriter) Close

func (w *SyslogWriter) Close() (err error)

Close closes a connection to the syslog server.

func (*SyslogWriter) WriteEntry

func (w *SyslogWriter) WriteEntry(e *Entry) (n int, err error)

WriteEntry implements Writer, sends logs with priority to the syslog server.

type TSVEntry

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

TSVEntry represents a tsv log entry. It is instanced by one of TSVLogger and finalized by the Msg method.

func (*TSVEntry) Bool

func (e *TSVEntry) Bool(b bool) *TSVEntry

Bool append the b as a bool to the entry, the value of output bool is 0 or 1.

func (*TSVEntry) BoolString

func (e *TSVEntry) BoolString(b bool) *TSVEntry

BoolString append the b as a bool to the entry, the value of output bool is false or true.

func (*TSVEntry) Byte

func (e *TSVEntry) Byte(b byte) *TSVEntry

Byte append the b as a byte to the entry.

func (*TSVEntry) Bytes

func (e *TSVEntry) Bytes(val []byte) *TSVEntry

Bytes adds a bytes as string to the entry.

func (*TSVEntry) Caller

func (e *TSVEntry) Caller(depth int) *TSVEntry

Caller adds the file:line of to the entry.

func (*TSVEntry) Encode

func (e *TSVEntry) Encode(key string, val []byte, enc interface {
	AppendEncode(dst, src []byte) []byte
}) *TSVEntry

Encode encodes bytes using enc.AppendEncode to the entry.

func (*TSVEntry) Float32

func (e *TSVEntry) Float32(f float32) *TSVEntry

Float32 adds a float32 to the entry.

func (*TSVEntry) Float64

func (e *TSVEntry) Float64(f float64) *TSVEntry

Float64 adds a float64 to the entry.

func (*TSVEntry) IPAddr

func (e *TSVEntry) IPAddr(ip net.IP) *TSVEntry

IPAddr adds IPv4 or IPv6 Address to the entry.

func (*TSVEntry) Int

func (e *TSVEntry) Int(i int) *TSVEntry

Int adds a int to the entry.

func (*TSVEntry) Int16

func (e *TSVEntry) Int16(i int16) *TSVEntry

Int16 adds a int16 to the entry.

func (*TSVEntry) Int32

func (e *TSVEntry) Int32(i int32) *TSVEntry

Int32 adds a int32 to the entry.

func (*TSVEntry) Int64

func (e *TSVEntry) Int64(i int64) *TSVEntry

Int64 adds a int64 to the entry.

func (*TSVEntry) Int8

func (e *TSVEntry) Int8(i int8) *TSVEntry

Int8 adds a int8 to the entry.

func (*TSVEntry) Msg

func (e *TSVEntry) Msg()

Msg sends the entry.

func (*TSVEntry) NetIPAddr

func (e *TSVEntry) NetIPAddr(ip netip.Addr) *TSVEntry

NetIPAddr adds IPv4 or IPv6 Address to the entry.

func (*TSVEntry) NetIPAddrPort

func (e *TSVEntry) NetIPAddrPort(ipPort netip.AddrPort) *TSVEntry

NetIPAddrPort adds IPv4 or IPv6 with Port Address to the entry.

func (*TSVEntry) NetIPPrefix

func (e *TSVEntry) NetIPPrefix(pfx netip.Prefix) *TSVEntry

NetIPPrefix adds IPv4 or IPv6 Prefix (address and mask) to the entry.

func (*TSVEntry) Str

func (e *TSVEntry) Str(val string) *TSVEntry

Str adds a string to the entry.

func (*TSVEntry) Timestamp

func (e *TSVEntry) Timestamp() *TSVEntry

Timestamp adds the current time as UNIX timestamp

func (*TSVEntry) TimestampMS

func (e *TSVEntry) TimestampMS() *TSVEntry

TimestampMS adds the current time with milliseconds as UNIX timestamp

func (*TSVEntry) Uint

func (e *TSVEntry) Uint(i uint) *TSVEntry

Uint adds a uint to the entry.

func (*TSVEntry) Uint16

func (e *TSVEntry) Uint16(i uint16) *TSVEntry

Uint16 adds a uint16 to the entry.

func (*TSVEntry) Uint32

func (e *TSVEntry) Uint32(i uint32) *TSVEntry

Uint32 adds a uint32 to the entry.

func (*TSVEntry) Uint64

func (e *TSVEntry) Uint64(i uint64) *TSVEntry

Uint64 adds a uint64 to the entry.

func (*TSVEntry) Uint8

func (e *TSVEntry) Uint8(i uint8) *TSVEntry

Uint8 adds a uint8 to the entry.

type TSVLogger

type TSVLogger struct {
	Separator byte
	Writer    io.Writer
}

TSVLogger represents an active logging object that generates lines of TSV output to an io.Writer.

func (*TSVLogger) New

func (l *TSVLogger) New() (e *TSVEntry)

New starts a new tsv message.

type Writer

type Writer interface {
	WriteEntry(*Entry) (int, error)
}

Writer defines an entry writer interface.

type WriterFunc

type WriterFunc func(*Entry) (int, error)

The WriterFunc type is an adapter to allow the use of ordinary functions as log writers. If f is a function with the appropriate signature, WriterFunc(f) is a Writer that calls f.

func (WriterFunc) WriteEntry

func (f WriterFunc) WriteEntry(e *Entry) (int, error)

WriteEntry calls f(e).

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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