logger

package module
v1.5.2 Latest Latest
Warning

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

Go to latest
Published: Mar 29, 2022 License: MIT Imports: 22 Imported by: 40

README

go-logger

GoVersion GoDoc License Report

master Test codecov

dev Test codecov

go-logger is a logging library based on node-bunyan.

The output is compatible with the bunyan log reader application from that node package.

Usage

You first start by creating a Logger object that will operate on a Stream.

package main

import "github.com/gildas/go-logger"

var Log = logger.Create("myapp")

Then, you can log messages to the same levels from node-bunyan:

Log.Tracef("This is a message at the trace level for %s", myObject)
Log.Debugf("This is a message at the debug level for %s", myObject)
Log.Infof("This is a message at the trace level for %s", myObject)
Log.Warnf("This is a message at the warn level for %s", myObject)
Log.Errorf("This is a message at the error level for %s", myObject, err)
Log.Fatalf("This is a message at the fatal level for %s", myObject, err)

Note the err variable (must implement the error interface) used with the last two log calls. By just adding it to the list of arguments at Error or Fatal level while not mentioning it in the format string will tell the Logger to spit that error in a bunyan Record field.

More generally, Record fields can be logged like this:

Log.Record("myObject", myObject).Infof("Another message about my object")
Log.Recordf("myObject", "format %s %+v". myObject.ID(), myObject).Infof("This record uses a formatted value")

log := Log.Record("dynamic", func() interface{} { return myObject.Callme() })

log.Infof("This is here")
log.Infof("That is there")

In the last example, the code myObject.Callme() will be executed each time log is used to write a message. This is used, as an example, to add a timestamp to the log's Record.

In addition to the Bunyan core fields, this library adds a couple of Record Fields:

  • topic can be used for stuff like types or general topics (e.g.: "http")
  • scope can be used to scope logging within a topic, like a func or a portion of code.

When the Logger is created its topic and scope are set to "main".

Here is a simple example how Record fields can be used with a type:

type Stuff struct {
    Field1 string
    Field2 int
    Logger *logger.Logger // So Stuff carries its own logger
}

func (s *Stuff) SetLogger(l *logger.Logger) {
    s.Logger = l.Topic("stuff").Scope("stuff")
}

func (s Stuff) DoSomething(other *OtherStuff) error {
    log := s.Logger.Scope("dosomething")

    log.Record("other", other).Infof("Need to do something")
    if err := someFunc(s, other); err != nil {
        log.Errorf("Something went wrong with other", err)
        return err
    }
    return nil
}

The call to Record(key, value) creates a new Logger object. So, they are like Russian dolls when it comes down to actually writing the log message to the output stream. In other words, Record objects are collected from their parent's Logger back to the original Logger.

For example:

var Log   = logger.Create("test")
var child = Log.Record("key1", "value1").Record("key2", "value2")

child will actually be something like Logger(Logger(Logger(Stream to stdout))). Though we added only 2 records.

Therefore, to optimize the number of Logger objects that are created, there are some convenience methods that can be used:

func (s stuff) DoSomethingElse(other *OtherStuff) {
    log := s.Logger.Child("new_topic", "new_scope", "id", other.ID(), "key1", "value1")

    log.Infof("I am logging this stuff")

    log.Records("key2", "value2", "key3", 12345).Warnf("Aouch that hurts!")
}

The Child method will create one Logger that has a Record containing a topic, a scope, 2 keys (id and key1) with their values.

The Records method will create one Logger that has 2 keys (key2 and key3) with their values.

For example, with these methods:

var Log    = logger.Create("test")
var child1 = Log.Child("topic", "scope", "key2", "value2", "key3", "value3")
var child2 = child1.Records("key2", "value21", "key4", "value4")

child1 will be something like Logger(Logger(Stream to stdout)). Though we added 2 records.
child2 will be something like Logger(Logger(Logger(Stream to stdout))). Though we added 1 record to the 2 records added previously.

Stream objects

A Stream is where the Logger actually writes its Record data.

When creating a Logger, you can specify the destination it will write to:

var Log = logger.Create("myapp", "file://path/to/myapp.log")
var Log = logger.Create("myapp", "/path/to/myapp.log")
var Log = logger.Create("myapp", "./localpath/to/myapp.log")
var Log = logger.Create("myapp", "stackdriver")
var Log = logger.Create("myapp", "gcp")
var Log = logger.Create("myapp", "/path/to/myapp.log", "stderr")
var Log = logger.Create("myapp", "nil")

The first three Logger objects will write to a file, the fourth to Google Stackdriver, the fifth to Google Cloud Platform (GCP), the sixth to a file and stderr, and the seventh to nowhere (i.e. logs do not get written at all).

By default, when creating the Logger with:

var Log = logger.Create("myapp")

The Logger will write to the standard output or the destination specified in the environment variable LOG_DESTINATION.

You can also create a Logger by passing it a Stream object (these are equivalent to the previous code):

var Log = logger.Create("myapp", &logger.FileStream{Path: "/path/to/myapp.log"})
var Log = logger.Create("myapp", &logger.StackDriverStream{})
var Log = logger.Create("myapp", &logger.NilStream{})
var Log = logger.Create("myapp", &logger.FileStream{Path: "/path/to/myapp.log"}, &logger.StderrStream{})

