Project

evt-log

0.01
No release in over 3 years
Low commit activity in last 3 years
There's a lot of open issues
Logging to STD IO with levels, tagging, and coloring
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies
 Project Readme

log

Logging to STD IO with levels, tagging, and coloring

Example

Something = Class.new
logger = Log.get(Something)

logger.info 'Some info log message'
# => [2000-01-01T00:00:00.00000Z] Something INFO: Some info log message

Log Levels

The logger provides six levels of detail/severity for categorizing log messages. Log levels are used to control the verbosity of the logger's output.

level Description
trace Most detailed level of tracing program flow
debug Recording of the completion of a secondary operation of a class or utility, or for recording other details
info Recording of the completion of the principle operation of a class or utility
warn Unexpected state that is not an error, or is recoverable, and that a developer or operator should examine
error Error message logged just prior to raising an error
fatal Message recorded, when possible, as the process is terminating due to an error

Writing a Log Message

A log message is written by invoking one of the log's six log level methods.

Something = Class.new
logger = Log.get(Something)

logger.trace 'Some trace log message'
# => [2000-01-01T00:00:00.00001Z] Something TRACE: Some trace log message

logger.debug 'Some debug log message'
# => [2000-01-01T00:00:00.00002Z] Something DEBUG: Some debug log message

logger.info 'Some info log message'
# => [2000-01-01T00:00:00.00003Z] Something INFO: Some info log message

logger.warn 'Some warn log message'
# => [2000-01-01T00:00:00.00004Z] Something WARN: Some warn log message

logger.error 'Some error log message'
# => [2000-01-01T00:00:00.00005Z] Something ERROR: Some error log message

logger.fatal 'Some fatal log message'
# => [2000-01-01T00:00:00.00006Z] Something FATAL: Some fatal log message

Late Evaluation

Log messages can be written with late evaluation or early evaluation.

Late evaluation allows a message string with interpolation to not be interpolated unless the logger's current level allows for the message to be printed.

Something = Class.new
logger = Log.get(Something)

some_value = 'Hello'

logger.info { "Some info log message: #{some_value}" }
# => [2000-01-01T00:00:00.00000Z] Something INFO: Some info log message: Hello

Write Unformatted Output

Log output can be printed without any of the formatting or headings.

Something = Class.new
logger = Log.get(Something)

some_value = 'Hello'

logger.puts("Some info log message: #{some_value}")
# => Some info log message: Hello

The puts method does not support tags or levels.

There is no deferred execution option with the logger's puts method. It is a straight pass-through to the logger's device.

logger.puts "Something"

Is equivalent to:

logger.device.puts "Something"

Log Tags

A log message can be written with an optional list of one or more tags. Tags can be used to filter the logger's output.

Tags are Ruby symbols.

Something = Class.new
logger = Log.get(Something)

# One tag
logger.info(tag: :some_tag) { 'Some info log message' }

# Many tags
logger.info(tags: [:some_tag, :some_other_tag]) { 'Some info log message' }

Log tags can also be applied to messages written with early evaluation.

# One tag
logger.info('Some info log message', tag: :some_tag)

# Many tags
logger.info('Some info log message', tags: [:some_tag, :some_other_tag])

For a list of tags throughout the toolkit that can be used to filter log output, see the log tags user guide.

The Override Log Tag

The special log tag :* overrides any log filters in effect.

When the :* tag is applied to a log message, it can't be filtered out of the log output.

Controlling Log Output

Log output can be controlled by both log level and log tags.

Both log level and log tag filters are set using environment variables.

Control by Log Level

The LOG_LEVEL environment variable controls the log output verbosity.

LOG_LEVEL=debug start_service.sh

Log levels are cumulative. The trace level is the most verbose, and the fatal level is the least verbose.

If the LOG_LEVEL is set to trace, all log messages at all levels will be displayed. If the LOG_LEVEL is set to fatal then only log messages at the fatal level will be displayed.

If the log level is set to a value that isn't a legitimate log level, an error is raised:

LOG_LEVEL=something start_service.sh

Level "something" must be one of: "fatal", "error", "warn", "info", "debug", "trace" (Log::Error)

Default Log Level

By default, a logger prints messages at the info level, and above, including the warn, error, and fatal levels.

Special Log Level Controls

The following log level filters are considered special in that they offer log output control above and beyond using the named levels

Special Level Description Example
_none No log messages will be printed LOG_LEVEL=_none start_service.sh
_min Minimum verbosity, equivalent to the fatal level LOG_LEVEL=_min start_service.sh
_max Maximum verbosity, equivalent to the trace level LOG_LEVEL=_max start_service.sh

Control by Log Tag

The LOG_TAGS environment variable controls which log messages will be printed based on the log tags applied to the log message.

LOG_TAGS=messaging start_service.sh

Note: If the LOG_TAG environment variable is set to any value (except _untagged), untagged log messages won't be printed.

Include Many Log Tags

