class Log

Overview

The Log class provides a logging utility that you can use to output messages.

The messages, or Log::Entry have associated levels, such as Info or Error that indicate their importance. See Log::Severity.

To log a message #debug, #verbose, #info, #warn, #error, and #fatal methods can be used. They expect a block that will evaluate to the message of the entry.

require "log"

Log.info { "Program started" }

If you want to log an exception, you can indicate it in the exception: named argument.

Log.warn(exception: e) { "Oh no!" }

The block is only evaluated if the current message is to be emitted to some Log::Backend.

To add structured information to the message you can use the Log::Context.

When creating log messages they belong to a source. If the top-level Log is used as in the above examples its source is the empty string.

The source can be used to identify the module or part of the application that is logging. You can configure for each source a different level to filter the messages.

A recommended pattern is to declare a Log constant in the namespace of your shard or module as follows:

module DB
  Log = ::Log.for("db") # => Log for db source

  def do_something
    Log.info { "this is logged in db source" }
  end
end

DB::Log.info { "this is also logged in db source" }
Log.for("db").info { "this is also logged in db source" }
Log.info { "this is logged in top-level source" }

That way, any Log.info call within the DB module will use the db source. And not the top-level ::Log.info.

Sources can be nested. Continuing the last example, to declare a Log constant db.pool source you can do as follows:

class DB::Pool
  Log = DB::Log.for("pool") # => Log for db.pool source
end

A Log will emit the messages to the Log::Backends attached to it as long as the configured severity filter #level permits it.

Logs can also be created from a type directly. For the type DB::Pool the source db.pool will be used. For generic types as Foo::Bar(Baz) the source foo.bar will be used (i.e. without generic arguments).

module DB
  Log = ::Log.for(self) # => Log for db source
end

Configure logging explicitly in the code

Use Log.builder to indicate which sources should go to which backends.

You can indicate actual sources or patterns.

The following configuration will setup for all sources to emit warnings (or higher) to STDOUT, allow any of the db.* and nested source to emit debug (or higher), and to also emit for all sources errors (or higher) to an elasticsearch backend.

backend = Log::IOBackend.new
Log.builder.bind "*", :warning, backend
Log.builder.bind "db.*", :debug, backend
Log.builder.bind "*", :error, ElasticSearchBackend.new("http://localhost:9200")

Configure logging from environment variables

Include the following line to allow configuration from environment variables.

Log.setup_from_env

The environment variables CRYSTAL_LOG_LEVEL and CRYSTAL_LOG_SOURCES are used to indicate which severity level to emit (defaults to INFO; use NONE to skip all messages) and to restrict which sources you are interested in.

The valid values for CRYSTAL_LOG_SOURCES are:

The logs are emitted to STDOUT using a Log::IOBackend.

If Log.setup_from_env is called on startup you can tweak the logging as:

Defined in:

log.cr
log/main.cr
log/env_config.cr
log/log.cr

Constructors

Class Method Summary

Instance Method Summary

Instance methods inherited from class Reference

==(other : self)
==(other : JSON::Any)
==(other : YAML::Any)
==(other)
==
, dup dup, hash(hasher) hash, inspect(io : IO) : Nil inspect, object_id : UInt64 object_id, pretty_print(pp) : Nil pretty_print, same?(other : Reference)
same?(other : Nil)
same?
, to_s(io : IO) : Nil to_s

Constructor methods inherited from class Reference

new new

Instance methods inherited from class Object

! : Bool !, !=(other) !=, !~(other) !~, ==(other) ==, ===(other : JSON::Any)
===(other : YAML::Any)
===(other)
===
, =~(other) =~, as(type : Class) as, as?(type : Class) as?, class class, dup dup, hash(hasher)
hash
hash
, in?(*values : Object) : Bool
in?(collection) : Bool
in?
, inspect : String
inspect(io : IO) : Nil
inspect
, is_a?(type : Class) : Bool is_a?, itself itself, nil? : Bool nil?, not_nil! not_nil!, pretty_inspect(width = 79, newline = "\n", indent = 0) : String pretty_inspect, pretty_print(pp : PrettyPrint) : Nil pretty_print, responds_to?(name : Symbol) : Bool responds_to?, tap(&) tap, to_json(io : IO)
to_json
to_json
, to_pretty_json(io : IO, indent : String = " ")
to_pretty_json(indent : String = " ")
to_pretty_json
, to_s : String
to_s(io : IO) : Nil
to_s
, to_yaml(io : IO)
to_yaml
to_yaml
, try(&) try, unsafe_as(type : T.class) forall T unsafe_as