A few notes:

  • logger.CreateWithStream can also be used to create with one or more streams.
    (Backward compatibility)
  • logger.CreateWithDestination can also be used to create with one or more destinations.
    (Backward compatibility)
  • the StackDriverStream needs a LogID parameter or the value of the environment variable GOOGLE_PROJECT_ID. (see Google's StackDriver documentation for the description of that parameter).
  • NilStream is a Stream that does not write anything, all messages are lost.
  • MultiStream is a Stream than can write to several streams.
  • StdoutStream and FileStream are buffered by default. Data is written from every LOG_FLUSHFREQUENCY (default 5 minutes) or when the Record's Level is at least ERROR.
  • Streams convert the Record to write via a Converter. The converter is set to a default value per Stream.

You can also create a Logger with a combination of destinations and streams, AND you can even add some records right away:

var Log = logger.Create("myapp",
    &logger.FileStream{Path: "/path/to/myapp.log"},
    "stackdriver",
    NewRecord().Set("key", "value"),
)
Setting the FilterLevel

All Stream types, except NilStream and MultiStream can use a FilterLevel. When set, Record objects that have a Level below the FilterLevel are not written to the Stream. This allows to log only stuff above WARN for instance.

These streams can even use a FilterLevel per topic and scope. This allows to log everything at the INFO level and only the log messages beloging to the topic db at the DEBUG level, for instance. Or even at the topic db and scope disk.

The FilterLevel can be set via the environment variable LOG_LEVEL:

  • LOG_LEVEL=INFO
    will set the FilterLevel to INFO, which is the default if nothing is set;
  • LOG_LEVEL=INFO;DEBUG:{topic1} or LOG_LEVEL=TRACE:{topic1};DEBUG
    will set the FilterLevel to DEBUG and the FilterLevel for the topic topic1 to TRACE (and all the scopes under that topic);
  • LOG_LEVEL=INFO;DEBUG:{topic1:scope1,scope2}
    will set the FilterLevel to INFO and the FilterLevel for the topic topic1 and scopes scope1, scope2 to DEBUG (all the other scopes under that topic will be filtered at INFO);
  • LOG_LEVEL=INFO;DEBUG:{topic1};TRACE:{topic2}
    will set the FilterLevel to INFO and the FilterLevel for the topic topic1 to DEBUG, respectively topic2 and TRACE (and all the scopes under these topics);
  • The last setting of a topic supersedes the ones set before;
  • If the environment variable DEBUG is set to 1, the default FilterLevel is overrident and set to DEBUG.

It is also possible to change the FilterLevel by calling FilterMore()and FilterLess() methods on the Logger or any of its Streamer members. The former will log less data and the latter will log more data. We provide an example of how to use these in the examples folder using Unix signals.

log := logger.Create("myapp", &logger.StdoutStream{})
// We are filtering at INFO
log.FilterLess()
// We are now filtering at DEBUG
StackDriver Stream

If you plan to log to Google's StackDriver from a Google Cloud Kubernetes or a Google Cloud Instance, you do not need the StackDriver Stream and should use the Stdout Stream with the StackDriver Converter, since the standard output of your application will be captured automatically by Google to feed StackDriver:

var Log = logger.Create("myapp", "gcp") // "google" or "googlecloud" are valid aliases
var Log = logger.Create("myapp", &logger.StdoutStream{Converter: &logger.StackDriverConverter{}})

To be able to use the StackDriver Stream from outside Google Cloud, you have some configuration to do first.

On your workstation, you need to get the key filename:

  1. Authenticate with Google Cloud
gcloud auth login
  1. Create a Service Account (logger-account is just an example of a service account name)
gcloud iam service-acccount create logger-account
  1. Associate the Service Account to the Project you want to use
gcloud projects add-iam-policy-binding my-logging-project \
  --member "serviceAccount:logger-account@my-logging-project.iam.gserviceaccount.com" \
  --role "roles/logging.logWriter"
  1. Retrieve the key filename
gcloud iam service-accounts keys create /path/to/key.json \
  --iam-account logger-account@my-logging-project.iam.gserviceaccount.com

You can either set the GOOGLE_APPLICATION_CREDENTIAL and GOOGLE_PROJECT_ID environment variables with the path of the obtained key and Google Project ID or provide them to the StackDriver stream:

var Log = logger.Create("myapp", &logger.StackDriverStream{})
var Log = logger.Create("myapp", &logger.StackDriverStream{
    Parent:      "my-logging-project",
    KeyFilename: "/path/to/key.json",
})
Writing your own Stream

You can also write your own Stream by implementing the logger.Streamer interface and create the Logger like this:

var Log = logger.Create("myapp", &MyStream{})
Miscellaneous

The following convenience methods can be used when creating a Logger from another one (received from arguments, for example):

var Log = logger.CreateIfNil(OtherLogger, "myapp")
var Log = logger.Create("myapp", OtherLogger)

If OtherLogger is nil, the new Logger will write to the NilStream().

var Log = logger.Must(logger.FromContext(context))

Must can be used to create a Logger from a method that returns *Logger, error, if there is an error, Must will panic.

FromContext can be used to retrieve a Logger from a GO context. (This is used in the paragraph about HTTP Usage)

log.ToContext will store the Logger to the given GO context.

Redacting

The Logger can redact records as needed by simply implementing the logger.Redactable interface in the data that is logged.

For example:

type Customer {
  ID   uuid.UUID `json:"id"`
  Name string    `json:"name"`
}

// implements logger.Redactable
func (customer Customer) Redact() interface{} {
  return Customer{customer.ID, "REDACTED"}
}

main() {
  // ...
  customer := Customer{uuid, "John Doe"}

  log.Record("customer", customer).Infof("Got a customer")
}

You can also redact the log messages by providing regular expressions, called redactors. Whenever a redactor matches, its matched content is replaced with "REDACTED".

You can assign several redactors to a single logger:

r1, err := logger.NewRedactor("[0-9]{10}")
r2 := (logger.Redactor)(myregexp)
log := logger.Create("test", r1, r2)

You can also add redactors to a child logger (without modifying the parent logger):

r3 := logger.NewRedactor("[a-z]{8}")
log := parent.Child("topic", "scope", "record1", "value1", r3)

Note: Adding redactors to a logger WILL have a performance impact on your application as each regular expression will be matched against every single message produced by the logger. We advise you to use as few redactors as possible and contain them in child logger, so they have a minmal impact.

Converters

The Converter object is responsible for converting the Record, given to the Stream to write, to match other log viewers.

The default Converter is BunyanConverter so the bunyan log viewer can read the logs.

Here is a list of all the converters:

  • BunyanConverter, the default converter (does nothing, actually),
  • CloudWatchConverter produces logs that are nicer with AWS CloudWatch log viewer.
  • PinoConverter produces logs that can be used by pino,
  • StackDriverConverter produces logs that are nicer with Google StackDriver log viewer,

Note: When you use converters, their output will most probably not work anymore with bunyan. That means you cannot have both worlds in the same Streamer. In some situation, you can survive this by using several streamers, one converted, one not.

Writing your own Converter

You can also write your own Converter by implementing the logger.Converter interface:

type MyConverter struct {
	// ...
}

func (converter *MyConverter) Convert(record Record) Record {
    record["newvalue"] = true
    return record
}

var Log = logger.Create("myapp", &logger.StdoutStream{Converter: &MyConverter{}})

Standard Log Compatibility

To use a Logger with the standard go log library, you can simply call the AsStandardLog() method. You can optionally give a Level:

package main

import (
  "net/http"
	"github.com/gildas/go-logger"
)

func main() {
    log := logger.Create("myapp")

    server1 := http.Server{
      // extra http stuff
      ErrorLog: log.AsStandardLog()
    }

    server2 := http.Server{
      // extra http stuff
      ErrorLog: log.AsStandardLog(logger.WARN)
    }
}

You can also give an io.Writer to the standard log constructor:

package main

import (
  "log"
  "net/http"
	"github.com/gildas/go-logger"
)

func main() {
    mylog := logger.Create("myapp")

    server1 := http.Server{
      // extra http stuff
      ErrorLog: log.New(mylog.Writer(), "", 0),
    }

    server2 := http.Server{
      // extra http stuff
      ErrorLog: log.New(mylog.Writer(logger.WARN), "", 0),
    }
}

Since Writer() returns io.Writer, anything that uses that interface could, in theory, write to a Logger.

HTTP Usage

It is possible to pass Logger objects to http.Handler. When doing so, the Logger will automatically write the request identifier ("X-Request-Id" HTTP Header), remote host, user agent, when the request starts and when the request finishes along with its duration.

The request identifier is attached every time the log writes in a Record.

Here is an example:

package main

import (
  "net/http"
  "github.com/gildas/go-logger"
  "github.com/gorilla/mux"
)

func MyHandler() http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
      // Extracts the Logger from the request's context
      //  Note: Use logger.Must only when you know there is a Logger as it will panic otherwise
      log := logger.Must(logger.FromContext(r.Context()))

      log.Infof("Now we are logging inside this http Handler")
    })
}

