grip

package module
v0.3.8 Latest Latest
Warning

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

Go to latest
Published: Aug 22, 2024 License: Apache-2.0 Imports: 8 Imported by: 42

README

====================================
``grip`` -- A Golang Logging Library
====================================
q
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 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 two 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 data" approach for structured data. With the
  ``message.Base`` implementation, it becomes possible to implement
  ``Composer`` for arbitrary payloads within your application, which may be
  useful for metrics payloads.

Additionally, there are a couple of types for convenience: the ``grip.Logger``
type provides a basic leveled application logging that uses ``Sender``
implementations, and ``message.Builder`` provides a chainable interface for
building log messages.

Goals
~~~~~

- Provide exceptional high-level interfaces for logging and metrics
  collection, with great ergonomics that simplify applications and
  operational stories.

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

- 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.)

Performance is not explicitly a goal, although reasonable performace should be
possible and architectures should always be possible that prevent the logger
from becoming a performance bottleneck in applications.

Features
--------

Global Logger
~~~~~~~~~~~~~

Following the standard library, and other logging packages, the top-level grip
package has a "global" logger, that you can use without any configuration, and
that wraps the standard library's global logging instance. The global
functions in this package have the same signatures and types as the methods of
the ``Logger`` type. The ``SetGlobalLogger`` allows you to override the global
logger: note, however, that this function (and the functions,) are not
thread-safe when used relative to each other, so *only* use
``SetGlobalLogger`` during process configuration and minimize the amount of
logger re-configuration your application does.

For many applications, using and passing a copy of the ``Logger`` you want to
use is preferable.

``Logger``
~~~~~~~~~~

``Logger`` instances simply wrap ``Sender`` instances and most of the
configuration (e.g. levels and threshold) are actually properties of the
messages and the sender. If you want to create a new logger that is a "child"
of an existing logger, consider something like: ::

    // new logger instance wrapping the sender instance from the global logger
    // this is just for the sake of example:
    logger := grip.NewLogger(grip.Sender())

    // create new logger that annotates all messages
    subLogger := grip.NewLogger(send.MakeAnnotating(
	logger.Sender(),
	map[string]any{
		"module": "http",
		"pid":    os.Getpid(),
	}))


Similarly, you could create an annotating logger that sent to two output
targets: ::

    multiLogger := grip.NewLogger(send.MakeMulti(
	grip.Sender(),
	send.NewAnnotating(
	    logger.Sender(),
	    map[string]any{
		    "module": "http",
		    "pid":    os.Getpid(),
	    })
    ))

While this specific example may not be useful (send all messages to the
standard logger output, and also send message to the annotating sender,) but
this kind of configuration can be useful if you want to filter messages of
different types to different outputs, or write messages to a local output
(e.g. standard output, standard error, system journal, etc.) as well as a
remote service (e.g. splunk, sumo logic, etc.).

The ``x`` Packages
~~~~~~~~~~~~~~~~~~

In an effort to reduce the impact for downstream users of additional
dependencies, the ``x`` package includes code that relies on third party
libraries to provide metrics collecting functionality as well as novel
mechanisms for sending messages. It's possible to use senders and loggers, to
propogate messages over email and sump, as well as using grip as an interface
to send logs directly to external aggregation services, such as splunk.

Features implemented here include:

- sending sumologic/splunk messages directly.
- sending messages directly to syslog and/or the systemd journal.
- desktop notifications
- slack messages
- creating jira tickets and commenting on jira issues
- creating github issues and updating github statuses
- sending email messages
- message payloads the capture system metrics:
  - go runtime metrics
  - process-tree metrics
  - single process metrics.

While the core of grip only has dependency on a single library, `fun
<github.com/tychoish/fun>`_, the packages in the ``x`` hierarchy do have
external dependencies. However, the project and go mod files are structured so
that these libraries are managed by different go mod files and can be
versioned separately.

``send.Sender``
~~~~~~~~~~~~~~~

Senders all wrap some sort of output target, which is at some level an
``io.Writer`` or similar kind of interface. The ``send`` package contains a
number of different configurations (standard error, standard output, files,
etc.) as well as 1additional tools for managing output targets, notably:

- converters for ``Sender`` implementations to ``io.Writer``
  instances.

- connections with standard library logging tools.

- buffering and asynchronous senders to reduce backpressure from loggers and
  to batch workloads to (potentially) slower senders.

- multi sender tools, to manage a group of related outputs.

Senders also permit configurable formating hooks and error handling hooks.

``message.Composer``
~~~~~~~~~~~~~~~~~~~~

The ``Composer`` interface is used for all messages, and provides a flexible
(and simple!) interface to create arbitrary messages, which can be
particularly useful for producing structured logging messages from your
application types. Fundamentally, most ``Composer`` implementations should be lazy,
and require minimal runtime resources in the case that the messages aren't
loggable, either as a result of their content (missing or not rising to the
threshold of loggability,) or because of the priority thresholds on the
logger/sender itself.

The message package provides a collection of implementations and features,
including:

- a ``Base`` type which you can compose in your own ``Composer``
  implementations which provides most of the implementation interface and
  holds some basic message metadata (level, timestamp, pid, hostname.) As a
  result implementors only need to implement ``Loggable``, ``String`` and
  ``Raw`` methods.

- a ``GroupMessage`` that provides a bundle of messages, which sender
  implementations can use to batch output. Additionally, the ``Wrap`` and
  ``Unwrap`` methods provide a stack-based approach to grouping messages.

- the ``Builder`` type provides a chainable interface for creating and sending
  log messages, which is integrated into the ``grip.Logger`` interface.

- Conditional or ``When`` messages allow you to embed logging conditions in
  the message, which can simplify the call site for logging messages.

- Error wrappers that convert go error objects into log messages, which are
  non-loggable when the error is nil, with an error-wrapping function that
  makes it possible to annotate messages.

- Logging functions, or producers, which are functions that produce messages,
  or errors and are only called when the message loggable (e.g. for priority
  level thresholds).

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.

- Shims for other popular logging frameworks to facilitate migrations and
  provide grip users to the benefits of existing infrastructure without
  requiring large refactoring.

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. Additionally the ``x`` hierarchy
contains many external integrations that were previously in the main
package. These reorganizations should improve performance and dependency
management and make it easier to stablize releases.

Documentation

Overview

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 Composers to avoid expensive message building operations.

Global Logging Infrastructure

By default (following from the standard library logger and other popular logging pacakges,) grip provides a "default" package level logging instance. This logging instance is accessible via a number of package functions which mirror the interface of the Logger type itself.

During init() this logging instance wraps and uses the underlying writer of the standard library's logger. You can use SetGlobalLogger to configure your own logging (and sender!) infrastructure for default operations, though this function is not thread safe.

In many cases, it might make sense to attach a Logger instance to a context, as Logging is a global concern and your application is likely already using contexts. The WithLogger and Context method make it possible to attach and access your logger. The Context method will *always* return a Logging instance, either the instance attached to a context or the global instance if one is not configured.

Basic Logger

The Logger type provides helpers for sending messages at the following levels:

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

These helpers also include Log* helpers to parameterize the level, as well as the Send method for default logging (or when the level is on the massage itself.)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Alert

func Alert(msg any)

func AlertWhen

func AlertWhen(conditional bool, m any)

func Alertf

func Alertf(msg string, a ...any)

func Alertln

func Alertln(a ...any)

func Build

func Build() *message.Builder

func Convert added in v0.3.2

func Convert(m any) message.Composer

func Critical

func Critical(msg any)

func CriticalWhen

func CriticalWhen(conditional bool, m any)

func Criticalf

func Criticalf(msg string, a ...any)

func Criticalln

func Criticalln(a ...any)

func Debug

func Debug(msg any)

func DebugWhen

func DebugWhen(conditional bool, m any)

func Debugf

func Debugf(msg string, a ...any)

func Debugln

func Debugln(a ...any)

func Emergency

func Emergency(msg any)

func EmergencyFatal

func EmergencyFatal(msg any)

