logging

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: May 21, 2019 License: MIT Imports: 10 Imported by: 5

README

Slogging

A simple logging framework for go that strives to be familiar while still being powerful.

Table Of Contents

Basic Usage

Using the slogging package directly you can just call Info, Debug, Warn, or Error to use the singleton root logger. Like so:

package main

import (
    "github.com/daihasso/slogging"
)

func main() {
    logging.Info("Hello world!")
}

This would result in something like following log:

{"log_level":"INFO","message":"Hello world!","timestamp":1552169765}

The default format for the root logger is JSON. This is chosen with the idea of deployments to production in mind. You may want to change this to something a little more readable for local testing. You can that like so:

package main

import (
    "github.com/daihasso/slogging"
)

func main() {
    logging.GetRootLogger().SetFormat(logging.Standard)
    logging.Info("Hello world!")
}

This would result in the much more straightforward log-line:

2019-03-09T14:59:50 INFO Hello world!

* NOTE: Changing the root logger directly can be dangerous if you're using multiple logger instances as new loggers are based on the root logger. Keep this in mind when changing the root logger.

Creating a new logger

If you want a specialized instance of a Logger you can get one like so:

package main

import (
    "os"
    "strings"

    "github.com/daihasso/slogging"
)

func main() {
    myBuf := new(strings.Builder)
    newLogger := logging.NewLogger(
        "MyCustomLogger",
        logging.WithFormat(logging.StandardExtended),
        logging.WithWriters(os.Stdout, myBuf),
        logging.WithLogLevel(logging.ERROR),
    )
    
    newLogger.Error("Just kidding, no error!")
}

This would result in something like the following being outputted to stdout and to myBuf:

timestamp           | log_level | message
2019-03-09T14:59:50 | ERROR     | Just kidding, no error!

Retrieving Loggers By Identifier

Every logger has an identifier (accessable via logger.Identifier()) which is entered into a global registry in the slogging framework. This means if you want to retrieve a given logger somewhere else in your code.

package main

import (
    "os"
    "strings"

    "github.com/daihasso/slogging"
)