func main() {
  log := logger.Create("myapp")
  router := mux.NewRouter()
  router.Methods("GET").Path("/").Handler(log.HttpHandler()(MyHandler()))
}

Environment Variables

The Logger can be configured completely by environment variables if needed. These are:

  • LOG_DESTINATION, default: StdoutStream
    The Streams to write logs to. It can be a comma-separated list (for a MultiStream)
  • LOG_LEVEL, default: INFO
    The level to filter by default. If the environment DEBUG is set the default level is DEBUG
  • LOG_CONVERTER, default: "bunyan"
    The default Converter to use
  • LOG_FLUSHFREQUENCY, default: 5 minutes
    The default Flush Frequency for the streams that will be buffered
  • LOG_OBFUSCATION_KEY, default: none
    The SSL public key to use when obfuscating if you want a reversible obfuscation
  • GOOGLE_APPLICATION_CREDENTIALS
    The path to the credential file for the StackDriverStream
  • GOOGLE_PROJECT_ID
    The Google Cloud Project ID for the StackDriverStream
  • DEBUG, default: none
    If set to "1", this will set the default level to filter to DEBUG

Thanks

Special thanks to @chakrit for his chakrit/go-bunyan that inspired me. In fact earlier versions were wrappers around his library.

Well, we would not be anywhere without the original work of @trentm and the original trentm/node-bunyan. Many, many thanks!

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var VERSION = "1.5.2" + commit

VERSION is the version of this application

Functions

func GetFlushFrequencyFromEnvironment

func GetFlushFrequencyFromEnvironment() time.Duration

GetFlushFrequencyFromEnvironment fetches the flush frequency from the environment

the frequency should be like https://golang.org/pkg/time/#ParseDuration or an ISO8601 duration.

If not set, the frequency will be 5 minutes

func GetLevelsFromEnvironment added in v1.5.0

func GetLevelsFromEnvironment() (Level, TopicScopeLevels)

GetLevelsFromEnvironment retrieves the level and the topic/scope levels from the environment variable LOG_LEVEL

func GetLevelsFromString added in v1.5.0

func GetLevelsFromString(settings string) (level Level, levels TopicScopeLevels)

GetLevelsFromString retrieves the level and the topic/scope levels from the given string

Types

type BunyanConverter added in v1.3.0

type BunyanConverter struct {
}

BunyanConverter is the default Converter

func (*BunyanConverter) Convert added in v1.3.0

func (converter *BunyanConverter) Convert(record Record) Record

Convert converts the Record into a Bunyan compatible Record

type CloudWatchConverter added in v1.5.0

type CloudWatchConverter struct {
}

CloudWatchConverter is used to convert a Record for AWS CloudWatch

func (*CloudWatchConverter) Convert added in v1.5.0

func (converter *CloudWatchConverter) Convert(record Record) Record

Convert converts the Record into a StackDriver compatible Record

type Converter added in v1.3.0

type Converter interface {
	Convert(record Record) Record
}

Converter is used to convert a Record into another format

func GetConverterFromEnvironment added in v1.3.0

func GetConverterFromEnvironment() Converter

GetConverterFromEnvironment fetches the Converter from the environment

type FileStream

type FileStream struct {
	*json.Encoder
	Path         string
	Converter    Converter
	FilterLevel  Level
	FilterLevels TopicScopeLevels
	Unbuffered   bool
	// contains filtered or unexported fields
}

FileStream is the Stream that writes to a file

Any record with a level < FilterLevel will be written

func (*FileStream) Close added in v1.3.0

func (stream *FileStream) Close()

Close closes the stream

implements logger.Streamer

func (*FileStream) FilterLess added in v1.5.0

func (stream *FileStream) FilterLess()

FilterLess tells the stream to filter less

