Documentation ¶
Overview ¶
Package scribe represents a functional abstraction for unifying loggers. It's much more than a shim-like façade (à la SLF4J), in that it does not have to transform from one API to another. Instead, Scribe uses function pointers to expose a standard printf-style API to the application where this is possible (where the underlying logger provides a printf-style interface out of the box). In that sense, Scribe is more of a mechanism for standardising and organising logger implementations. Where the underlying logger does not expose a printf-style contract, Scribe can be used with a shim binding.
Scribe supports log enrichment, allowing the user to provide additional contextual metadata. (This is called a Scene.) It achieves the same goal as a traditional façade, without creating a layer of indirection and increasing the depth of the call stack. Therefore, the original call site information is preserved. (By contrast, a naive façade/adapter/shim injects itself into the call stack, reporting the wrong file name and line number to the logger.)
Scribe is thread-safe; multiple goroutines may use the same instance.
Index ¶
- Constants
- Variables
- func LevelName(level Level) (string, error)
- func LevelNameAbbreviated(level Level) (string, error)
- func Nop(_ string, _ ...interface{})
- func Space(buffer *bytes.Buffer)
- func WriteScene(buffer *bytes.Buffer, scene Scene)
- type Assertion
- type DynamicAssertion
- type Entries
- type Entry
- type Fields
- type Hook
- type Level
- type LevelSpec
- type Logger
- type LoggerFactories
- type LoggerFactory
- type MockScribe
- type Predicate
- type Scene
- type ScenePredicate
- type Scribe
- type StdLogAPI
Constants ¶
const DefaultEnabledLevel = Trace
DefaultEnabledLevel specifies the level of logging which is enabled by default. This includes all levels having higher ordinals.
Variables ¶
var Levels = map[Level]LevelSpec{ All: {All, "All", "ALL"}, Trace: {Trace, "Trace", "TRC"}, Debug: {Debug, "Debug", "DBG"}, Info: {Info, "Info", "INF"}, Warn: {Warn, "Warn", "WRN"}, Error: {Error, "Error", "ERR"}, Off: {Off, "Off", "WRN"}, }
Levels lists built-in levels (including the two symbolic ones, All and Off), mapping them to their descriptions.
Custom levels can be defined (provided they conform to the Level data type); the knowledge of such levels will remain within the confines of the user application.
Functions ¶
func LevelName ¶
LevelName gets the name of the given level, if one is known. An error is returned if the level is not among the known Levels map. In the error case, the name will contain its ordinal.
func LevelNameAbbreviated ¶
LevelNameAbbreviated gives the abbreviated name for a given level. An error is returned if the level is not among the known Levels map. In the error case, the name will contain its ordinal.
func Space ¶
Space appends a whitespace character to the given buffer if the latter is non-empty. This function is used to separate fields.
func WriteScene ¶
WriteScene is a utility for compactly writing scene contents to an output writer.
Types ¶
type Assertion ¶
Assertion is a verification of Entries that returns a nil string if the assertion passes, or a string describing the nature of the failure otherwise. MockScribe will append the stack trace behind the scenes.
func CountAtLeast ¶
CountAtLeast ensures that there is a minimum number of entries.
func CountAtMost ¶
CountAtMost ensures that there is a maximum number of entries.
type DynamicAssertion ¶
type DynamicAssertion struct {
// contains filtered or unexported fields
}
DynamicAssertion permits the testing of captures housed by the ScribeMock, rather than the Entries snapshot. Owing to this, assertions created from a DynamicAssertion are evaluated against a refreshed Entries snapshot. This is ideal for performing time-based assertions, where a condition might be satisfied after some time (when the application eventually logs the missing entry).
func (DynamicAssertion) Having ¶
func (s DynamicAssertion) Having(p Predicate) DynamicAssertion
Having applies a predicate to the DynamicAssertion.
type Entries ¶
type Entries interface { Having(p Predicate) Entries List() []Entry Length() int Assert(t check.Tester, a Assertion) Entries }
Entries is an immutable snapshot of captured log calls.
type Entry ¶
Entry is a single, captured log entry.
func (Entry) FormattedMessage ¶
FormattedMessage returns the application of fmt.Sprintf to Entry.Format and Entry.Args.
type Fields ¶
type Fields map[string]interface{}
Fields is a free-form set of attributes that can be captured as part of a Scene, supporting log enrichment and structured logging.
type Hook ¶
Hook is a function that can inspect log arguments before they are passed to the underlying logger, and potentially modify these arguments.
The supplied log level cannot be modified, as log factories are provided on a per log level basis. The other arguments can be modified by assignment through dereferencing:
*scene = Scene{...} *format = "new format with %s %s" *args = []interface{}{"new", "args"}
func AppendScene ¶
func AppendScene() Hook
AppendScene is a hook that appends the contents of the captured scene after the formatted log message.
type Level ¶
type Level uint8
Level of logging. The lowest ordinal corresponds to the most fine-grained level. By convention, a level subsumes all levels above it, meaning that if a level L is enabled, then any level M, where M > L, is also enabled.
const ( // All is a symbolic value for the lowest possible level. It does not actually get logged, but is useful for // addressing all levels above it (for example, to enable all logging). All Level = 0 // Trace is the most fine-grained level that actually gets logged. Trace Level = 10 // Debug level. Debug Level = 20 // Info level. Info Level = 30 // Warn level Warn Level = 40 // Error is the most coarse-grained level that actually gets logged. Error Level = 50 // Off is a symbolic value for the highest possible level. It does not actually get logged, but is useful for // addressing all levels below it (for example, to disable all logging). Off Level = 200 )
We allocate ordinals by hand rather than use a iota to ensure that we can add more levels in the future without breaking compatibility. In addition, the user may specify their own log level, provided it conforms to the Level data type.
type LevelSpec ¶
LevelSpec describes a log level.
func ParseLevelName ¶
ParseLevelName locates a LevelSpec for a given name string, returning an error if none could be matched.
type Logger ¶
type Logger func(format string, args ...interface{})
Logger is a single-use function for logging output. It is meant to be used at the point where the application is ready to submit the log message. This is not a constraint as such; it allows for the capture of contextual scene metadata.
Implementations may reuse a single instance of a logger function if they don't care about scene capture or deal with race-prone state.
type LoggerFactories ¶
type LoggerFactories map[Level]LoggerFactory
LoggerFactories is used to configure Scribe, specifying a LogFactory for each supported level.
func BindFmt ¶
func BindFmt() LoggerFactories
BindFmt creates a binding for the logger used by fmt. There are several issues with fmt:
- It's Printf has return values, making it incompatible with Scribe.
- It does not add a newline.
As a result of these limitations, this binding is implemented as a shim, rather than a function pointer. In practice, this is of no consequence, as fmt does not care about caller site information.
func BindLogPrintf ¶
func BindLogPrintf(logger ...*log.Logger) LoggerFactories
BindLogPrintf creates a pass-through binding for log.Printf(). An optional Logger instance can be specified; if omitted, the standard logger will be used.
func ShimFacs ¶
func ShimFacs(facs LoggerFactories, hook Hook) LoggerFactories
ShimFacs applies a shim to all factories in facs, using the given hook, returning an equivalent map of shimmed factories.
func StandardBinding ¶
func StandardBinding() LoggerFactories
StandardBinding creates a shim-based binding for log.Printf(), appending scene information. This should be the default binding used by applications that have not yet adopted a logging framework.
type LoggerFactory ¶
LoggerFactory specifies the behaviour for constructing a logger instance. The log factory is called upon each time a logger is requested — every time an application needs to log something.
func Fac ¶
func Fac(logger Logger) LoggerFactory
Fac wraps a given reusable logger function in a factory. Useful for simple loggers that don't care about scene metadata, and willing to recycle the same logging function.
func ShimFac ¶
func ShimFac(fac LoggerFactory, hook Hook) LoggerFactory
ShimFac applies a shim to fac, using the given hook. The result is a LoggerFactory that applies the hook before invoking the shimmed logger.
Note: shimming is an intrusive process that changes the call site from the perspective of the underlying logger. Shimming and hooks within Scribe should only be used for debugging, or to enhance loggers that don't natively support features such as structured logging. Where possible, use the native hooks provided by your chosen logging framework.
type MockScribe ¶
type MockScribe interface { Factories() LoggerFactories Reset() Entries() Entries ContainsEntries() DynamicAssertion }
MockScribe provides a facility for mocking a Scribe, capturing log calls for subsequent inspection, filtering and assertions. This implementation is thread-safe.
func NewMock ¶
func NewMock() MockScribe
NewMock creates a new MockScribe. The returning instance cannot be used to log directly — only to inspect and assert captures. To configure a Scribe to use the mocks for subsequent logging:
mock := scribe.NewMock() scribe := scribe.New(mock.Factories())
type Predicate ¶
Predicate is a condition evaluated against a given entry, returning true if the underlying condition has been satisfied.
func ASceneWith ¶
func ASceneWith(p ScenePredicate) Predicate
ASceneWith returns a conventional (Entry) predicate that satisfies the given ScenePredicate.
func Anything ¶
func Anything() Predicate
Anything is a predicate that matches any entry. It is useful for taking a copy of Entries:
exactCopy := original.Having(scribe.Anything())
func MessageContaining ¶
MessageContaining matches entries where the formatted message contains the given substr.
func MessageEqual ¶
MessageEqual matches entries where the formatted message exactly matches the expected string.
type Scene ¶
Scene captures additional metadata from the call site that is forwarded to the logger. This is used to facilitate structured logging, pass contexts onto loggers, communicate application errors, and so forth.
type ScenePredicate ¶
ScenePredicate is a refinement of the predicate concept, applying to the Scene field of an Entry (as opposed to the entire Entry struct).
func AField ¶
func AField(name string, value interface{}) ScenePredicate
AField is satisfied if the scene contains a field with the given name-value pair.
func AFieldNamed ¶
func AFieldNamed(name string) ScenePredicate
AFieldNamed is satisfied if the scene contains a field with the given name.
func Content ¶
func Content() ScenePredicate
Content is satisfied if the scene has any of its fields set.
func (ScenePredicate) Invert ¶
func (p ScenePredicate) Invert() ScenePredicate
Invert a scene predicate.
type Scribe ¶
type Scribe interface { StdLogAPI Enabled() Level SetEnabled(level Level) Capture(scene Scene) StdLogAPI }
Scribe is the starting point for invoking a logger. There is no concept of a default Scribe logger; one one must be constructed explicitly using NewScribe() and handed to the application. (Or the application may instantiate a singleton logger and use the same Scribe instance throughout.)
func New ¶
func New(facs LoggerFactories) Scribe
New constructs a Scribe instance from the given facs configuration.
The supplied facs maps a supported log level to a corresponding LoggerFactory. Factories may be supplied individually for each supported log level. The special All level can be used to configure a default factory that will be applied to all built-in log levels that have not been explicitly configured in facs. If one of the built-in levels is not configured, and no default LogFactory is specified for All, this function will panic.
Custom log levels are supported by supplying a mapping for a custom Level. However, the default LogFactory specified for the All level does not apply to custom levels. In other words, each custom level requires an explicit LogFactory.
Directories ¶
Path | Synopsis |
---|---|
Package glog provides a Glog binding for Scribe.
|
Package glog provides a Glog binding for Scribe. |
Package log15 provides a Log15 binding for Scribe.
|
Package log15 provides a Log15 binding for Scribe. |
Package logrus provides a Logrus binding for Scribe.
|
Package logrus provides a Logrus binding for Scribe. |
Package overlog provides a reference logging implementation for Scribe.
|
Package overlog provides a reference logging implementation for Scribe. |
Package seelog provides a Seelog binding for Scribe.
|
Package seelog provides a Seelog binding for Scribe. |
Package zap provides a Zap binding for Scribe.
|
Package zap provides a Zap binding for Scribe. |