func main() {
    myLogger, ok := logging.GetLogger(MyLogger)
    if myLogger == nil {
        panic("MyLogger didn't exist!!!")
    }
    
    myLogger.Info(
}

func init() {
    logging.NewLogger(
        "MyLogger",
        logging.WithFormat(logging.Standard),
        logging.WithLogLevel(logging.DEBUG),
    )
}

Logging Extras

Sometimes you don't just want to log a message, you also want to log some extra data. With slogging, that's relatively straightforward:

package main

import (
    "os"
    "strings"

    "github.com/daihasso/slogging"
)

func main() {
    logging.GetRootLogger().SetFormat(logging.Standard)
    logging.Info("Started app.", logging.Extras{
        "app_name": "Logging Test App"
    })
}

This would result in a log like the following:

2019-03-09T14:59:50 INFO app_name="Logging Test App" Started app.

* NOTE: Generally the provided keys are used as-is however; for Standard format variants \r, \n and whitespace is removed and replaced with _.

Your value for your extras doesn't even have to be a string! The provided value will be marshalled into the log format (For Standard variants fmt.Sprint is used to format the value).

package main

import (
    "os"
    "strings"

    "github.com/daihasso/slogging"
)

type MyStruct struct {
    Name string
}

func main() {
    logging.GetRootLogger().SetFormat(logging.Standard)
    
    myStruct := MyStruct{
        Name: "Structicus",
    }
    logging.Info("Started app.", logging.Extras{
        "app_name": "Logging Test App",
        "my_struct": myStruct,
    })
}
2019-03-09T15:42:20 INFO app_name="Logging Test App" test="{Structicus}" Started app.

Default Extras

Sometimes you want all logs for a logger to have a set of default Extras that they log along with your message. This is where default extras come in.

package main

import (
    "os"
    "strings"

    "github.com/daihasso/slogging"
)

func main() {
    newLogger := logging.NewLogger(
        "MyLoggerWithDefaultExtras",
        logging.WithFormat(logging.Standard),
        logging.WithDefaultExtras(
            StaticExtras(Extras{
                "app_name": "MyApp",
            }),
        ),
    )
    newLogger.Info("Started app.")
}

This would result in the following log line.

2019-03-09T15:52:13 INFO app_name="MyApp" Started app.
Global Default Extras

Default Extras can also be set on a global scale--meaning every single logger will evaluate these before logging. This can be done like so:

package main

import (
    "os"
    "strings"

    "github.com/daihasso/slogging"
)

func main() {
    logging.AddGlobalExtras(
        StaticExtras(Extras{
            "app_name": "MyGlobalApp",
        }),
    ),
    newLogger := logging.NewLogger(
        "MyLogger",
        logging.WithFormat(logging.Standard),
    )
    newLogger.Info("Started app.")
}

This would result in the following log line.

2019-03-09T15:52:13 INFO app_name="MyGlobalApp" Started app.
Advanced Usage

There are actually two types of default Extras; StaticExtras and FunctionalExtras. The former takes extras in the format you would normally for a specific log line as discussed above and the latter takes in a function that is evaluated at log-time. Let's see FunctionlExtras in action.

package main

import (
    "os"
    "strings"

    "github.com/daihasso/slogging"
)

func main() {
    logCount := 0
    newLogger := logging.NewLogger(
        "MyLoggerWithSharedExtras",
        logging.WithFormat(logging.Standard),
        logging.WithDefaultExtras(
            Functional(ExtrasFuncs{
                "total_log_statements": func() (interface{}, error) {
                    logCount++
                    return logCount, nil
                },
            }),
        ),
    )
    newLogger.Info("Started app.")
    newLogger.Info("Quitting app.")
}

This would result in the following logs:

2019-03-09T15:55:24 INFO total_log_statements="1" Started app.
2019-03-09T15:55:25 INFO total_log_statements="2" Quitting app.

It's really quite powerful when used properly.

Logging formats

Three formats are currently supported:

  • JSON
  • Standard
  • Standard Extended
JSON Example
{"log_level":"INFO","message":"Hello world!","extra_key":"extra_value","timestamp":1552172390}
Standard Example
2019-03-09T14:59:50 INFO extra_key="extra_value" Hello world!
Standard Extended Example
timestamp           | log_level | extra_key   | message
2019-03-09T14:59:50 | INFO      | extra_value | Hello World!

Compatibility

You may find yourself needing to provide a Logger to a library that expects a io.Writer or a *log.Logger. For this slogging provides the PseudoWriter.

package main

import (
    "os"
    "strings"

    "github.com/daihasso/slogging"
)

func main() {
    pseudoWriter := logging.NewPseudoWriter(
        logging.ERROR, logging.GetRootLogger(),
    )

    server := http.Server{
        Addr: "localhost:8080",
        ErrorLog: log.New(pseudoWriter, "", 0),
    }
    
    server.ListenAndServe()
}

The PseudoWriter is an ultra simple wrapper which simply wraps your logger and logs to the provided LogLevel when Write is called on it.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	SloggingEnvVarPrefix = "SLOGGING"

	RootLoggerLevelEnvVar  = prefixEnvVar("ROOT_LOGGER_LEVEL")
	RootLoggerFormatEnvVar = prefixEnvVar("ROOT_LOGGER_FORMAT")
	StringifyByteArrays    = true
)

Functions

func AddGlobalExtras added in v0.1.0

func AddGlobalExtras(extras ...ExtrasGenerator)

AddGlobalExtras appends the provided extras to the global extras.

func Debug

func Debug(message string, extras ...Extras)

Debug uses the root logger to log to debug level.

func Error

func Error(message string, extras ...Extras)

Error uses the root logger to log to error level.

func Exception added in v1.0.0

func Exception(err error, message string, extras ...Extras)

Exception uses the root logger to log an error at error level.

func GetLogLevelsForString

func GetLogLevelsForString(logLevel string) (map[LogLevel]bool, error)

GetLogLevelsForString will get the appropriate loglevels for a string log level representation.

func Info

func Info(message string, extras ...Extras)