The stream will filter less if it is not already at the lowest level. Which means more log messages will be written to the stream

Example: if the stream is at INFO, it will be filtering at DEBUG

implements logger.FilterModifier

func (*FileStream) FilterMore added in v1.5.0

func (stream *FileStream) FilterMore()

FilterMore tells the stream to filter more

The stream will filter more if it is not already at the highest level. Which means less log messages will be written to the stream

Example: if the stream is at DEBUG, it will be filtering at INFO

implements logger.FilterModifier

func (*FileStream) Flush

func (stream *FileStream) Flush()

Flush flushes the stream (makes sure records are actually written)

implements logger.Streamer

func (*FileStream) SetFilterLevel added in v1.3.0

func (stream *FileStream) SetFilterLevel(level Level)

SetFilterLevel sets the filter level

implements logger.FilterSetter

func (*FileStream) SetFilterLevelForTopic added in v1.5.0

func (stream *FileStream) SetFilterLevelForTopic(level Level, topic string)

SetFilterLevelForTopic sets the filter level for a given topic

implements logger.FilterSetter

func (*FileStream) SetFilterLevelForTopicAndScope added in v1.5.0

func (stream *FileStream) SetFilterLevelForTopicAndScope(level Level, topic, scope string)

SetFilterLevelForTopicAndScope sets the filter level for a given topic

implements logger.FilterSetter

func (*FileStream) SetFilterLevelIfUnset added in v1.4.0

func (stream *FileStream) SetFilterLevelIfUnset(level Level)

SetFilterLevelIfUnset sets the filter level if not set already

implements logger.FilterSetter

func (*FileStream) ShouldWrite

func (stream *FileStream) ShouldWrite(level Level, topic, scope string) bool

ShouldWrite tells if the given level should be written to this stream

implements logger.Streamer

func (*FileStream) String

func (stream *FileStream) String() string

String gets a string version

implements fmt.Stringer

func (*FileStream) Write

func (stream *FileStream) Write(record Record) (err error)

Write writes the given Record

implements logger.Streamer

type FilterModifier added in v1.5.0

type FilterModifier interface {
	// FilterMore tells the stream to filter more
	FilterMore()

	// FilterLess tells the stream to filter less
	FilterLess()
}

FilterModifier describes objects that can modify their Filter Level

type FilterSetter added in v1.5.0

type FilterSetter interface {
	// SetFilterLevel sets the filter level
	SetFilterLevel(level Level)

	// SetFilterLevelForTopic sets the filter level for a given topic
	SetFilterLevelForTopic(level Level, topic string)

	// SetFilterLevelForTopicAndScope sets the filter level for a given topic
	SetFilterLevelForTopicAndScope(level Level, topic, scope string)

	// SetFilterLevelIfUnset sets the filter level if not set already
	SetFilterLevelIfUnset(level Level)
}

FilterSetter describes objects that can set their Filter Level

The Filter Level is the level that will be used to filter what gets written to the Stream: Records with a level lower than the filter level will not be written

type Level

type Level byte

Level represents the log Level The higher the value the more chances to write in the Stream

const (
	// UNSET level means the level is not yet set
	UNSET Level = iota * 10
	// TRACE level should be used for entries that should be used by the developer of the app/package only
	TRACE
	// DEBUG level should be used for detailed logging as they tend to be noisy
	DEBUG
	// INFO level should be used as the standard level. Entries that really mean something to most people should go there
	INFO
	// WARN level should be used when the code considers a situation as not optimal but it can live with it
	WARN
	// ERROR level should be used when the code encounters an issue and normal flow is disrupted
	ERROR
	// FATAL level should be used when the code eoncounters an issue it cannot recover from
	FATAL
	// ALWAYS level should be used for entries that should always be logged, like app version, etc.
	ALWAYS Level = 255
	// NEVER level should be used for entries that should never be logged
	NEVER Level = 1
)

func GetLevelFromEnvironment

func GetLevelFromEnvironment() Level

GetLevelFromEnvironment retrieves the level from the environment LOG_LEVEL

func GetLevelFromRecord

func GetLevelFromRecord(record Record) Level

GetLevelFromRecord retrieves the level from the given Record

func ParseLevel

func ParseLevel(value string) Level

ParseLevel converts a string into a Level

func (Level) Next added in v1.5.0

func (level Level) Next() Level

Next returns the Level that follows the current one

If level is ALWAYS, it will return ALWAYS

Example: TRACE.Next() will return DEBUG

func (Level) Previous added in v1.5.0

func (level Level) Previous() Level

Previous returns the Level that precedes the current one

If level is NEVER, it will return NEVER

Example: DEBUG.Previous() will return TRACE

func (Level) ShouldWrite

func (level Level) ShouldWrite(filter Level) bool

ShouldWrite tells if the current level is writeable when compared to the given filter level

To be writeable, the current level must be higher than the filter level

func (Level) String

func (level Level) String() string

String gets a string version

type Logger

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

Logger is a Logger that creates Bunyan's compatible logs (see: https://github.com/trentm/node-bunyan)

func Create

func Create(name string, parameters ...interface{}) *Logger

Create creates a new Logger

func CreateIfNil

func CreateIfNil(logger *Logger, name string) *Logger

CreateIfNil creates a new Logger if the given Logger is nil, otherwise return the said Logger

func CreateWithDestination

func CreateWithDestination(name string, destinations ...string) *Logger

CreateWithDestination creates a new Logger streaming to the given destination(s)

func CreateWithStream

func CreateWithStream(name string, streams ...Streamer) *Logger

CreateWithStream creates a new Logger streaming to the given stream or list of streams

func FromContext

func FromContext(context context.Context) (*Logger, error)

FromContext retrieves the Logger stored in the context

func Must

func Must(log *Logger, err error) *Logger

Must returns the given logger or panics if there is an error or if the Logger is nil

func (*Logger) AsStandardLog added in v1.3.7

func (log *Logger) AsStandardLog(level ...Level) *stdlog.Logger

AsStandardLog gets a standard GO logger

func (*Logger) Child