To display log messages from a number of tags, a comma-separated list of tags can be specified.

When using a list of tags, a log message just has to have one of the specified tags applied.

LOG_TAGS=messaging,message_store start_service.sh

Exclude Tags

Log messages can be excluded by tag by prefixing the tag name with the - character.

LOG_TAGS=-message_store start_service.sh

Exclusion tags can be combined with each other, as well as with inclusion tags in the tags list.

LOG_TAGS=-message_store,messaging,-consumer,cache start_service.sh

Special Log Tag Controls

The following log tag filters are considered special in that they offer log output control above and beyond using the named tags

Special Level Description Example
_all Print log messages from all tags, except for untagged messages LOG_TAGS=_all start_service.sh
_untagged Print log messages that aren't tagged LOG_TAGS=_untagged start_service.sh

Log Level Standards

Trace Level

The trace level is used to log the entry of a method that concludes with either an info or debug log message.

Log messages at the trace level are typically worded to indicate that something is being done or about to be done. The ing present or gerund form of verbs is used in trace messages, for example "Writing message".

Info Level

The info level is used to log the completion of the principle operation of a class or utility, like a callable class or object's actuator.

Log messages at the info level are typically worded to indicate that something has been done or completed. The ed past tense form of verbs is used in trace messages, for example "Wrote message".

Debug Level

The debug level is used to log the completion of a secondary operation of a class or utility, or for recording other details.

Log messages at the debug level are typically worded to indicate that something has been done or completed. The ed past tense form of verbs is used in debug messages, for example "Wrote initial message".

Error Level

The error level is used to log an error message to record an error state immediately before raising the error.

Warn Level

The warn level is used to log an unexpected condition that isn't an error and that does not need to terminate the process. A warn log message indicates something that may not have been intentional and that a developer or operator should examine.

Fatal Level

The fatal level is used only when a process is terminating due to an error. It should only be used by a top-level error handler just before the process terminates.

Logger Subject

A logger is constructed for a specific subject. That subject is included in a printed log message's prefix.

In the following example, the Something class is the logger's subject. The subject is printed between the log message's timestamp and its capitalized representation of the message's log level. In this case, the printed subject is "Something".

Something = Class.new
logger = Log.get(Something)

logger.info 'Some info log message'
# => [2000-01-01T00:00:00.00000Z] Something INFO: Some info log message

The subject can be a class, an object, or a string. If an object is used, the logger's subject will be the object's class. If a string is used, the logger's subject will be the value of the string.

Get a Logger from the Logger Registry

The Log namespace has a registry of logger instances that are associated with a subject.

Rather than build a new logger each time for a subject that has previously had a logger built for it, loggers can be registered for subsequent use of the same subject at a later time.

self.get(subject)

Returns

New instance of the logger class, or an existing instance that was previously registered for the subject.

Parameters

Name Description Type
subject The subject that the logger is writing messages for Class, Object, or String

When a subject doesn't already exist in the registry for the subject, a new logger will be constructed for it, and added to the registry.

When a subject is already in the registry, it's associated logger is returned rather than building a new logger.

Constructing a Logger

Loggers can be constructed in one of two ways

  • Via the constructor
  • Via the initializer

Note: Directly constructing a logger does not add the logger to the logger registry. The `get` class method should be used in order to both build and register loggers.

Via the Constructor

self.build(subject)

The constructor not only instantiates the logger, but also invokes the writer's configure instance method, which constructs the writer's operational dependencies and sets its defaults, such as the default levels.

Returns

Instance of the logger class.

Parameters

Name Description Type
subject The subject that the logger is writing messages for Class, Object, or String

Via the Initializer

self.initialize(subject)

Returns

Instance of the logger class.

Parameters

Name Description Type
subject The subject that the logger is writing messages for Class, Object, or String

By constructing a logger using the initializer, the logger's dependencies are not set to operational dependencies. They remain inert substitutes.

See the useful objects user guide for background on inert substitutes.

Assigning a Logger as a Dependency

self.configure(receiver, attr_name: :logger)

Constructs an instance of the logger and registers it (or retrieves an existing logger from the registry) and assigns it to the receiver's logger attribute. By default, the receiving attribute's name is expected to be logger, but it can be altered with the use of the attr_name parameter.

something = Something.new
Messaging::Postgres::Write.configure(something)

something.logger
# => #<Log:0x...>

Parameters

Name Description Type
receiver The object that will receive the constructed logger Object
attr_name The receiver's attribute that will be assigned the constructed logger Symbol

Note: When configuring a logger as a dependency, the `receiver` is used as the logger's subject.

See the useful objects user guide for background on configuring dependencies.

The Log::Dependency Module

The Log::Dependency module is a mixin that both creates a logger attribute, an configures an operational logger as its value.

The Log::Dependency is the most common way of assigning a logger to a subject.

class Something
  include Log::Dependency

  # ...
end

License

The log library is released under the MIT License.