Class methods inherited from class Object

from_json(string_or_io, root : String)
from_json(string_or_io)
from_json
, from_yaml(string_or_io : String | IO) from_yaml

Constructor Detail

def self.for(source : String, level : Severity? = nil) : Log #

Creates a Log for the given source. If level is given, it will override the configuration.


[View source]
def self.for(type : Class, level : Severity? = nil) : Log #

Creates a Log for the given type. A type Foo::Bar(Baz) corresponds to the source foo.bar. If level is given, it will override the configuration.


[View source]

Class Method Detail

def self.builder #

Returns the default Log::Builder used for Log.for calls.


[View source]
def self.context : Log::Context #

Returns the current fiber logging context.


[View source]
def self.context=(value : Log::Context) #

Sets the current fiber logging context.


[View source]
def self.debug(*, exception : Exception? = nil, &) #

See Log#debug.


[View source]
def self.error(*, exception : Exception? = nil, &) #

See Log#error.


[View source]
def self.fatal(*, exception : Exception? = nil, &) #

See Log#fatal.


[View source]
def self.info(*, exception : Exception? = nil, &) #

See Log#info.


[View source]
def self.setup_from_env(*, builder : Log::Builder = Log.builder, level = ENV.fetch("CRYSTAL_LOG_LEVEL", "INFO"), sources = ENV.fetch("CRYSTAL_LOG_SOURCES", ""), backend = Log::IOBackend.new) #

Setups builder based on CRYSTAL_LOG_LEVEL and CRYSTAL_LOG_SOURCES environment variables.


[View source]
def self.verbose(*, exception : Exception? = nil, &) #

[View source]
def self.warn(*, exception : Exception? = nil, &) #

See Log#warn.


[View source]
def self.with_context(&) #

Method to save and restore the current logging context.

Log.context.set a: 1
Log.info { %(message with {"a" => 1} context) }
Log.with_context do
  Log.context.set b: 2
  Log.info { %(message with {"a" => 1, "b" => 2} context) }
end
Log.info { %(message with {"a" => 1} context) }

[View source]

Instance Method Detail

def backend : Backend? #

[View source]
def context : Log::Context #

Returns the current fiber logging context.


[View source]
def context=(value : Log::Context) #

Sets the current fiber logging context.


[View source]
def debug(*, exception : Exception? = nil, &) #

Logs a message if the logger's current severity is lower or equal to 0.


[View source]
def error(*, exception : Exception? = nil, &) #

Logs a message if the logger's current severity is lower or equal to 4.


[View source]
def fatal(*, exception : Exception? = nil, &) #

Logs a message if the logger's current severity is lower or equal to 5.


[View source]
def for(child_source : String, level : Severity? = nil) : Log #

Creates a Log for the given nested source. If level is given, it will override the configuration.


[View source]
def for(type : Class, level : Severity? = nil) : Log #

Creates a Log for the given type. A type Foo::Bar(Baz) corresponds to the source foo.bar. If level is given, it will override the configuration.


[View source]
def info(*, exception : Exception? = nil, &) #

Logs a message if the logger's current severity is lower or equal to 2.


[View source]
def level : Severity #

[View source]
def level=(value : Severity) #

Change this log severity level filter.


[View source]
def source : String #

[View source]
def verbose(*, exception : Exception? = nil, &) #

Logs a message if the logger's current severity is lower or equal to 1.


[View source]
def warn(*, exception : Exception? = nil, &) #

Logs a message if the logger's current severity is lower or equal to 3.


[View source]