func (log *Logger) Child(topic, scope interface{}, params ...interface{}) *Logger

Child creates a child Logger with a topic, a scope, and records

func (*Logger) Close added in v1.3.0

func (log *Logger) Close()

Close closes the logger's stream

implements logger.Streamer

func (*Logger) Debugf

func (log *Logger) Debugf(msg string, args ...interface{})

Debugf traces a message at the DEBUG Level

func (*Logger) Errorf

func (log *Logger) Errorf(msg string, args ...interface{})

Errorf traces a message at the ERROR Level

If the last argument is an error, a Record is added and the error string is added to the message

func (*Logger) Fatalf

func (log *Logger) Fatalf(msg string, args ...interface{})

Fatalf traces a message at the FATAL Level

If the last argument is an error, a Record is added and the error string is added to the message

func (*Logger) FilterLess added in v1.5.0

func (log *Logger) FilterLess()

FilterLess tells the stream to filter less

The stream will filter less if it is not already at the lowest level. Which means more log messages will be written to the stream

Example: if the stream is at INFO, it will be filtering at DEBUG

implements logger.FilterModifier

func (*Logger) FilterMore added in v1.5.0

func (log *Logger) FilterMore()

FilterMore tells the stream to filter more

The stream will filter more if it is not already at the highest level. Which means less log messages will be written to the stream

Example: if the stream is at DEBUG, it will be filtering at INFO

implements logger.FilterModifier

func (*Logger) Flush

func (log *Logger) Flush()

Flush flushes the stream (makes sure records are actually written)

implements logger.Streamer

func (*Logger) GetRecord

func (log *Logger) GetRecord(key string) interface{}

GetRecord returns the Record field value for a given key

func (*Logger) GetScope added in v1.5.0

func (log *Logger) GetScope() string

GetScope returns the Record scope

func (*Logger) GetTopic added in v1.5.0

func (log *Logger) GetTopic() string

GetTopic returns the Record topic

func (*Logger) HttpHandler

func (l *Logger) HttpHandler() func(http.Handler) http.Handler

HttpHandler function will wrap an http handler with extra logging information

func (*Logger) Infof

func (log *Logger) Infof(msg string, args ...interface{})

Infof traces a message at the INFO Level

func (*Logger) Memory added in v1.3.11

func (log *Logger) Memory()

Memory traces memory usage at the TRACE Level

func (*Logger) Memoryf added in v1.3.11

func (log *Logger) Memoryf(msg string, args ...interface{})

Memoryf traces memory usage at the TRACE level with a given message

func (*Logger) Memoryl added in v1.3.11

func (log *Logger) Memoryl(level Level)

Memoryl traces memory usage at the given level

func (*Logger) Memorylf added in v1.3.11

func (log *Logger) Memorylf(level Level, msg string, args ...interface{})

Memorylf traces memory usage at the given level and with the given message

func (*Logger) Record

func (log *Logger) Record(key string, value interface{}) *Logger

Record adds the given Record to the Log

func (*Logger) Recordf

func (log *Logger) Recordf(key, value string, args ...interface{}) *Logger

Recordf adds the given Record with formatted arguments

func (*Logger) Records

func (log *Logger) Records(params ...interface{}) *Logger

Records adds key, value pairs as Record objects

The key should be castable to a string.
If the last value is missing, its key is ignored

E.g.: log.Records("key1", value1, "key2", value2)

func (*Logger) Scope

func (log *Logger) Scope(scope interface{}) *Logger

Scope sets the Scope if this Logger

func (*Logger) SetFilterLevel added in v1.3.0

func (log *Logger) SetFilterLevel(level Level)

SetFilterLevel sets the filter level of the streamer

implements logger.FilterSetter

func (*Logger) SetFilterLevelForTopic added in v1.5.0

func (log *Logger) SetFilterLevelForTopic(level Level, topic string)

SetFilterLevelForTopic sets the filter level for a given topic

implements logger.FilterSetter

func (*Logger) SetFilterLevelForTopicAndScope added in v1.5.0

func (log *Logger) SetFilterLevelForTopicAndScope(level Level, topic, scope string)

SetFilterLevelForTopicAndScope sets the filter level for a given topic

implements logger.FilterSetter

func (*Logger) SetFilterLevelIfUnset added in v1.4.0

func (log *Logger) SetFilterLevelIfUnset(level Level)

SetFilterLevelIfUnset sets the filter level if not set already

implements logger.FilterSetter

func (*Logger) ShouldWrite

func (log *Logger) ShouldWrite(level Level, topic, scope string) bool

ShouldWrite tells if the given level should be written to this stream

implements logger.Streamer

func (Logger) String

func (log Logger) String() string

String gets a string version

implements fmt.Stringer

func (*Logger) ToContext

func (l *Logger) ToContext(parent context.Context) context.Context

ToContext stores the Logger in the given context

func (*Logger) Topic

func (log *Logger) Topic(topic interface{}) *Logger

Topic sets the Topic of this Logger

func (*Logger) Tracef

func (log *Logger) Tracef(msg string, args ...interface{})

Tracef traces a message at the TRACE Level

func (*Logger) Warnf

func (log *Logger) Warnf(msg string, args ...interface{})

Warnf traces a message at the WARN Level

func (*Logger) Write

func (log *Logger) Write(record Record) error

Write writes the given Record

implements logger.Streamer

Example (FailsWithBogusStream)
output := CaptureStderr(func() {
	log := logger.Create("test", &BogusStream{})

	log.Infof("test")
})
fmt.Println(output)
Output:

Logger error: This Stream is Bogus

func (*Logger) Writer added in v1.3.6

func (log *Logger) Writer(level ...Level) io.Writer

Writer gets a n io.Writer to use with the standard log (for example)

type MultiStream

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

MultiStream is the Stream that writes to several streams

func (*MultiStream) Close added in v1.3.0

func (stream *MultiStream) Close()

Close closes the stream

implements logger.Streamer

func (*MultiStream) FilterLess added in v1.5.0

func (stream *MultiStream) FilterLess()

