Class: Hanami::Logger

Inherits:
Logger
  • Object
show all
Defined in:
lib/hanami/logger.rb,
lib/hanami/logger/filter.rb,
lib/hanami/logger/colorizer.rb,
lib/hanami/logger/formatter.rb

Overview

Hanami logger

Implementation with the same interface of Ruby std lib `Logger`. It uses `STDOUT`, `STDERR`, file name or open file as output stream.

When a Hanami application is initialized, it creates a logger for that specific application. For instance for a `Bookshelf::Application` a `Bookshelf::Logger` will be available.

This is useful for auto-tagging the output. Eg (`app=Booshelf`).

When used standalone (eg. `Hanami::Logger.info`), it tags lines with `app=Shared`.

The available severity levels are the same of `Logger`:

* DEBUG
* INFO
* WARN
* ERROR
* FATAL
* UNKNOWN

Those levels are available both as class and instance methods.

Also Hanami::Logger supports different formatters. Now available only two:

* Formatter (default)
* JSONFormatter

And if you want to use custom formatter you need create new class inherited from `Formatter` class and define `_format` private method like this:

class CustomFormatter < Formatter
  private
  def _format(hash)
    # ...
  end
end

Examples:

Basic usage

require 'hanami'

module Bookshelf
  class Application < Hanami::Application
  end
end

# Initialize the application with the following code:
Bookshelf::Application.load!
# or
Bookshelf::Application.new

Bookshelf::Logger.new.info('Hello')
# => app=Bookshelf severity=INFO time=1988-09-01 00:00:00 UTC message=Hello

Standalone usage

require 'hanami/logger'

Hanami::Logger.new.info('Hello')
# => app=Hanami severity=INFO time=2016-05-27 10:14:42 UTC message=Hello

Custom tagging

require 'hanami/logger'

Hanami::Logger.new('FOO').info('Hello')
# => app=FOO severity=INFO time=2016-05-27 10:14:42 UTC message=Hello

Write to file

require 'hanami/logger'

Hanami::Logger.new(stream: 'logfile.log').info('Hello')
# in logfile.log
# => app=FOO severity=INFO time=2016-05-27 10:14:42 UTC message=Hello

Use JSON formatter

require 'hanami/logger'

Hanami::Logger.new(formatter: Hanami::Logger::JSONFormatter).info('Hello')
# => "{\"app\":\"Hanami\",\"severity\":\"INFO\",\"time\":\"1988-09-01 00:00:00 UTC\",\"message\":\"Hello\"}"

Disable colorization

require 'hanami/logger'

Hanami::Logger.new(colorizer: false)

Use custom colors

require 'hanami/logger'

Hanami::Logger.new(colorizer: Hanami::Logger::Colorizer.new(colors: { app: :red }))

Use custom colorizer

require "hanami/logger"
require "paint" # gem install paint

class LogColorizer < Hanami::Logger::Colorizer
  def initialize(colors: { app: [:red, :bright], severity: [:red, :blue], datetime: [:italic, :yellow] })
    super
  end

  private

  def colorize(message, color:)
    Paint[message, *color]
  end
end

Hanami::Logger.new(colorizer: LogColorizer.new)

See Also:

Since:

  • 0.5.0

Defined Under Namespace

Classes: Colorizer, Filter, Formatter, JSONFormatter, NullColorizer

Constant Summary collapse

DEFAULT_APPLICATION_NAME =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Default application name. This is used as a fallback for tagging purposes.

Since:

  • 0.5.0

"hanami"
LEVELS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Since:

  • 0.8.0

::Hash[
  "debug" => DEBUG,
  "info" => INFO,
  "warn" => WARN,
  "error" => ERROR,
  "fatal" => FATAL,
  "unknown" => UNKNOWN
].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(application_name = nil, *args, stream: $stdout, level: DEBUG, formatter: nil, filter: [], colorizer: nil) ⇒ Logger

Initialize a logger

rubocop:disable Lint/SuppressedException rubocop:disable Metrics/ParameterLists

Examples:

Basic usage

require 'hanami/logger'

logger = Hanami::Logger.new
logger.info "Hello World"

# => [Hanami] [DEBUG] [2017-03-30 15:41:01 +0200] Hello World

Custom application name

require 'hanami/logger'

logger = Hanami::Logger.new('bookshelf')
logger.info "Hello World"

# => [bookshelf] [DEBUG] [2017-03-30 15:44:23 +0200] Hello World

Logger level (Integer)

require 'hanami/logger'