Info uses the root logger to log to info level.

func SetGlobalExtras added in v0.1.0

func SetGlobalExtras(extras ...ExtrasGenerator)

SetGlobalExtras sets the global extras.

func SetRootLogger added in v1.0.0

func SetRootLogger(identifier string, logger *Logger) error

SetRootLogger will use the provided identifier as the default logger for future log calls.

func SetRootLoggerExisting added in v1.0.0

func SetRootLoggerExisting(identifier string) error

SetRootLoggerExisting will use the provided identifier as the default logger for future log calls.

func Warn

func Warn(message string, extras ...Extras)

Warn uses the root logger to log to warn level.

Types

type Extras added in v0.3.2

type Extras map[string]interface{}

Extras defines a key, value map that will be marshaled to the final log message.

func Extra added in v0.3.2

func Extra(key string, value interface{}) Extras

Extra is a convinience function for creating an Extras map it has some overhead of generating several extras that will have to be combined but it may be prefereable at times.

type ExtrasFuncs added in v0.3.2

type ExtrasFuncs map[string]ValueFunc

ExtrasFuncs is a map of key, values which will be evaluated at log-time to get the resulting log value.

type ExtrasGenerator added in v0.3.2

type ExtrasGenerator func() (Extras, error)

ExtrasGenerator is a function which produces an Extras map when called. The resulting Extras (and possibly error) will be handled by the logger.

func FunctionalExtras added in v0.3.2

func FunctionalExtras(
	attributeFuncs ExtrasFuncs,
) ExtrasGenerator

FunctionalExtras adds all items in a key, value (function) map that will append:

key: value()

to the log for each item in the map. Refer to log formats specifications for how this will look when logged.

func GetGlobalExtras added in v0.1.0

func GetGlobalExtras() []ExtrasGenerator

GetGlobalExtras returns the global extras.

func StaticExtras added in v0.3.2

func StaticExtras(attributes Extras) ExtrasGenerator

StaticExtras adds all items in a key, value (Extras) map that will append:

key: value

to the log for each item in the map. Refer to log formats specifications for how this will look when logged.

type LogFormat

type LogFormat int

LogFormat is a representation of what format a log should output.

const (
	UnsetFormat LogFormat = iota
	UnknownFormat
	JSON
	Standard
	StandardExtended
)

Definition of all the available LogFormats known by this framework.

func FormatFromString added in v1.0.2

func FormatFromString(format string) LogFormat

FormatFromString takes a string and returns a format for it.

type LogLevel

type LogLevel string

LogLevel is a representation of the logging level for a logger.

const (
	UnsetLogLevel LogLevel = ""
	ERROR         LogLevel = "ERROR"
	WARN          LogLevel = "WARN"
	INFO          LogLevel = "INFO"
	DEBUG         LogLevel = "DEBUG"
)

Definition of LogLevels for a logger.

func LogLevelFromString added in v0.3.2

func LogLevelFromString(logLevel string) LogLevel

type Logger

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

Logger is a logger instance that provides a unified interface for logging data.

func CloneLogger added in v1.0.1

func CloneLogger(
	identifier string, baseLogger *Logger, options ...LoggerOption,
) (*Logger, error)

CloneLogger creates a new logger basing it off the provided logger.

func GetLogger added in v1.0.0

func GetLogger(identifier string) *Logger

GetLogger get an existing logger by its identifier.

func GetRootLogger added in v1.0.0

func GetRootLogger() *Logger

GetRootLogger gets the root logger.

func NewLogger added in v0.3.2

func NewLogger(
	identifier string, options ...LoggerOption,
) (*Logger, error)

NewLogger creates a new logger basing it off the default/root logger.

func (*Logger) AddDefaultExtras added in v1.0.0

func (self *Logger) AddDefaultExtras(
	extras ExtrasGenerator, otherExtras ...ExtrasGenerator,
)

AddDefaultExtras adds extra(s) which will be added for every log made with this logger.

func (*Logger) AddWriters added in v1.0.0

func (self *Logger) AddWriters(w io.Writer, otherWs ...io.Writer)