FilterLess tells the stream to filter less

The stream will filter less if it is not already at the lowest level. Which means more log messages will be written to the stream

Example: if the stream is at INFO, it will be filtering at DEBUG

implements logger.FilterModifier

func (*MultiStream) FilterMore added in v1.5.0

func (stream *MultiStream) FilterMore()

FilterMore tells the stream to filter more

The stream will filter more if it is not already at the highest level. Which means less log messages will be written to the stream

Example: if the stream is at DEBUG, it will be filtering at INFO

implements logger.FilterModifier

func (*MultiStream) Flush

func (stream *MultiStream) Flush()

Flush flushes the stream (makes sure records are actually written)

implements logger.Streamer

func (*MultiStream) SetFilterLevel added in v1.3.0

func (stream *MultiStream) SetFilterLevel(level Level)

SetFilterLevel sets the filter level of all streams

implements logger.FilterSetter

func (*MultiStream) SetFilterLevelForTopic added in v1.5.0

func (stream *MultiStream) SetFilterLevelForTopic(level Level, topic string)

SetFilterLevelForTopic sets the filter level for a given topic

implements logger.FilterSetter

func (*MultiStream) SetFilterLevelForTopicAndScope added in v1.5.0

func (stream *MultiStream) SetFilterLevelForTopicAndScope(level Level, topic, scope string)

SetFilterLevelForTopicAndScope sets the filter level for a given topic

implements logger.FilterSetter

func (*MultiStream) SetFilterLevelIfUnset added in v1.4.0

func (stream *MultiStream) SetFilterLevelIfUnset(level Level)

SetFilterLevelIfUnset sets the filter level if not set already

implements logger.FilterSetter

func (*MultiStream) ShouldWrite

func (stream *MultiStream) ShouldWrite(level Level, topic, scope string) bool

ShouldWrite tells if the given level should be written to this stream

If at least one stream returns true, the stream should write the record

implements logger.Streamer

func (MultiStream) String

func (stream MultiStream) String() string

String gets a string version

implements fmt.Stringer

func (*MultiStream) Write

func (stream *MultiStream) Write(record Record) error

Write writes the given Record

implements logger.Streamer

type NilStream

type NilStream struct {
}

NilStream is the Stream that writes nowhere

Example
stream := &logger.NilStream{}

if err := stream.Write(logger.NewRecord().Set("bello", "banana").Set("だれ", "Me")); err != nil {
	os.Stdout.WriteString(err.Error() + "\n")
}
if stream.ShouldWrite(logger.ALWAYS, "", "") {
	os.Stdout.WriteString("This should not be seen\n")
}
stream.Flush()
Output:

func (*NilStream) Close added in v1.3.0

func (stream *NilStream) Close()

Close closes the stream

implements logger.Streamer

func (*NilStream) FilterLess added in v1.5.0

func (stream *NilStream) FilterLess()

FilterLess tells the stream to filter less

The stream will filter less if it is not already at the lowest level. Which means more log messages will be written to the stream

Example: if the stream is at INFO, it will be filtering at DEBUG

implements logger.FilterModifier

func (*NilStream) FilterMore added in v1.5.0

func (stream *NilStream) FilterMore()

FilterMore tells the stream to filter more

The stream will filter more if it is not already at the highest level. Which means less log messages will be written to the stream

Example: if the stream is at DEBUG, it will be filtering at INFO

implements logger.FilterModifier

func (*NilStream) Flush

func (stream *NilStream) Flush()

Flush flushes the stream (makes sure records are actually written)

implements logger.Streamer

func (*NilStream) SetFilterLevel added in v1.3.0

func (stream *NilStream) SetFilterLevel(level Level)

SetFilterLevel sets the filter level of all streams

implements logger.FilterSetter

func (*NilStream) SetFilterLevelForTopic added in v1.5.0

func (stream *NilStream) SetFilterLevelForTopic(level Level, topic string)

SetFilterLevelForTopic sets the filter level for a given topic

implements logger.FilterSetter

func (*NilStream) SetFilterLevelForTopicAndScope added in v1.5.0

func (stream *NilStream) SetFilterLevelForTopicAndScope(level Level, topic, scope string)

SetFilterLevelForTopicAndScope sets the filter level for a given topic

implements logger.FilterSetter

func (*NilStream) SetFilterLevelIfUnset added in v1.4.0

func (stream *NilStream) SetFilterLevelIfUnset(level Level)

SetFilterLevelIfUnset sets the filter level if not set already

implements logger.FilterSetter

func (*NilStream) ShouldWrite

func (stream *NilStream) ShouldWrite(level Level, topic, scope string) bool

ShouldWrite tells if the given level should be written to this stream

implements logger.Streamer

func (NilStream) String

func (stream NilStream) String() string

String gets a string version

implements fmt.Stringer

func (*NilStream) Write

func (stream *NilStream) Write(record Record) error

Write writes the given Record

implements logger.Streamer

type PinoConverter added in v1.3.0

type PinoConverter struct {
}

PinoConverter is used to convert Records to be read by pino

func (*PinoConverter) Convert added in v1.3.0

func (converter *PinoConverter) Convert(record Record) Record

Convert converts the Record into a Pino compatible Record

type Record

type Record map[string]interface{}

Record is the map that contains all records of a log entry

If the value at a key is a func() interface the func will be called when the record is marshaled

func NewRecord

func NewRecord() Record

NewRecord creates a new empty record

func (Record) MarshalJSON

func (record Record) MarshalJSON() ([]byte, error)

MarshalJSON marshals this into JSON

func (Record) Merge

func (record Record) Merge(source Record) Record

Merge merges a source Record into this Record

values already set in this record cannot be overridden

func (Record) Set

func (record Record) Set(key string, value interface{}) Record

Set sets the key and value if not yet set

func (*Record) UnmarshalJSON

func (record *Record) UnmarshalJSON(payload []byte) error

UnmarshalJSON unmarshals JSON into this

type Redactable added in v1.4.0

type Redactable interface {
	Redact() interface{}
}

Redactable can be used by structs that want to redact their fields

