log

package module
v0.0.0-...-42b3097 Latest Latest
Warning

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

Go to latest
Published: Dec 14, 2020 License: Apache-2.0 Imports: 7 Imported by: 5

README

log GoDoc

There is more to it, than picking the next logger and call it a day, to get logging right. First, you have to be clear about your intention. What do you really need, logging, monitoring or tracing?

about logging

Logging is about tracking events and their related data. Think about administrators as your customer. In the old days, log files where managed entirely by the application itself, e.g. by appending to existing files and rotating when required. Today, most operating systems provide advanced logging facilities attached to stdout. On Linux, this is likely the systemd journal. Thus, there is usually no need anymore to handle this in the applications' layer.

However, the most important finding about logging is, that this is NOT the correct place to (solely) inform about alerts, warnings or panic situations: consider, that nobody will read your logs. A common way to collect, inspect and filter log data is using elastic search and kibana.

about tracing

Tracing is about following the programs' flow, typically from a user perspective. This may be accomplished by heavy and very verbose logging instruments, but indeed tools like Jaeger are more suited for this.

about monitoring

Monitoring is about instrumenting, collecting, aggregating and analyzing metrics to understand the behavior of your application and system, especially under load. Well known tools are Prometheus and Grafana.

how to log right?

If you are still here and are sure, that you need to log information, keep the following rules of thumb in mind:

  • avoid any vendor lock-in into existing logging frameworks by linking directly to them.
  • realize, that log levels do not make sense. Real errors will cause your application to halt just like a panic or an os.Exit. Anything else is an information, and the evaluation is in the eye of the beholder. It is worth to read the article from Dave Cheney.
  • logging hurts performance, and in high performance code, the argument propagation will still cause allocations and even worse - escaping to the heap. To enable verbose logs, guard all according calls with compile time flags, so that the actual calls can get eliminated entirely.
  • use a standard scheme for your fields, like the ECS field reference.

This is our recommended logging interface:

// Field is an interface to an explicit key/value tuple, to be clear about structured information.
type Field interface {
    // Key returns the unique key of this structured Field.
    Key() string
    // Value returns an arbitrary message, which itself may be structured.
    Value() interface{}
}

type Logger interface {
    // Println processes and prints the arguments as fields. The interpretation and formatting depends on the
    // concrete implementation and may range from fmt.Println over log.Println to a full structured logger.
    // Implementations are encouraged to type-switch on each field.
    Println(fields ...interface{})
}

This is our recommended guard:

// +build !debug

package log

// Debug is a build tag determined at build time, so that the compiler can remove dead code.
const Debug = false

Available implementations

usage

If you want zero dependencies, just copy the recommended logging interface and provide injection capabilities through factory methods. Alternatively, this package provides a standard factory and three simple but ready-to use logger implementations. To get the best of both worlds, we recommend to just start with the dependency, and optimize later by setting a factory to any of the implementations above, when required. Note, that the default logger is simple.PrintColored, if started from within your IDE and otherwise simple.PrintStructured. However, you can change it using SetDefault to whatever you like.

There are also the following default special treatments: *

package main

import (
  "github.com/golangee/log"
  "github.com/golangee/log/ecs"
  "context"
)

func main(){
    // prints from IDE: 2020-12-14T10:46:37+01:00 my.logger hello world
    // prints in prod: {"@timestamp":"2020-12-14T10:46:37+01:00","log.logger":"my.logger","message":"hello world"}
    log.Println("hello world")

    // prints from IDE: 2020-12-14T10:46:37+01:00 my.logger INFO auto message https://automatic.url automatic error *errors.errorString
    // prints in prod: {"@timestamp":"2020-12-14T10:46:37+01:00","error.message":"automatic error","error.type":"*errors.errorString","log.level":"info","log.logger":"my.logger","message":"auto message","url.path":"https://automatic.url"}
    log.Println("info", "auto message", "https://automatic.url", fmt.Errorf("automatic error"))
	
    // how to create custom logger setup
    myLogger := log.NewLogger(ecs.Log("my.logger"))

    // prints from IDE: 2020-11-20T15:26:07+01:00 my.logger hello
    // prints in prod: {"@timestamp":"2020-11-20T15:26:07+01:00","log.level":"trace","log.logger":"my.logger","message":"hello"}
    myLogger.Println(ecs.Msg("hello")) 
    myLogger.Println(ecs.Msg("world"))

    // guard verbose and/or expensive logs
    if log.Debug{
    	myLogger.Println(ecs.Msg("info point 1"), ecs.ErrStack()) 
    }

    // in your http middleware you should use the context
    reqCtx := log.WithLogger(context.Background(), log.WithFields(myLogger, ecs.Log("my.request.logger")))
    log.FromContext(reqCtx).Println(ecs.Msg("from a request"))
}

