grip

package module
v0.0.0-...-8f46c05 Latest Latest
Warning

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

Go to latest
Published: Feb 8, 2021 License: Apache-2.0 Imports: 12 Imported by: 0

README

====================================
``grip`` -- A Golang Logging Library
====================================

Overview
--------

Grip is a high level logging and message system for providing a single
solution for structured logging, notification, and message sending.

#. Provide a common logging interface with support for multiple
   output/messaging backends.

#. Provides some simple methods for errors, particularly when
   you want to accumulate and then return errors.

#. Provides tools for collecting structured logging information.

*You just get a grip, folks.*

Use
---

``grip`` declares its dependencies via go modules. The top level ``grip``
package provides global logging functions that use a global logging
interface. You can also use the logging package to produce logger objects with
the same interface to avoid relying on a global logger.

Grip is available under the terms of the Apache License (v2.)

Design
------

Interface
~~~~~~~~~

Grip provides three main interfaces:

- The ``send.Sender`` interfaces which implements sending messages to various
  output sources. Provides sending as well as the ability to support error
  handling, and message formating support.

- The ``message.Composer`` which wraps messages providing both "string"
  formating as well as a "raw" serialized approach.

- The ``grip.Journaler`` interface provides a high level logging interface,
  and is mirrored in the package's public interface as a defult logger.

Goals
~~~~~

- Provide robust high-level abstractions for applications to manage messaging,
  logging, and metrics collection.

- Integrate with other logging systems (e.g. standard library logging,
  standard output of subprocesses, other libraries, etc.)

- Minimize operational complexity and dependencies for having robust logging
  (e.g. make it possible to log effectively from within a program without
  requiring log relays or collection agents.)

Development
-----------

Future Work
~~~~~~~~~~~

Grip is relatively stable, though there are additional features and areas of
development:

- structured metrics collection. This involves adding a new interface as a
  superset of the Composer interface, and providing ways of filtering these
  messages out to provide better tools for collecting diagnostic data from
  applications.

- additional Sender implementations to support additional output formats and
  needs.

- better integration with recent development in error wrapping in the go
  standard library.

If you encounter a problem please feel free to create a github issue or open a
pull request.

History
~~~~~~~

Grip originated as a personal project, and became the default logging and
messaging tool for `Evergreen <https://github.com/evergreen-ci/>`_ and related
projects at MongoDB's release infrastructure developer productivity
organization.

This fork removes some legacy components and drops support older versions of
Golang, thereby adding support for modules.

Features
--------

Output Formats
~~~~~~~~~~~~~~

Grip supports a number of different logging output backends:

- systemd's journal (linux-only)
- syslog (unix-only)
- writing messages to standard output.
- writing messages to a file.
- sending messages to a slack's channel
- sending messages to a user via XMPP (jabber.)
- creating or commeting on a jira ticket
- creating or commenting on a github issue
- sending a desktop notification
- sending an email.
- sending log output.
- create a tweet.

See the documentation of the `Sender interface
<https://godoc.org/github.com/tychoish/grip/send#Sender>`_ for more
information on building new senders. The `base sender implementation
<https://godoc.org/github.com/tychoish/grip/send#Base>`_ implements most of
the interface, except for the Send method.

In addition to a collection of useful output implementations, grip also
provides tools for managing output including:

- the `multi sender
  <https://godoc.org/github.com/cdr/grip/send#NewConfiguredMultiSender>`_
  for combining multiple senders to "tee" the output together,

- the `buffering sender
  <https://godoc.org/github.com/cdr/grip/send#NewBufferedSender>`_ for
  wrapping a sender with a buffer that will batch messages after reciving a
  specified number of messages, or on a specific interval.