When the Logger writes the Record contains a Redactable, it will call Redact

type Redactor added in v1.4.0

type Redactor regexp.Regexp

func NewRedactor added in v1.4.0

func NewRedactor(regex string) (*Redactor, error)

func (Redactor) Redact added in v1.4.0

func (redactor Redactor) Redact(value string) (string, bool)

type StackDriverConverter added in v1.3.0

type StackDriverConverter struct {
}

StackDriverConverter is used to convert a Record for StackDriver

func (*StackDriverConverter) Convert added in v1.3.0

func (converter *StackDriverConverter) Convert(record Record) Record

Convert converts the Record into a StackDriver compatible Record

type StackDriverStream

type StackDriverStream struct {
	LogID        string
	Parent       string
	KeyFilename  string
	Key          interface{}
	Converter    Converter
	FilterLevel  Level
	FilterLevels TopicScopeLevels
	// contains filtered or unexported fields
}

StackDriverStream is the Stream that writes to the standard output

implements logger.Streamer

func (*StackDriverStream) Close added in v1.3.0

func (stream *StackDriverStream) Close()

Close closes the stream

implements logger.Streamer

func (*StackDriverStream) FilterLess added in v1.5.0

func (stream *StackDriverStream) FilterLess()

FilterLess tells the stream to filter less

The stream will filter less if it is not already at the lowest level. Which means more log messages will be written to the stream

Example: if the stream is at INFO, it will be filtering at DEBUG

implements logger.FilterModifier

func (*StackDriverStream) FilterMore added in v1.5.0

func (stream *StackDriverStream) FilterMore()

FilterMore tells the stream to filter more

The stream will filter more if it is not already at the highest level. Which means less log messages will be written to the stream

Example: if the stream is at DEBUG, it will be filtering at INFO

implements logger.FilterModifier

func (*StackDriverStream) Flush

func (stream *StackDriverStream) Flush()

Flush flushes the stream (makes sure records are actually written)

implements logger.Streamer

func (*StackDriverStream) SetFilterLevel added in v1.3.0

func (stream *StackDriverStream) SetFilterLevel(level Level)

SetFilterLevel sets the filter level

implements logger.FilterSetter

func (*StackDriverStream) SetFilterLevelForTopic added in v1.5.0

func (stream *StackDriverStream) SetFilterLevelForTopic(level Level, topic string)

SetFilterLevelForTopic sets the filter level for a given topic

implements logger.FilterSetter

func (*StackDriverStream) SetFilterLevelForTopicAndScope added in v1.5.0

func (stream *StackDriverStream) SetFilterLevelForTopicAndScope(level Level, topic, scope string)

SetFilterLevelForTopicAndScope sets the filter level for a given topic

implements logger.FilterSetter

func (*StackDriverStream) SetFilterLevelIfUnset added in v1.4.0

func (stream *StackDriverStream) SetFilterLevelIfUnset(level Level)

SetFilterLevelIfUnset sets the filter level if not set already

implements logger.FilterSetter

func (*StackDriverStream) ShouldWrite

func (stream *StackDriverStream) ShouldWrite(level Level, topic, scope string) bool

ShouldWrite tells if the given level should be written to this stream

implements logger.Streamer

func (*StackDriverStream) String

func (stream *StackDriverStream) String() string

String gets a string version

implements fmt.Stringer

func (*StackDriverStream) Write

func (stream *StackDriverStream) Write(record Record) (err error)

Write writes the given Record

implements logger.Streamer

type StderrStream

type StderrStream struct {
	*json.Encoder
	Converter    Converter
	FilterLevel  Level
	FilterLevels TopicScopeLevels
	// contains filtered or unexported fields
}

StderrStream is the Stream that writes to the standard error

Example
output := CaptureStderr(func() {
	stream := &logger.StderrStream{}

	if err := stream.Write(logger.NewRecord().Set("bello", "banana").Set("だれ", "Me")); err != nil {
		os.Stderr.WriteString(err.Error() + "\n")
	}
	if stream.ShouldWrite(logger.TRACE, "", "") {
		os.Stderr.WriteString("This should not be seen, stream Filter: " + stream.FilterLevel.String() + "\n")
	}
	stream.Flush()
})
fmt.Println(output)
Output:

{"bello":"banana","だれ":"Me"}

func (*StderrStream) Close added in v1.3.0

func (stream *StderrStream) Close()

Close closes the stream

implements logger.Streamer

func (*StderrStream) FilterLess added in v1.5.0

func (stream *StderrStream) FilterLess()

FilterLess tells the stream to filter less

The stream will filter less if it is not already at the lowest level. Which means more log messages will be written to the stream

Example: if the stream is at INFO, it will be filtering at DEBUG

implements logger.FilterModifier

func (*StderrStream) FilterMore added in v1.5.0

func (stream *StderrStream) FilterMore()

FilterMore tells the stream to filter more

The stream will filter more if it is not already at the highest level. Which means less log messages will be written to the stream

Example: if the stream is at DEBUG, it will be filtering at INFO

implements logger.FilterModifier

func (*StderrStream) Flush

func (stream *StderrStream) Flush()

Flush flushes the stream (makes sure records are actually written)

implements logger.Streamer

func (*StderrStream) SetFilterLevel added in v1.3.0

func (stream *StderrStream) SetFilterLevel(level Level)

SetFilterLevel sets the filter level

implements logger.FilterSetter

func (*StderrStream) SetFilterLevelForTopic added in v1.5.0

func (stream *StderrStream) SetFilterLevelForTopic(level Level, topic string)

SetFilterLevelForTopic sets the filter level for a given topic

implements logger.FilterSetter

func (*StderrStream) SetFilterLevelForTopicAndScope added in v1.5.0

func (stream *StderrStream) SetFilterLevelForTopicAndScope(level Level, topic, scope string)

SetFilterLevelForTopicAndScope sets the filter level for a given topic

implements logger.FilterSetter

func (*StderrStream) SetFilterLevelIfUnset added in v1.4.0

func (stream *StderrStream) SetFilterLevelIfUnset(level Level)