logger = Hanami::Logger.new(level: 2) # WARN
logger.info "Hello World"
# => true

logger.info "Hello World"
# => true

logger.warn "Hello World"
# => [Hanami] [WARN] [2017-03-30 16:00:48 +0200] Hello World

Logger level (Constant)

require 'hanami/logger'

logger = Hanami::Logger.new(level: Hanami::Logger::WARN)
logger.info "Hello World"
# => true

logger.info "Hello World"
# => true

logger.warn "Hello World"
# => [Hanami] [WARN] [2017-03-30 16:00:48 +0200] Hello World

Logger level (String)

require 'hanami/logger'

logger = Hanami::Logger.new(level: 'warn')
logger.info "Hello World"
# => true

logger.info "Hello World"
# => true

logger.warn "Hello World"
# => [Hanami] [WARN] [2017-03-30 16:00:48 +0200] Hello World

Use a file

require 'hanami/logger'

logger = Hanami::Logger.new(stream: "development.log")
logger.info "Hello World"

# => true

File.read("development.log")
# =>
#  # Logfile created on 2017-03-30 15:52:48 +0200 by logger.rb/56815
#  [Hanami] [DEBUG] [2017-03-30 15:52:54 +0200] Hello World

Period rotation

require 'hanami/logger'

# Rotate daily
logger = Hanami::Logger.new('bookshelf', 'daily', stream: 'development.log')

File size rotation

require 'hanami/logger'

# leave 10 old log files where the size is about 1,024,000 bytes
logger = Hanami::Logger.new('bookshelf', 10, 1024000, stream: 'development.log')

Use a StringIO

require 'hanami/logger'

stream = StringIO.new
logger = Hanami::Logger.new(stream: stream)
logger.info "Hello World"

# => true

stream.rewind
stream.read

# => "[Hanami] [DEBUG] [2017-03-30 15:55:22 +0200] Hello World\n"

JSON formatter

require 'hanami/logger'

logger = Hanami::Logger.new(formatter: :json)
logger.info "Hello World"

# => {"app":"Hanami","severity":"DEBUG","time":"2017-03-30T13:57:59Z","message":"Hello World"}

Parameters:

  • application_name (String) (defaults to: nil)

    an optional application name used for tagging purposes

  • args (Array<Object>)

    an optional set of arguments to honor Ruby's `Logger#initialize` arguments. See Ruby documentation for details.

  • stream (String, IO, StringIO, Pathname) (defaults to: $stdout)

    an optional log stream. This is a filename (`String`) or `IO` object (typically `$stdout`, `$stderr`, or an open file). It defaults to `$stderr`.

  • level (Integer, String) (defaults to: DEBUG)

    logging level. It can be expressed as an integer, according to Ruby's `Logger` from standard library or as a string with the name of the level

  • formatter (Symbol, #_format) (defaults to: nil)

    a formatter - We support `:json` as JSON formatter or an object that respond to `#_format(data)`

See Also:

Since:

  • 0.5.0


284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/hanami/logger.rb', line 284

def initialize(application_name = nil, *args, stream: $stdout, level: DEBUG, formatter: nil, filter: [], colorizer: nil) # rubocop:disable Layout/LineLength
  begin
    Utils::Files.mkdir_p(stream)
  rescue TypeError
  end

  super(stream, *args)

  @level            = _level(level)
  @stream           = stream
  @application_name = application_name
  @formatter        = Formatter.fabricate(formatter, self.application_name, filter, lookup_colorizer(colorizer))
end

Instance Attribute Details

#application_nameString

Returns the current application name, this is used for tagging purposes

Returns:

  • (String)

    the application name

Since:

  • 0.5.0


306
307
308
# File 'lib/hanami/logger.rb', line 306

def application_name
  @application_name || _application_name_from_namespace || _default_application_name
end

Class Method Details

.level(level) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Since:

  • 1.2.0


145
146
147
148
149
150
151
152
# File 'lib/hanami/logger.rb', line 145

def self.level(level)
  case level
  when DEBUG..UNKNOWN
    level
  else
    LEVELS.fetch(level.to_s.downcase, DEBUG)
  end
end

Instance Method Details

#closeObject

Closes the logging stream if this stream isn't an STDOUT

Since:

  • 0.8.0


319
320
321
# File 'lib/hanami/logger.rb', line 319

def close
  super unless [STDOUT, $stdout].include?(@stream)
end

#level=(value) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Since:

  • 0.8.0


312
313
314
# File 'lib/hanami/logger.rb', line 312

def level=(value)
  super _level(value)
end