- the `io.Writer
  <https://godoc.org/github.com/cdr/grip/send#WriterSender>`_ to convert a
  sender implementation to an io.Writer, to be able to use grip fundamentals
  in situations that call for ``io.Writers`` (e.g. the output of
  subprocesses,.

- the `WrapWriter
  <https://godoc.org/github.com/cdr/grip/send#WrapWriter>`_ to use an
  arbitrary ``io.Writer`` interface as a sender.

Logging
~~~~~~~

Provides a fully featured level-based logging system with multiple
backends (e.g. send.Sender). By default logging messages are printed
to standard output, but backends exists for many possible targets. The
interface for logging is provided by the Journaler interface.

By default ``grip.std`` defines a standard global  instances
that you can use with a set of ``grip.<Level>`` functions, or you can
create your own ``Journaler`` instance and embed it in your own
structures and packages.

Defined helpers exist for the following levels/actions:

- ``Debug``
- ``Info``
- ``Notice``
- ``Warning``
- ``Error``
- ``Critical``
- ``Alert``
- ``Emergency``
- ``EmergencyPanic``
- ``EmergencyFatal``

Helpers ending with ``Panic`` call ``panic()`` after logging the message
message, and helpers ending with ``Fatal`` call ``os.Exit(1)`` after logging
the message. These are primarily for handling errors in your main() function
and should be used sparingly, if at all, elsewhere.

Sender instances have a notion of "default" log levels and thresholds, which
provide the basis for verbosity control and sane default behavior. The default
level defines the priority/level of any message with an invalid priority
specified. The threshold level, defines the minimum priority or level that
``grip`` sends to the logging system. It's not possible to suppress the
highest log level, ``Emergency`` messages will always log.

``Journaler`` objects have additional methods (also
available as functions in the ``grip`` package to manage and configure the
instance.

Error Collector for "Continue on Error" Semantics
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you want to do something other than ignore or simply log errors, but don't
want to abort after an error, the `Catcher Interface
<https://godoc.org/github.com/cdr/grip#Catcher>`_ provides a threadsafe
way of aggregating errors. Consider: ::

   func doStuff(dirname string) (error) {
	   files, err := ioutil.ReadDir(dirname)
	   if err != nil {
		   // should abort here because we shouldn't continue.
		   return err
	   }

	   catcher := grip.NewCatcher()t
	   for _, f := range files {
	       err = doStuffToFile(f.Name())
	       catcher.Add(err)
	   }

	   return catcher.Resolve()
   }

Grip provides several error catchers (which are independent of the logging
infrastructure.) They are Basic, Simple, and Extended. These variants differ
on how the collected errors are represented in the final error object. Basic
uses the ``Error()`` method of component errors, Simple users
``fmt.Sprintf("%s", err)`` and Extended users ``fmt.Sprintf("%+v",
err)``. There are also Timestamp methods that annotate all errors with a
timestamp of when the error was collected to improve debugability in longer
running asynchronous contexts: these collectors rely on ``WrapErrorTime`` to
annotate the timestamp, which may be useful in other contexts.

Conditional Logging
~~~~~~~~~~~~~~~~~~~

``grip`` incldues support for conditional logging, so that you can
only log a message in certain situations, by adding a Boolean argument
to the logging call. Use this to implement "log sometimes" messages to
minimize verbosity without complicating the calling code around the
logging, or simplify logging call sites. These methods have a ``<Level>When```
format.

This is syntactic sugar around the `message.When
<https://godoc.org/github.com/cdr/grip/message#When>`_ message type, but
can reduce a lot of nesting and call-site complexity.

Composed Logging
~~~~~~~~~~~~~~~~

If the production of the log message is resource intensive or
complicated, you may wish to use a "composed logging," which delays
the generation of the log message from the logging call site to the
message propagation, to avoid generating the log message unless
necessary. Rather than passing the log message as a string, pass the
logging function an instance of a type that implements the
``Composer`` interface.

Grip uses composers internally, but you can pass composers directly to
any of the basic logging method (e.g. ``Info()``, ``Debug()``) for
composed logging.

Grip includes a number of message types, including those that collect
system information, process information, stacktraces, or simple
user-specified structured information.

Documentation

Overview

Package grip provides a flexible logging package for basic Go programs. Drawing inspiration from Go and Python's standard library logging, as well as systemd's journal service, and other logging systems, Grip provides a number of very powerful logging abstractions in one high-level package.

Logging Instances

The central type of the grip package is the Journaler type, instances of which provide distinct log capturing system. For ease, following from the Go standard library, the grip package provides parallel public methods that use an internal "standard" Jouernaler instance in the grip package, which has some defaults configured and may be sufficient for many use cases.

Output

The send.Sender interface provides a way of changing the logging backend, and the send package provides a number of alternate implementations of logging systems, including: systemd's journal, logging to standard output, logging to a file, and generic syslog support.

Messages

The message.Composer interface is the representation of all messages. They are implemented to provide a raw structured form as well as a string representation for more conentional logging output. Furthermore they are intended to be easy to produce, and defer more expensive processing until they're being logged, to prevent expensive operations producing messages that are below threshold.

Basic Logging

Loging helpers exist for the following levels:

Emergency + (fatal/panic)
Alert
Critical
Error
Warning
Notice
Info
Debug

These methods accept both strings (message content,) or types that implement the message.MessageComposer interface. Composer types make it possible to delay generating a message unless the logger is over the logging threshold. Use this to avoid expensive serialization operations for suppressed logging operations.

All levels also have additional methods with `ln` and `f` appended to the end of the method name which allow Println() and Printf() style functionality. You must pass printf/println-style arguments to these methods.

Conditional Logging

The Conditional logging methods take two arguments, a Boolean, and a message argument. Messages can be strings, objects that implement the MessageComposer interface, or errors. If condition boolean is true, the threshold level is met, and the message to log is not an empty string, then it logs the resolved message.

Use conditional logging methods to potentially suppress log messages based on situations orthogonal to log level, with "log sometimes" or "log rarely" semantics. Combine with MessageComposers to to avoid expensive message building operations.

Error Catcher

The MutiCatcher type makes it possible to collect from a group of operations and then aggregate them as a single error.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Alert

func Alert(msg interface{})

func AlertWhen

func AlertWhen(conditional bool, m interface{})

func Alertf

func Alertf(msg string, a ...interface{})

func Alertln

func Alertln(a ...interface{})

func Critical

func Critical(msg interface{})

func CriticalWhen

func CriticalWhen(conditional bool, m interface{})

func Criticalf

func Criticalf(msg string, a ...interface{})

func Criticalln

func Criticalln(a ...interface{})

func Debug

func Debug(msg interface{})

func DebugWhen

func DebugWhen(conditional bool, m interface{})

func Debugf

func Debugf(msg string, a ...interface{})

func Debugln

func Debugln(a ...interface{})

func Emergency

func Emergency(msg interface{})

func EmergencyFatal

func EmergencyFatal(msg interface{})

func EmergencyPanic

func EmergencyPanic(msg interface{})

func EmergencyWhen

func EmergencyWhen(conditional bool, m interface{})

func Emergencyf

func Emergencyf(msg string, a ...interface{})

func Emergencyln

func Emergencyln(a ...interface{})

func Error

func Error(msg interface{})

func ErrorTimeFinder

func ErrorTimeFinder(err error) (time.Time, bool)

ErrorTimeFinder unwraps a timestamp annotated error if possible and is capable of finding a timestamp in an error that has been annotated using pkg/errors.

func ErrorWhen

func ErrorWhen(conditional bool, m interface{})

func Errorf

func Errorf(msg string, a ...interface{})

func Errorln

func Errorln(a ...interface{})

func GetSender

func GetSender() send.Sender

GetSender returns the current Journaler's sender instance. Use this in combination with SetSender to have multiple Journaler instances backed by the same send.Sender instance.

func Info

func Info(msg interface{})

func InfoWhen

func InfoWhen(conditional bool, message interface{})

func Infof

func Infof(msg string, a ...interface{})

func Infoln

func Infoln(a ...interface{})

func Log

func Log(l level.Priority, msg interface{})

func LogWhen

func LogWhen(conditional bool, l level.Priority, m interface{})

func Logf

func Logf(l level.Priority, msg string, a ...interface{})

func Logln

func Logln(l level.Priority, a ...interface{})

func MakeCatcherErrorHandler

func MakeCatcherErrorHandler(catcher Catcher, fallback send.Sender) send.ErrorHandler

MakeCatcherErrorHandler produces an error handler useful for collecting errors from a sender using the supplied error catcher. At the very least, consider using a catcher that has a specified maxsize, and possibly timestamp annotating catcher as well. If you

func MakeStandardLogger

func MakeStandardLogger(p level.Priority) *log.Logger

MakeStandardLogger constructs a standard library logging instance that logs all messages to the global grip logging instance.

func Name

func Name() string

Name of the logger instance

func Notice

func Notice(msg interface{})

func NoticeWhen

func NoticeWhen(conditional bool, m interface{})

func Noticef

func Noticef(msg string, a ...interface{})

func Noticeln

func Noticeln(a ...interface{})

func SetDefaultJournaler

func SetDefaultJournaler(l Journaler)

SetDefaultJournaler allows you to override the standard logger, that is used by calls in the grip package. This call is not thread safe relative to other logging calls, or the GetDefaultJournaler call, although all journaling methods are safe: as a result be sure to only call this method during package and process initialization.

func SetDefaultStandardLogger

func SetDefaultStandardLogger(p level.Priority)

SetDefaultStandardLogger set's the standard library's global logging instance to use grip's global logger at the specified level.

func SetLevel

func SetLevel(info send.LevelInfo) error

SetLevel sets the default and threshold level in the underlying sender.

func SetName

func SetName(name string)

SetName declare a name string for the logger, including in the logging message. Typically this is included on the output of the command.

func SetSender

func SetSender(s send.Sender) error

SetSender swaps send.Sender() implementations in a logging instance. Calls the Close() method on the existing instance before changing the implementation for the current instance.

func Warning

func Warning(msg interface{})

func WarningWhen

func WarningWhen(conditional bool, m interface{})

func Warningf

func Warningf(msg string, a ...interface{})

func Warningln

func Warningln(a ...interface{})

func WrapErrorTime

func WrapErrorTime(err error) error

WrapErrorTime annotates an error with the timestamp. The underlying concrete object implements message.Composer as well as error.

func WrapErrorTimeMessage

func WrapErrorTimeMessage(err error, m string) error

WrapErrorTimeMessage annotates an error with the timestamp and a string form. The underlying concrete object implements message.Composer as well as error.

func WrapErrorTimeMessagef

func WrapErrorTimeMessagef(err error, m string, args ...interface{}) error

WrapErrorTimeMessagef annotates an error with a timestamp and a string formated message, like fmt.Sprintf or fmt.Errorf. The underlying concrete object implements message.Composer as well as error.

Types

type Catcher

type Catcher interface {
	Add(error)
	AddWhen(bool, error)
	Extend([]error)
	ExtendWhen(bool, []error)
	Len() int
	HasErrors() bool
	String() string
	Resolve() error
	Errors() []error

	New(string)
	NewWhen(bool, string)
	Errorf(string, ...interface{})
	ErrorfWhen(bool, string, ...interface{})

	Wrap(error, string)
	Wrapf(error, string, ...interface{})

	Check(CheckFunction)
	CheckExtend([]CheckFunction)
	CheckWhen(bool, CheckFunction)
}

Catcher is an interface for an error collector for use when implementing continue-on-error semantics in concurrent operations. There are three different Catcher implementations provided by this package that differ *only* in terms of the string format returned by String() (and also the format of the error returned by Resolve().)

If you do not use github.com/pkg/errors to attach errors, the implementations are usually functionally equivalent. The Extended variant formats the errors using the "%+v" (which returns a full stack trace with pkg/errors,) the Simple variant uses %s (which includes all the wrapped context,) and the// basic catcher calls error.Error() (which should be equvalent to %s for most error implementations.)

func MakeBasicCatcher

func MakeBasicCatcher(size int) Catcher

MakeBasicCatcher collects error messages and formats them using a new-line separated string of the output of error.Error(). If the size greater than 0 the catcher will never collect more than the specified number of errors, discarding earlier messages when adding new messages.

func MakeExtendedCatcher

func MakeExtendedCatcher(size int) Catcher

MakeExtendedCatcher collects error messages and formats them using a new-line separated string of the extended string format of the error message (e.g. %+v). If the size greater than 0 the catcher will never collect more than the specified number of errors, discarding earlier messages when adding new messages.

func MakeExtendedTimestampCatcher

func MakeExtendedTimestampCatcher(size int) Catcher

MakeTimestampCatcher constructs a Catcher instance that annotates all errors with their collection time and also captures stacks when possible. If the size greater than 0 the catcher will never collect more than the specified number of errors, discarding earlier messages when adding new messages.

func MakeSimpleCatcher

func MakeSimpleCatcher(size int) Catcher

MakeSimpleCatcher collects error messages and formats them using a new-line separated string of the string format of the error message (e.g. %s). If the size greater than 0 the catcher will never collect more than the specified number of errors, discarding earlier messages when adding new messages.

func MakeTimestampCatcher

func MakeTimestampCatcher(size int) Catcher

MakeTimestampCatcher constructs a Catcher instance that annotates all errors with their collection time; however, if the size is greater than 0 the catcher will never collect more than the specified number of errors, discarding earlier messages when adding new messages.

func NewBasicCatcher

func NewBasicCatcher() Catcher

NewBasicCatcher collects error messages and formats them using a new-line separated string of the output of error.Error()

func NewCatcher

func NewCatcher() Catcher

NewCatcher returns a Catcher instance that you can use to capture error messages and aggregate the errors. For consistency with earlier versions NewCatcher is the same as NewExtendedCatcher()

DEPRECATED: use one of the other catcher implementations. See the documentation for the Catcher interface for most implementations.

func NewExtendedCatcher

func NewExtendedCatcher() Catcher

NewExtendedCatcher collects error messages and formats them using a new-line separated string of the extended string format of the error message (e.g. %+v).

func NewExtendedTimestampCatcher

func NewExtendedTimestampCatcher() Catcher

NewExtendedTimestampCatcher adds long-form annotation to the aggregated error message (e.g. including stacks, when possible.)

func NewSimpleCatcher

func NewSimpleCatcher() Catcher

NewSimpleCatcher collects error messages and formats them using a new-line separated string of the string format of the error message (e.g. %s).

func NewTimestampCatcher

func NewTimestampCatcher() Catcher

NewTimestampCatcher produces a Catcher instance that reports the short form of all constituent errors and annotates those errors with a timestamp to reflect when the error was collected.

type CheckFunction

type CheckFunction func() error

CheckFunction are functions which take no arguments and return an error.

type Journaler

type Journaler interface {
	Name() string
	SetName(string)

	// Methods to access the underlying message sending backend.
	GetSender() send.Sender
	SetSender(send.Sender) error
	SetLevel(send.LevelInfo) error

	// Send allows you to push a composer which stores its own
	// priorty (or uses the sender's default priority).
	Send(interface{})

	// Specify a log level as an argument rather than a method
	// name.
	Log(level.Priority, interface{})
	Logf(level.Priority, string, ...interface{})
	Logln(level.Priority, ...interface{})
	LogWhen(bool, level.Priority, interface{})

	// Emergency methods have "panic" and "fatal" variants that
	// call panic or os.Exit(1). It is impossible for "Emergency"
	// to be below threshold, however, if the message isn't
	// loggable (e.g. error is nil, or message is empty,) these
	// methods will not panic/error.
	EmergencyFatal(interface{})
	EmergencyPanic(interface{})

	// For each level, in addition to a basic logger that takes
	// strings and message.Composer objects (and tries to do its best
	// with everythingelse.) there are println and printf
	// loggers. Each Level also has "When" variants that only log
	// if the passed condition are true.
	Emergency(interface{})
	Emergencyf(string, ...interface{})
	Emergencyln(...interface{})
	EmergencyWhen(bool, interface{})

	Alert(interface{})
	Alertf(string, ...interface{})
	Alertln(...interface{})
	AlertWhen(bool, interface{})

	Critical(interface{})
	Criticalf(string, ...interface{})
	Criticalln(...interface{})
	CriticalWhen(bool, interface{})

	Error(interface{})
	Errorf(string, ...interface{})
	Errorln(...interface{})
	ErrorWhen(bool, interface{})

	Warning(interface{})
	Warningf(string, ...interface{})
	Warningln(...interface{})
	WarningWhen(bool, interface{})

	Notice(interface{})
	Noticef(string, ...interface{})
	Noticeln(...interface{})
	NoticeWhen(bool, interface{})

	Info(interface{})
	Infof(string, ...interface{})
	Infoln(...interface{})
	InfoWhen(bool, interface{})

	Debug(interface{})
	Debugf(string, ...interface{})
	Debugln(...interface{})
	DebugWhen(bool, interface{})
}

Journaler describes the public interface of the the Grip interface. Used to enforce consistency between the grip and logging packages.

func GetDefaultJournaler

func GetDefaultJournaler() Journaler

GetDefaultJournaler returns the default journal instance used by this library. This call is not thread safe relative to other logging calls, or SetDefaultJournaler call, although all journaling methods are safe.

func NewJournaler

func NewJournaler(name string) Journaler

NewJournaler creates a new Journaler instance. The Sender method is a non-operational bootstrap method that stores default and threshold types, as needed. You must use SetSender() or the UseSystemdLogger(), UseNativeLogger(), or UseFileLogger() methods to configure the backend.

Directories

Path Synopsis
Package level defines a Priority type and some conversion methods for a 7-tiered logging level schema, which mirror syslog and system's logging levels.
Package level defines a Priority type and some conversion methods for a 7-tiered logging level schema, which mirror syslog and system's logging levels.
Package logging provides the primary implementation of the Journaler interface (which is cloned in public functions in the grip interface itself.) Basic Logging Loging helpers exist for the following levels: Emergency + (fatal/panic) Alert + (fatal/panic) Critical + (fatal/panic) Error + (fatal/panic) Warning Notice Info Debug
Package logging provides the primary implementation of the Journaler interface (which is cloned in public functions in the grip interface itself.) Basic Logging Loging helpers exist for the following levels: Emergency + (fatal/panic) Alert + (fatal/panic) Critical + (fatal/panic) Error + (fatal/panic) Warning Notice Info Debug
package message defines the Composer interface and a handful of implementations which represent the structure for messages produced by grip.
package message defines the Composer interface and a handful of implementations which represent the structure for messages produced by grip.
Package recovery provides a number of grip-integrated panic handling tools for capturing and responding to panics using grip loggers.
Package recovery provides a number of grip-integrated panic handling tools for capturing and responding to panics using grip loggers.
Call Site Sender Call site loggers provide a way to record the line number and file name where the logging call was made, which is particularly useful in tracing down log messages.
Call Site Sender Call site loggers provide a way to record the line number and file name where the logging call was made, which is particularly useful in tracing down log messages.

Jump to

Keyboard shortcuts

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