SetFilterLevelIfUnset sets the filter level if not set already

implements logger.FilterSetter

func (*StderrStream) ShouldWrite

func (stream *StderrStream) ShouldWrite(level Level, topic, scope string) bool

ShouldWrite tells if the given level should be written to this stream

implements logger.Streamer

func (*StderrStream) String

func (stream *StderrStream) String() string

String gets a string version

implements fmt.Stringer

func (*StderrStream) Write

func (stream *StderrStream) Write(record Record) error

Write writes the given Record

implements logger.Streamer

type StdoutStream

type StdoutStream struct {
	*json.Encoder
	Converter    Converter
	FilterLevel  Level
	FilterLevels TopicScopeLevels
	Unbuffered   bool
	// contains filtered or unexported fields
}

StdoutStream is the Stream that writes to the standard output

Example
os.Setenv("LOG_FLUSHFREQUENCY", "10ms")
defer os.Unsetenv("LOG_FLUSHFREQUENCY")
stream := &logger.StdoutStream{}

if err := stream.Write(logger.NewRecord().Set("bello", "banana").Set("だれ", "Me")); err != nil {
	os.Stdout.WriteString(err.Error() + "\n")
}
if stream.ShouldWrite(logger.TRACE, "", "") {
	os.Stdout.WriteString("This should not be seen, stream Filter: " + stream.FilterLevel.String() + "\n")
}
if err := stream.Write(logger.NewRecord().Set("bello", "banana").Set("level", logger.ERROR)); err != nil {
	os.Stdout.WriteString(err.Error() + "\n")
}
stream.Flush()
time.Sleep(11 * time.Millisecond)
stream.Close()
Output:

{"bello":"banana","だれ":"Me"}
{"bello":"banana","level":50}

func (*StdoutStream) Close added in v1.3.0

func (stream *StdoutStream) Close()

Close closes the stream

implements logger.Streamer

func (*StdoutStream) FilterLess added in v1.5.0

func (stream *StdoutStream) FilterLess()

FilterLess tells the stream to filter less

The stream will filter less if it is not already at the lowest level. Which means more log messages will be written to the stream

Example: if the stream is at INFO, it will be filtering at DEBUG

implements logger.FilterModifier

func (*StdoutStream) FilterMore added in v1.5.0

func (stream *StdoutStream) FilterMore()

FilterMore tells the stream to filter more

The stream will filter more if it is not already at the highest level. Which means less log messages will be written to the stream

Example: if the stream is at DEBUG, it will be filtering at INFO

implements logger.FilterModifier

func (*StdoutStream) Flush

func (stream *StdoutStream) Flush()

Flush flushes the stream (makes sure records are actually written)

implements logger.Streamer

func (*StdoutStream) SetFilterLevel added in v1.3.0

func (stream *StdoutStream) SetFilterLevel(level Level)

SetFilterLevel sets the filter level

implements logger.FilterSetter

func (*StdoutStream) SetFilterLevelForTopic added in v1.5.0

func (stream *StdoutStream) SetFilterLevelForTopic(level Level, topic string)

SetFilterLevelForTopic sets the filter level for a given topic

implements logger.FilterSetter

func (*StdoutStream) SetFilterLevelForTopicAndScope added in v1.5.0

func (stream *StdoutStream) SetFilterLevelForTopicAndScope(level Level, topic, scope string)

SetFilterLevelForTopicAndScope sets the filter level for a given topic

implements logger.FilterSetter

func (*StdoutStream) SetFilterLevelIfUnset added in v1.4.0

func (stream *StdoutStream) SetFilterLevelIfUnset(level Level)

SetFilterLevelIfUnset sets the filter level if not set already

implements logger.FilterSetter

func (*StdoutStream) ShouldWrite

func (stream *StdoutStream) ShouldWrite(level Level, topic, scope string) bool

ShouldWrite tells if the given level should be written to this stream

implements logger.Streamer

func (*StdoutStream) String

func (stream *StdoutStream) String() string

String gets a string version

implements fmt.Stringer

func (*StdoutStream) Write

func (stream *StdoutStream) Write(record Record) error

Write writes the given Record

implements logger.Streamer

type Streamer

type Streamer interface {
	// Write writes the given Record
	Write(record Record) error

	// ShouldWrite tells if the given level should be written to this stream
	ShouldWrite(level Level, topic, scope string) bool

	// Flush flushes the stream (makes sure records are actually written)
	Flush()

	// Close closes the stream
	Close()
}

Streamer is the interface a Logger writes to

func CreateMultiStream added in v1.1.1

func CreateMultiStream(streams ...Streamer) Streamer

CreateMultiStream creates a MultiStream that contains all given Streamer objects

func CreateStreamWithDestination added in v1.1.0

func CreateStreamWithDestination(destinations ...string) Streamer

CreateStreamWithDestination creates a new Streamer from a list of strings

"stdout" will create a StdoutStream

"stderr" will create a StderrStream

"nil", "null" will create a NilStream

"stackdriver" will create a StackDriverStream

"gcp", "googlecloud", "google" will create a StdoutStream, unbuffered, with the StackDriverConverter

"file:///path/to/file" or "path/to/file", "/path/to/file" will create a FileStream on the given location

If more than one string is given, a MultiStream of all Streams from strings is created.

If the environment variable DEBUG is set to 1, all Streams are created unbuffered.

If the list is empty, the environment variable LOG_DESTINATION is used.

type TopicScopeLevels added in v1.5.0

type TopicScopeLevels map[string]Level

TopicScopeLevels stores the level for a given topic,scope pair

func (TopicScopeLevels) Get added in v1.5.0

func (levels TopicScopeLevels) Get(topic, scope string) (level Level, found bool)

Get returns the level for a given topic,scope pair

If the scope is empty, it will return the level for the topic, if found

func (*TopicScopeLevels) Set added in v1.5.0

func (levels *TopicScopeLevels) Set(topic, scope string, level Level)

Set sets the level for a given topic,scope pair

Jump to

Keyboard shortcuts

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