func EmergencyPanic

func EmergencyPanic(msg any)

func EmergencyWhen

func EmergencyWhen(conditional bool, m any)

func Emergencyf

func Emergencyf(msg string, a ...any)

func Emergencyln

func Emergencyln(a ...any)

func Error

func Error(msg any)

func ErrorWhen

func ErrorWhen(conditional bool, m any)

func Errorf

func Errorf(msg string, a ...any)

func Errorln

func Errorln(a ...any)

func HasContextLogger added in v0.2.0

func HasContextLogger(ctx context.Context, name string) bool

HasContextLogger checks the provided context to see if a logger with the given name is attached to the provided context.

func HasLogger added in v0.2.6

func HasLogger(ctx context.Context) bool

HasLogger returns true when the default context logger is attached.

func Info

func Info(msg any)

func InfoWhen

func InfoWhen(conditional bool, message any)

func Infof

func Infof(msg string, a ...any)

func Infoln

func Infoln(a ...any)

func Log

func Log(l level.Priority, msg any)

func LogWhen

func LogWhen(conditional bool, l level.Priority, m any)

func Logf

func Logf(l level.Priority, msg string, a ...any)

func Logln

func Logln(l level.Priority, a ...any)

func Notice

func Notice(msg any)

func NoticeWhen

func NoticeWhen(conditional bool, m any)

func Noticef

func Noticef(msg string, a ...any)

func Noticeln

func Noticeln(a ...any)

func Sender

func Sender() send.Sender

func SetConverter added in v0.3.2

func SetConverter(c message.Converter)

func SetSender added in v0.3.2

func SetSender(s send.Sender)

func Trace

func Trace(msg any)

func TraceWhen

func TraceWhen(conditional bool, m any)

func Tracef

func Tracef(msg string, a ...any)

func Traceln

func Traceln(a ...any)

func Warning

func Warning(msg any)

func WarningWhen

func WarningWhen(conditional bool, m any)

func Warningf

func Warningf(msg string, a ...any)

func Warningln

func Warningln(a ...any)

func WithContextLogger added in v0.2.0

func WithContextLogger(ctx context.Context, name string, logger Logger) context.Context

WithContextLogger attaches a logger with a specific name to the context. Your package should wrap this and use constants for logger names. In most cases, WithLogger to set a default logger, or even just using the standard Context is preferable.

If this logger exists, WitContextLogger is a noop and the existing context is returned directly.

func WithLogger

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

WithLogger attaches a Logger instance to the context.

func WithNewContextLogger added in v0.2.8

func WithNewContextLogger(ctx context.Context, name string, fn func() send.Sender) context.Context

WithNewContextLogger checks if a logger is configured with a specific name in the current context. If this logger exists, WithNewContextLogger is a noop; otherwise, it constructs a logger with the sender produced by the provided function and attaches it to the context returning that context.

The name provided controls the id of the logger in the context, not the name of the logger.

Types

type Logger

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

Logger provides the public interface of the grip Logger.

Package level functions mirror all methods on the Logger type to access a "global" Logger instance in the grip package.

func Clone added in v0.3.2

func Clone() Logger

func Context

func Context(ctx context.Context) Logger

Context resolves a logger from the given context, and if one does not exist (or the context is nil), produces the global Logger instance.

func ContextLogger added in v0.2.8

func ContextLogger(ctx context.Context, name string) Logger

ContextLogger produces a logger stored in the context by a given name. If such a context is not stored the standard/default logger is returned.

func MakeLogger added in v0.3.2

func MakeLogger(s send.Sender, c message.Converter) Logger

MakeLogger constructs a new sender with the specified converter function.

func NewLogger

func NewLogger(s send.Sender) Logger

NewLogger builds a new logging interface from a sender implementation.

func (Logger) Alert

func (g Logger) Alert(m any)

func (Logger) AlertWhen

func (g Logger) AlertWhen(c bool, m any)

func (Logger) Alertf

func (g Logger) Alertf(m string, a ...any)

func (Logger) Alertln

func (g Logger) Alertln(a ...any)

func (Logger) Build