Documentation

Overview

Package log is not another logger but a simple, clean and potentially dependency free logging facade. It combines ideas from Dave Cheney (https://dave.cheney.net/2015/11/05/lets-talk-about-logging) and Rob Pike (https://github.com/golang/glog) to provide a simple yet efficient structured logging API.

The default logger is created at package initialization time and if your application is executed from the IDE it uses the simple.PrintColored and otherwise simple.PrintStructured logger. Note, that the simple loggers use the standard library log.Print function and disables their time printing (log.SetFlags(0)).

Index

Constants

View Source
const Debug = false

Debug is a build tag determined at build time, so that the compiler can remove dead code.

Variables

This section is empty.

Functions

func IsDevelopment

func IsDevelopment() bool

IsDevelopment evaluates the following sources:

  • if any _INTELLIJ_* environment variable is defined, returns true
  • XPC_SERVICE_NAME contains goland
  • if APP_ENV or NODE_ENV environment variable is set to 'production' returns false, otherwise if specified at all returns true
  • if any VSCODE_* environment variable is defined, returns true
  • otherwise returns false

func Println

func Println(fields ...interface{})

Println delegates directly to the default configured logger. See also Logger, NewLogger and SetDefault.

func SetDefault

func SetDefault(f func(fields ...interface{}))

SetDefault just sets a delegate for NewLogger.

func V

func V(key string, val interface{}) field.DefaultField

V is just a shortcut for a field construction. V is a short version of Value.

func WithFunc

func WithFunc(next func(fields ...interface{}), more ...func() interface{}) func(fields ...interface{})

WithFunc returns a logger func which invokes the more field funcs and appends the given fields to it before invoking next.

func WithLogger

func WithLogger(ctx context.Context, logger Logger) context.Context

WithLogger creates a new context with the given logger.

Types

type Field

type Field interface {
	// Key returns the unique key of this structured Field.
	Key() string
	// Value returns an arbitrary message, which itself may be structured.
	Value() interface{}
}

Field is an interface to an explicit key/value tuple, to be clear about structured information.

type Logger

type Logger interface {
	// Println processes and prints the arguments as fields. The interpretation and formatting depends on the
	// concrete implementation and may range from fmt.Println over log.Println to a full structured logger.
	// Implementations are encouraged to type-switch on each field.
	Println(fields ...interface{})
}

Logger provides the abstraction for logging. It is kept as simple as possible and to avoid recursive dependency cycles by using other interfaces or concrete types. It deliberately breaks with the conventional logger APIs, due to the following considerations:

  • there are verbose developer specific logs which are not important or even bad for life system. You mostly even want that there is no cost for the log parameter propagation, which would cause even more harm like escaping values and heap-pressure, even if disabled. The only way to avoid this, is a guarded compile time constant evaluation.
  • anything else which is so important, that a developer is not sure to turn off in production, must not be guarded. Instead it is up to the administrator or software engineer to filter through the log in a structured way. Any error which does not kill your application, is just another kind of information.
  • any error which does break your post-variants and you cannot continue, should be logged (again, still info) either bail out with a runtime panic or an explicit os.Exit.

func FromContext

func FromContext(ctx context.Context) Logger

FromContext returns the contained logger or a new root logger. Context may be nil.

func NewLogger

func NewLogger(fields ...interface{}) Logger

NewLogger uses the factory to create a new logger. The given fields are prepended.

func WithFields

func WithFields(logger Logger, fields ...interface{}) Logger

WithFields just prepends the given fields before the actual logger field parameters will be passed.

type LoggerFunc

type LoggerFunc func(fields ...interface{})

LoggerFunc allows a function to become a Logger.

func (LoggerFunc) Println

func (f LoggerFunc) Println(fields ...interface{})

Println prints the fields by delegating to the function itself.

Directories

Path Synopsis
Package ecs provides helpers and common field functions for the Elastic Common Schema, see also https://www.elastic.co/guide/en/ecs/current/ecs-field-reference.html
Package ecs provides helpers and common field functions for the Elastic Common Schema, see also https://www.elastic.co/guide/en/ecs/current/ecs-field-reference.html
Package simple provides some naive logging implementations which just do some basic formatting and forward the data to the go standard library log.Print infrastructure.
Package simple provides some naive logging implementations which just do some basic formatting and forward the data to the go standard library log.Print infrastructure.

Jump to

Keyboard shortcuts

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