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.