AddWriters adds writers provided to the existing writers if they don't already exist (duplicates will not be added multiple times).

func (Logger) Close added in v1.0.0

func (self Logger) Close()

Close removes this logger from the global Logger registry and performs any cleanup tasks. It is not required to call this function when you're done with a logger but it is highly recommended to clear up memory and prevent accidental identifier clashing.

func (Logger) Debug

func (self Logger) Debug(message string, extras ...Extras)

Debug logs according to this loggers formatter at the DEBUG level.

func (Logger) Error

func (self Logger) Error(message string, extras ...Extras)

Error logs according to this loggers formatter at the ERROR level.

func (Logger) Exception added in v1.0.0

func (self Logger) Exception(
	err error, message string, extras ...Extras,
)

Exception logs an error's contents & stack at an error level.

func (Logger) Identifier added in v1.0.0

func (self Logger) Identifier() string

Identifier provides this Logger's identifier in the global Logger registry.

func (Logger) Info

func (self Logger) Info(message string, extras ...Extras)

Info logs according to this loggers formatter at the INFO level.

func (Logger) Log

func (self Logger) Log(level LogLevel, messageBytes []byte)

Log is the most basic log function. It logs the bytes directly if the loglevel is enabled. No aditional formating is done.

func (*Logger) RemoveWriter added in v1.0.0

func (self *Logger) RemoveWriter(w io.Writer)

RemoveWriter removes the provided writer if it is found.

func (*Logger) SetDefaultExtras added in v1.0.0

func (self *Logger) SetDefaultExtras(
	extras ExtrasGenerator, otherExtras ...ExtrasGenerator,
)

SetDefaultExtras sets (overriding) the extra(s) which will be added for every log made with this logger.

func (*Logger) SetFormat added in v1.0.0

func (self *Logger) SetFormat(logFormat LogFormat)

SetFormat changes the loggers format to the provided format.

func (*Logger) SetLogLevel added in v0.1.0

func (self *Logger) SetLogLevel(logLevel LogLevel) error

SetLogLevel sets this logger to log at the provided LogLevel and below.

func (*Logger) SetWriters added in v1.0.0

func (self *Logger) SetWriters(w io.Writer, otherWs ...io.Writer)

SetWriters sets the internal logger's writers to the provided writer(s).

func (Logger) Warn

func (self Logger) Warn(message string, extras ...Extras)

Warn logs according to this loggers formatter at the WARN level.

type LoggerOption added in v0.3.2

type LoggerOption func(*loggerConfig) error

LoggerOption is an option used when creating a new Logger.

func WithDefaultExtras added in v0.3.2

func WithDefaultExtras(
	extraParam ExtrasGenerator, extraParams ...ExtrasGenerator,
) LoggerOption

WithDefaultExtras provides one or many Extras that will be logged for every log statement for this Logger.

func WithFormat added in v0.3.2

func WithFormat(logFormat LogFormat) LoggerOption

WithFormat sets the new Logger's format to the provided format.

func WithLogLevel added in v0.3.2

func WithLogLevel(logLevel LogLevel) LoggerOption

WithLogLevel sets this Logger's log level to the provided LogLevel.

func WithLogWriters added in v0.3.2

func WithLogWriters(primary io.Writer, others ...io.Writer) LoggerOption

WithLogWriters sets the provided Logger's writers to the provided writers.

type PseudoWriter

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

PseudoWriter is a wrapper for JSONLogger for things that need a writer to output.

func NewPseudoWriter added in v1.0.0

func NewPseudoWriter(logLevel LogLevel, logger *Logger) *PseudoWriter

NewPsuedoWriter wraps a logger with the Write functionality wich writes out logs at a specified log level.

func (PseudoWriter) Write

func (self PseudoWriter) Write(p []byte) (n int, err error)

Write satisfies the io.Writer interface and writes the the logger it wraps.

type ValueFunc added in v0.3.2

type ValueFunc func() (interface{}, error)

ValueFunc defines a function which will generate the eventual value that will be logged for a ExtrasFunc map.

Jump to

Keyboard shortcuts

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