log

package module
v1.14.0 Latest Latest
Warning

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

Go to latest
Published: Jul 1, 2024 License: Apache-2.0 Imports: 20 Imported by: 65

README

codecov

Log

Fortio's log is simple logger built on top of go's default one with additional opinionated levels similar to glog but simpler to use and configure.

It's been used for many years for Fortio's org Fortio project and more (under fortio.org/fortio/log package) but split out recently for standalone use, with the "flag pollution" limited (as a library it doesn't include the flags, you configure it using apis).

// On a cli tool (avoids file name and line numbers, stack traces on log.Fatalf etc)
log.SetDefaultsForClientTools()
log.LoggerStaticFlagSetup() // adds -loglevel flag to configure
// Or on a server type, import fortio.org/dflag, then:
dflag.LoggerFlagSetup()

// Then, printf style leveled logging:
log.Debugf(...) // Debug level
log.LogVf(...)  // Verbose level
log.Infof(...)  // Info/default level
log.Warnf(...)  // Warning level
log.Errf(...)   // Error level
log.Critf(...)  // Critical level (always logged even if level is set to max)
log.Fatalf(...) // Fatal level - program will panic/exit

// for http servers there is also
// access log type including user-agent, forwarded ip/proto (behind load balancer case),
// TLS crypto used and CN of peer certificate if any.
log.LogRequest(r, "some info")

// Structured logging with attributes
log.S(log.Info, "msg", log.Attr("key1", value1)...)

See the Config object for options like whether to include line number and file name of caller or not etc

New since 1.4 server logging (as used in fortio.org/scli for instance) is now structured (JSON), client logging (as setup by fortio.org/cli remains as before.

One can also revert server to not be JSON through config.

In JSON mode the output looks like this

{"ts":1683504169.239557,"level":"info","file":"logger.go","line":221,"msg":"Log level is now 1 Verbose (was 2 Info"}

Which can be converted to JSONEntry but is also a fixed, optimized format (ie ts is always first etc)

The timestamp ts is in seconds.microseconds since epoch (golang UnixMicro() split into seconds part before decimal and microseconds after)

Since 1.8 the Go Routine ID is present in JSON (r field) or colorized log output (for multi threaded server types).

Optional additional KeyValue pairs can be added to the base structure using the new log.S or passed to log.LogRequest using log.Any and log.Str. Note that numbers, as well as arrays of any type and maps of string keys to any type are supported (but more expensive to serialize recursively).

If console output is detected (and ConsoleColor is true, which is the default) or if ForceColor is set, colorized output similar to logc will be done instead of JSON. levelsDemo/levels.go produces the following output:

When output is redirected, JSON output:

{"ts":1689986143.463329,"level":"dbug","r":1,"file":"levels.go","line":16,"msg":"This is a debug message ending with backslash \\"}
{"ts":1689986143.463374,"level":"trace","r":1,"file":"levels.go","line":17,"msg":"This is a verbose message"}
{"ts":1689986143.463378,"level":"info","r":1,"msg":"This an always printed, file:line omitted message"}
{"ts":1689986143.463382,"level":"info","r":1,"file":"levels.go","line":19,"msg":"This is an info message with no attributes but with \"quotes\"..."}
{"ts":1689986143.463389,"level":"info","r":1,"file":"levels.go","line":20,"msg":"This is multi line\n\tstructured info message with 3 attributes","attr1":"value1","attr2":42,"attr3":"\"quoted\nvalue\""}
{"ts":1689986143.463396,"level":"warn","r":1,"file":"levels.go","line":22,"msg":"This is a warning message"}
{"ts":1689986143.4634,"level":"err","r":1,"file":"levels.go","line":23,"msg":"This is an error message"}
{"ts":1689986143.463403,"level":"crit","r":1,"file":"levels.go","line":24,"msg":"This is a critical message"}
{"ts":1689986143.463406,"level":"fatal","r":1,"file":"levels.go","line":25,"msg":"This is a fatal message"}
This is a non-JSON output, will get prefixed with a exclamation point with logc

When on console:

Example console color output

JSON formatted logs can also be converted back to text later/after capture and similarly colorized using fortio.org/logc

The log.Colors can be used by callers and they'll be empty string when not in color mode, and the ansi escape codes otherwise.

HTTP request/response logging

LogAndCall() combines LogRequest and LogResponse for a light middleware recording what happens during serving of a request (both incoming and outgoing attributes).

For instance (most attributes elided for brevity, also logs client cert and TLSInfo if applicable)

{"level":"info","msg":"test-log-and-call2","method":"GET","url":"/tea","status":418,"size":5,"microsec":100042}

Config

You can either use fortio.org/cli or fortio.org/scli (or dflags) for configuration using flags (or dynamic flags and config map) or use the environment variables:

LOGGER_LOG_PREFIX=' '
LOGGER_LOG_FILE_AND_LINE=false
LOGGER_FATAL_PANICS=false
LOGGER_JSON=false
LOGGER_NO_TIMESTAMP=false
LOGGER_CONSOLE_COLOR=true
LOGGER_FORCE_COLOR=false
LOGGER_GOROUTINE_ID=false
LOGGER_COMBINE_REQUEST_AND_RESPONSE=true
LOGGER_LEVEL='Info'

Small binaries

If you're never logging http requests/responses, use -tags no_http (or -tags no_net) to exclude the http/https logging utilities (which pulls in a lot of dependencies because of net/http init).

If you never need to JSON log complex structures/types that have a special json.Marshaler then you can use -tags no_net,no_json for the smallest executables

(see make size-check)

Documentation

Overview

Fortio's log is simple logger built on top of go's default one with additional opinionated levels similar to glog but simpler to use and configure.

See Config object for options like whether to include line number and file name of caller or not etc

So far it's a "global" logger as in you just use the functions in the package directly (e.g log.S()) and the configuration is global for the process.

Index

Constants

This section is empty.

Variables

View Source
var (

	// ANSI color codes.
	// This isn't meant to be used directly and is here only to document the names of the struct.
	// Use the Colors variable instead.
	ANSIColors = color{
		Reset:     "\033[0m",
		Red:       "\033[31m",
		Green:     "\033[32m",
		Yellow:    "\033[33m",
		Blue:      "\033[34m",
		Purple:    "\033[35m",
		Cyan:      "\033[36m",
		Gray:      "\033[37m",
		White:     "\033[97m",
		BrightRed: "\033[91m",
		DarkGray:  "\033[90m",
	}

	// ANSI color codes or empty depending on ColorMode.
	// These will be reset to empty string if color is disabled (see ColorMode() and SetColorMode()).
	// Start with actual colors, will be reset to empty if color is disabled.
	Colors = ANSIColors

	// Mapping of log levels to color.
	LevelToColor = []string{
		Colors.Gray,
		Colors.Cyan,
		Colors.Green,
		Colors.Yellow,
		Colors.Red,
		Colors.Purple,
		Colors.BrightRed,
		Colors.Green,
	}
	// Used for color version of console logging.
	LevelToText = []string{
		"DBG",
		"VRB",
		"INF",
		"WRN",
		"ERR",
		"CRI",
		"FTL",
		"",
	}
	// Cached flag for whether to use color output or not.
	Color = false
)
View Source
var (
	Config = DefaultConfig()
	// Used for dynamic flag setting as strings and validation.
	LevelToStrA = []string{
		"Debug",
		"Verbose",
		"Info",
		"Warning",
		"Error",
		"Critical",
		"Fatal",
	}

	// Used for JSON logging.
	LevelToJSON = []string{

		"\"dbug\"",
		"\"trace\"",
		"\"info\"",
		"\"warn\"",
		"\"err\"",
		"\"crit\"",
		"\"fatal\"",
		"\"info\"",
	}
	// Reverse mapping of level string used in JSON to Level. Used by https://github.com/fortio/logc
	// to interpret and colorize pre existing JSON logs.
	JSONStringLevelToLevel map[string]Level
)

Functions

func ColorLevelToStr added in v1.9.2

func ColorLevelToStr(lvl Level) string

Longer version when colorizing on console of the level text.

func ColorMode added in v1.6.0

func ColorMode() bool

ColorMode returns true if we should be using color text mode, which is either because it's forced or because we are in a console and the config allows it. Should not be called often, instead read/update the Color variable when needed.

func ConsoleLogging added in v1.6.0

func ConsoleLogging() bool

ConsoleLogging is a utility to check if the current logger output is a console (terminal).

func Critf

func Critf(format string, rest ...interface{})

Critf logs if Warning level is on.

func Debugf

func Debugf(format string, rest ...interface{})

Debugf logs if Debug level is on.

func EnvHelp added in v1.12.0

func EnvHelp(w io.Writer)

EnvHelp shows the current config as environment variables.

LOGGER_LOG_PREFIX, LOGGER_LOG_FILE_AND_LINE, LOGGER_FATAL_PANICS, LOGGER_JSON, LOGGER_NO_TIMESTAMP, LOGGER_CONSOLE_COLOR, LOGGER_CONSOLE_COLOR LOGGER_FORCE_COLOR, LOGGER_GOROUTINE_ID, LOGGER_COMBINE_REQUEST_AND_RESPONSE, LOGGER_LEVEL.

func Errf

func Errf(format string, rest ...interface{})

Errf logs if Warning level is on.

func FErrf

func FErrf(format string, rest ...interface{}) int

FErrF logs a fatal error and returns 1. meant for cli main functions written like:

func main() { os.Exit(Main()) }

and in Main() they can do:

if err != nil {
	return log.FErrf("error: %v", err)
}

so they can be tested with testscript. See https://github.com/fortio/delta/ for an example.

func Fatalf

func Fatalf(format string, rest ...interface{})

Fatalf logs if Warning level is on and panics or exits.

func Infof

func Infof(format string, rest ...interface{})

Infof logs if Info level is on.

func InterceptStandardLogger added in v1.10.0

func InterceptStandardLogger(level Level)

InterceptStandardLogger changes the output of the standard logger to use ours, at the given level, with the source "std", as a catchall.

func Log

func Log(lvl Level) bool

Log returns true if a given level is currently logged.

func LogAndCall added in v1.12.0

func LogAndCall(msg string, handlerFunc http.HandlerFunc, extraAttributes ...KeyVal) http.HandlerFunc

LogAndCall logs the incoming request and the response code, byte size and duration of the request.

If Config.CombineRequestAndResponse or the LOGGER_COMBINE_REQUEST_AND_RESPONSE environment variable is true, then a single log entry is done combining request and response information, including catching for panic.

Additional key:value pairs can be passed as extraAttributes.

func LogDebug

func LogDebug() bool

LogDebug shortcut for fortio.Log(fortio.Debug).

func LogRequest added in v1.1.0

func LogRequest(r *http.Request, msg string, extraAttributes ...KeyVal)

LogRequest logs the incoming request, TLSInfo, including headers when loglevel is verbose. additional key:value pairs can be passed as extraAttributes.

func LogResponse added in v1.12.0

func LogResponse[T *ResponseRecorder | *http.Response](r T, msg string, extraAttributes ...KeyVal)

LogResponse logs the response code, byte size and duration of the request. additional key:value pairs can be passed as extraAttributes.

func LogVerbose

func LogVerbose() bool

LogVerbose shortcut for fortio.Log(fortio.Verbose).

func LogVf

func LogVf(format string, rest ...interface{})

LogVf logs if Verbose level is on.

func Logf

func Logf(lvl Level, format string, rest ...interface{})

Logf logs with format at the given level. 2 level of calls so it's always same depth for extracting caller file/line. Note that log.Logf(Fatal, "...") will not panic or exit, only log.Fatalf() does.

func LoggerStaticFlagSetup added in v1.2.0

func LoggerStaticFlagSetup(names ...string)

LoggerStaticFlagSetup call to setup a static flag under the passed name or `-loglevel` by default, to set the log level. Use https://pkg.go.dev/fortio.org/dflag/dynloglevel#LoggerFlagSetup for a dynamic flag instead.

func NewStdLogger added in v1.10.0

func NewStdLogger(source string, level Level) *log.Logger

Returns a Std logger that will log to the given level with the given source attribute. Can be passed for instance to net/http/httputil.ReverseProxy.ErrorLog.

func Printf

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

Printf forwards to the underlying go logger to print (with only timestamp prefixing).

func S added in v1.4.0

func S(lvl Level, msg string, attrs ...KeyVal)

S logs a message of the given level with additional attributes.

func SetColorMode added in v1.6.0

func SetColorMode()

SetColorMode computes whether we currently should be using color text mode or not. Need to be reset if config changes (but is already automatically re evaluated when calling SetOutput()). It will reset the Colors variable to either be the actual escape sequences or empty strings (when color is disabled).

func SetDefaultsForClientTools

func SetDefaultsForClientTools()

SetDefaultsForClientTools changes the default value of LogPrefix and LogFileAndLine to make output without caller and prefix, a default more suitable for command line tools (like dnsping). Needs to be called before flag.Parse(). Caller could also use log.Printf instead of changing this if not wanting to use levels. Also makes log.Fatalf just exit instead of panic.

func SetFlags

func SetFlags(f int)

SetFlags forwards flags to the system logger.

func SetLogLevelStr

func SetLogLevelStr(str string) error

Sets level from string (called by dflags). Use https://pkg.go.dev/fortio.org/dflag/dynloglevel#LoggerFlagSetup to set up `-loglevel` as a dynamic flag (or an example of how this function is used).

func SetOutput

func SetOutput(w io.Writer)

SetOutput sets the output to a different writer (forwards to system logger).

func TLSInfo added in v1.1.0

func TLSInfo(r *http.Request) string

TLSInfo returns ' https <cipher suite> "<peer CN>"' if the request is using TLS (and ' "<peer CN>"' part if mtls / a peer certificate is present) or "" otherwise. Use AppendTLSInfoAttrs unless you do want to just output text.

func TimeToTS added in v1.4.0

func TimeToTS(t time.Time) float64

Converts a time.Time to a float64 timestamp (seconds since epoch at microsecond resolution). This is what is used in JSONEntry.TS.

func Warnf

func Warnf(format string, rest ...interface{})

Warnf logs if Warning level is on.

Types

type JSONEntry added in v1.4.0

type JSONEntry struct {
	TS    float64 // In seconds since epoch (unix micros resolution), see TimeToTS().
	R     int64   // Goroutine ID (if enabled)
	Level string
	File  string
	Line  int
	Msg   string
}

JSONEntry is the logical format of the JSON [Config.JSON] output mode. While that serialization of is custom in order to be cheap, it maps to the following structure.

func (*JSONEntry) Time added in v1.4.0

func (l *JSONEntry) Time() time.Time

Time() converts a LogEntry.TS to time.Time. The returned time is set UTC to avoid TZ mismatch. Inverse of TimeToTS().

type KeyVal added in v1.4.0

type KeyVal struct {
	Key      string
	StrValue string
	Value    fmt.Stringer
	Cached   bool
}

func AddIfNotEmpty added in v1.12.0

func AddIfNotEmpty(attrs []KeyVal, key, value string) []KeyVal

func Any added in v1.11.0

func Any[T ValueTypes](key string, value T) KeyVal

func AppendTLSInfoAttrs added in v1.4.0

func AppendTLSInfoAttrs(attrs []KeyVal, r *http.Request) []KeyVal

func Attr added in v1.4.0

func Attr[T ValueTypes](key string, value T) KeyVal

Our original name, now switched to slog style Any.

func Bool added in v1.11.0

func Bool(key string, value bool) KeyVal

func Float64 added in v1.11.0

func Float64(key string, value float64) KeyVal

func Int added in v1.11.0

func Int(key string, value int) KeyVal

Few more slog style short cuts.

func Int64 added in v1.11.0

func Int64(key string, value int64) KeyVal

func Rune added in v1.14.0

func Rune(key string, value rune) KeyVal

func Str added in v1.4.0

func Str(key, value string) KeyVal

func String added in v1.11.0

func String(key, value string) KeyVal

String() is the slog compatible name for Str. Ends up calling Any() anyway.

func (*KeyVal) StringValue added in v1.11.0

func (v *KeyVal) StringValue() string

type Level

type Level int32

Level is the level of logging (0 Debug -> 6 Fatal).

const (
	Debug Level = iota
	Verbose
	Info
	Warning
	Error
	Critical
	Fatal
	NoLevel
	// Prefix for all config from environment,
	// e.g NoTimestamp becomes LOGGER_NO_TIMESTAMP.
	EnvPrefix = "LOGGER_"
)

Log levels. Go can't have variable and function of the same name so we keep medium length (Dbg,Info,Warn,Err,Crit,Fatal) names for the functions.

func GetLogLevel

func GetLogLevel() Level

GetLogLevel returns the currently configured LogLevel.

func LevelByName

func LevelByName(str string) Level

LevelByName returns the LogLevel by its name.

func SetLogLevel

func SetLogLevel(lvl Level) Level

SetLogLevel sets the log level and returns the previous one.

func SetLogLevelQuiet

func SetLogLevelQuiet(lvl Level) Level

SetLogLevelQuiet sets the log level and returns the previous one but does not log the change of level itself.

func ValidateLevel

func ValidateLevel(str string) (Level, error)

ValidateLevel returns error if the level string is not valid.

func (Level) String

func (l Level) String() string

String returns the string representation of the level.

type LogConfig

type LogConfig struct {
	LogPrefix      string    // "Prefix to log lines before logged messages
	LogFileAndLine bool      // Logs filename and line number of callers to log.
	FatalPanics    bool      // If true, log.Fatalf will panic (stack trace) instead of just exit 1
	FatalExit      func(int) `env:"-"` // Function to call upon log.Fatalf. e.g. os.Exit.
	JSON           bool      // If true, log in structured JSON format instead of text (but see ConsoleColor).
	NoTimestamp    bool      // If true, don't log timestamp in json.
	ConsoleColor   bool      // If true and we detect console output (not redirected), use text+color mode.
	// Force color mode even if logger output is not console (useful for CI that recognize ansi colors).
	// SetColorMode() must be called if this or ConsoleColor are changed.
	ForceColor bool
	// If true, log the goroutine ID (gid) in json.
	GoroutineID bool
	// If true, single combined log for LogAndCall
	CombineRequestAndResponse bool
	// String version of the log level, used for setting from environment.
	Level string
}

func DefaultConfig

func DefaultConfig() *LogConfig

DefaultConfig() returns the default initial configuration for the logger, best suited for servers. It will log caller file and line number, use a prefix to split line info from the message and panic (+exit) on Fatal. It's JSON structured by default, unless console is detected. Use SetDefaultsForClientTools for CLIs.

type LoggerI

type LoggerI interface {
	Printf(format string, rest ...interface{})
}

LoggerI defines a log.Logger like interface to pass to packages for simple logging. See [Logger()]. See also [NewStdLogger()] for intercepting with same type / when an interface can't be used.

func Logger

func Logger() LoggerI

Logger returns a LoggerI (standard logger compatible) that can be used for simple logging.

type ResponseRecorder added in v1.12.0

type ResponseRecorder struct {
	StatusCode    int
	ContentLength int64
	// contains filtered or unexported fields
}

Can be used (and is used by LogAndCall()) to wrap a http.ResponseWriter to record status code and size.

func (*ResponseRecorder) Flush added in v1.12.0

func (rr *ResponseRecorder) Flush()

Implement http.Flusher interface.

func (*ResponseRecorder) Header added in v1.12.0

func (rr *ResponseRecorder) Header() http.Header

func (*ResponseRecorder) Write added in v1.12.0

func (rr *ResponseRecorder) Write(p []byte) (int, error)

func (*ResponseRecorder) WriteHeader added in v1.12.0

func (rr *ResponseRecorder) WriteHeader(code int)

type ValueType added in v1.4.0

type ValueType[T ValueTypes] struct {
	Val T
}

func (ValueType[T]) String added in v1.4.0

func (v ValueType[T]) String() string

type ValueTypes added in v1.4.0

type ValueTypes interface{ any }

Directories

Path Synopsis
Package goroutine provides a single function that will return the runtime's ID number for the calling goroutine.
Package goroutine provides a single function that will return the runtime's ID number for the calling goroutine.
Initially from https://github.com/fortio/logc/blob/v1.1.0/levelsDemo/levels.go
Initially from https://github.com/fortio/logc/blob/v1.1.0/levelsDemo/levels.go

Jump to

Keyboard shortcuts

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