func (g Logger) Build() *message.Builder

func (Logger) Clone added in v0.3.2

func (g Logger) Clone() Logger

Clone creates a new Logger with the same message sender and converter; however they are fully independent loggers.

func (Logger) Convert added in v0.3.2

func (g Logger) Convert(m any) message.Composer

func (Logger) Critical

func (g Logger) Critical(m any)

func (Logger) CriticalWhen

func (g Logger) CriticalWhen(c bool, m any)

func (Logger) Criticalf

func (g Logger) Criticalf(m string, a ...any)

func (Logger) Criticalln

func (g Logger) Criticalln(a ...any)

func (Logger) Debug

func (g Logger) Debug(m any)

func (Logger) DebugWhen

func (g Logger) DebugWhen(c bool, m any)

func (Logger) Debugf

func (g Logger) Debugf(m string, a ...any)

func (Logger) Debugln

func (g Logger) Debugln(a ...any)

func (Logger) Emergency

func (g Logger) Emergency(m any)

func (Logger) EmergencyFatal

func (g Logger) EmergencyFatal(m any)

func (Logger) EmergencyPanic

func (g Logger) EmergencyPanic(m any)

func (Logger) EmergencyWhen

func (g Logger) EmergencyWhen(c bool, m any)

func (Logger) Emergencyf

func (g Logger) Emergencyf(m string, a ...any)

func (Logger) Emergencyln

func (g Logger) Emergencyln(a ...any)

func (Logger) Error

func (g Logger) Error(m any)

func (Logger) ErrorWhen

func (g Logger) ErrorWhen(c bool, m any)

func (Logger) Errorf

func (g Logger) Errorf(m string, a ...any)

func (Logger) Errorln

func (g Logger) Errorln(a ...any)

func (Logger) Info

func (g Logger) Info(m any)

func (Logger) InfoWhen

func (g Logger) InfoWhen(c bool, m any)

func (Logger) Infof

func (g Logger) Infof(m string, a ...any)

func (Logger) Infoln

func (g Logger) Infoln(a ...any)

func (Logger) Log

func (g Logger) Log(l level.Priority, m any)

func (Logger) LogWhen

func (g Logger) LogWhen(c bool, l level.Priority, m any)

func (Logger) Logf

func (g Logger) Logf(l level.Priority, msg string, a ...any)

func (Logger) Logln

func (g Logger) Logln(l level.Priority, a ...any)

func (Logger) Notice

func (g Logger) Notice(m any)

func (Logger) NoticeWhen

func (g Logger) NoticeWhen(c bool, m any)

func (Logger) Noticef

func (g Logger) Noticef(m string, a ...any)

func (Logger) Noticeln

func (g Logger) Noticeln(a ...any)

func (Logger) Sender

func (g Logger) Sender() send.Sender

func (Logger) SetConverter added in v0.3.2

func (g Logger) SetConverter(m message.Converter)

func (Logger) SetSender added in v0.3.2

func (g Logger) SetSender(s send.Sender)

func (Logger) Trace

func (g Logger) Trace(m any)

func (Logger) TraceWhen

func (g Logger) TraceWhen(c bool, m any)

func (Logger) Tracef

func (g Logger) Tracef(m string, a ...any)

func (Logger) Traceln

func (g Logger) Traceln(a ...any)

func (Logger) Warning

func (g Logger) Warning(m any)

func (Logger) WarningWhen

func (g Logger) WarningWhen(c bool, m any)

func (Logger) Warningf

func (g Logger) Warningf(m string, a ...any)

func (Logger) Warningln

func (g Logger) Warningln(a ...any)

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 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 Sender
Package series provides tools for collecting and aggregating timeseries events as part of the logging infrastructure.
Package series provides tools for collecting and aggregating timeseries events as part of the logging infrastructure.
x
desktop Module
email Module
github Module
graphite Module
jira Module
metrics Module
slack Module
splunk Module
sumologic Module
system Module
telegram Module
twitter Module
xmpp Module
zap Module
zerolog Module

Jump to

Keyboard shortcuts

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