Skip to main content

Version 2

This document aims to outline a unified specification, inspired by various logging implementations.

Cross-language considerations

Casing

This specification assumes that methods are written in CamelCase and enums in CONSTANT_CASE. If the programming language your implementation uses has different conventions, use them instead.

Enums

This specification assumes that the programming language your implementation uses supports enums. If it doesn't, use integer constants instead. If that isn't possible, use strings.

What a good logger needs

A good logger implementation needs the following things:

  • levels, to distinguish message importance
  • a message's origin, to know from where a message came
  • the actual log message

Levels

An implementation must provide at least five log levels and may implement an optional one to be able to determine a message's priority.

Name Method name Printed name Enum name Optional
Diagnostic diag DIAG DIAGNOSTIC No
Verbose verb VERB VERBOSE No
Silent Warning sarn SARN SILENT_WARNING No
Informational info INFO INFORMATIONAL No
Warning warn WARN WARNING No
Error error ERR! ERROR No
Crash crash CRSH CRASH If the language and/or platform does not provide a good native crash handler

Format

A format is required to represent a log message as well as relevant information in a human way. The logging format shall be minimal but extensible with so-called "format features", which may be chained together. A few optional and required features are listed in this specification. Implementation-specific features may be added, depending on the use case, environment, language and other variables.

Default format

[<printed level name> <origin>] <message>

Feature formatting

The content stays the same but the message is colorized.

This feature is optional.

Feature runtime

Prepends the time the implementation or application is running in milliseconds.
Example by extending the default: [<run time in milliseconds>ms] [<printed level name> <origin>] <message>

This feature is required.

Features date & time

Prepends the date and/or the time to the output.
Example by extending the default: [<date> [time]] [<printed level name> <origin>] <message>

This feature is required unless the language of the implementation does not provide good support for dates and time.

Features methodName & lineNumber

Appends the method name and/or line number to the origin. Example by extending the default: [<printed level name> <origin>#<method name>~<line number>] <message>

This feature is required unless the language of the implementation does not provide insufficient or any automatic (ie. without developer intervention on log call) support.

All features

Below is an example of how the format would look like if all features mentioned in this specification were enabled.

With placeholders

[<runtime>ms] [<date> <time>] [<printed level name> <origin>#<method name>~<line number>] <message>

Filled

[505ms] [03.10.1990 23:23:23] [INFO Test.example#sayHi~42] Hello World!

Configuration

A logger implementing this specification should be able to be configured by the running application at runtime. This specification lists a few required and optional features. Implementations may provide their own.

Minimum level

Specifies the minimum allowed log level. Lower levels are forbidden and won't be logged.

This option is required and must either be an enum, integer or a string (fallback to the next if one is unavailable).

Features

Specifies a list of enabled features.

This option is required and must be a comma-separated string or list of strings.

Multithreading

Specifies that the implementation is multithreaded by accepting log calls, queueing and then processing them on a separate thread.

This option is optional but recommended.

Thread Polling Delay

Specifies the time the logging thread shall wait before processing the queue again. This value should be subtracted by the time if took to process all queued messages after all messages have been processed.

This option is required if multithreading is built into the implementation.

Placeholders

Implementations may allow placeholders to be placed into a log message and replaced during processing. These must be wrapped inside %-signs and must allow for optional configuration. Placeholders must allow placeholders to be added and removed dynamically.

Methods

Implementations are required to provide methods for all levels, with each being named after the level's method name.

Each method must require at least the message to be logged. If required by the language of the implementation, information about the message origin may be required as well. This however should be avoided to not annoy developers and create maintenance burdens.