Class: Dry::Logger::Dispatcher

Inherits:
Object
  • Object
show all
Defined in:
lib/dry/logger/dispatcher.rb

Overview

Logger dispatcher routes log entries to configured logging backends

Since:

  • 1.0.0

Constant Summary collapse

CRASH_LOGGER =

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:

  • 1.0.0

::Logger.new($stdout).tap { |logger|
  logger.formatter = -> (_, _, _, message) { "#{message}#{NEW_LINE}" }
  logger.level = FATAL
}.freeze
ON_CRASH =

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:

  • 1.0.0

-> (progname:, exception:, message:, payload:) {
  CRASH_LOGGER.fatal(Logger.templates[:crash] % {
    severity: "FATAL",
    progname: progname,
    time: Time.now,
    log_entry: [message, payload].map(&:to_s).reject(&:empty?).join(SEPARATOR),
    exception: exception.class,
    message: exception.message,
    backtrace: TAB + exception.backtrace.join(NEW_LINE + TAB)
  })
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id, backends: [], tags: [], context: self.class.default_context, **options) ⇒ Dispatcher

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.

Returns a new instance of Dispatcher.

Since:

  • 1.0.0



95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/dry/logger/dispatcher.rb', line 95

def initialize(
  id, backends: [], tags: [], context: self.class.default_context, **options
)
  @id = id
  @backends = backends
  @options = {**options, progname: id}
  @mutex = Mutex.new
  @context = context
  @tags = tags
  @clock = Clock.new(**(options[:clock] || EMPTY_HASH))
  @on_crash = options[:on_crash] || ON_CRASH
end

Instance Attribute Details

#backendsObject (readonly)

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.0.0



35
36
37
# File 'lib/dry/logger/dispatcher.rb', line 35

def backends
  @backends
end

#clockObject (readonly)

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.0.0



43
44
45
# File 'lib/dry/logger/dispatcher.rb', line 43

def clock
  @clock
end

#contextObject (readonly)

(EXPERIMENTAL) Shared payload context

Examples:

logger.context[:component] = "test"

logger.info "Hello World"
# Hello World component=test

Since:

  • 1.0.0



31
32
33
# File 'lib/dry/logger/dispatcher.rb', line 31

def context
  @context
end

#idObject (readonly)

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.0.0



19
20
21
# File 'lib/dry/logger/dispatcher.rb', line 19

def id
  @id
end

#mutexObject (readonly)

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.0.0



51
52
53
# File 'lib/dry/logger/dispatcher.rb', line 51

def mutex
  @mutex
end

#on_crashObject (readonly)

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.0.0



47
48
49
# File 'lib/dry/logger/dispatcher.rb', line 47

def on_crash
  @on_crash
end

#optionsObject (readonly)

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.0.0



39
40
41
# File 'lib/dry/logger/dispatcher.rb', line 39

def options
  @options
end

Class Method Details

.default_contextObject

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.0.0



89
90
91
# File 'lib/dry/logger/dispatcher.rb', line 89

def self.default_context
  Thread.current[:__dry_logger__] ||= {}
end

.setup(id, **options) {|dispatcher| ... } ⇒ Dispatcher

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.

Set up a dispatcher

Yields:

  • (dispatcher)

Returns:

Since:

  • 1.0.0



80
81
82
83
84
85
# File 'lib/dry/logger/dispatcher.rb', line 80

def self.setup(id, **options)
  dispatcher = new(id, **DEFAULT_OPTS, **options)
  yield(dispatcher) if block_given?
  dispatcher.add_backend if dispatcher.backends.empty?
  dispatcher
end

Instance Method Details

#add_backend(instance = nil, **backend_options) {|backend| ... } ⇒ Dispatcher

Add a new backend to an existing dispatcher

Examples:

logger.add_backend(template: "ERROR: %<message>s") { |b|
  b.log_if = -> entry { entry.error? }
}

Yields:

  • (backend)

Returns:

Since:

  • 1.0.0



270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/dry/logger/dispatcher.rb', line 270

def add_backend(instance = nil, **backend_options)
  backend =
    case (instance ||= Dry::Logger.new(**options, **backend_options))
    when Backends::Stream then instance
    else Backends::Proxy.new(instance, **options, **backend_options)
    end

  yield(backend) if block_given?

  backends << backend
  self
end

#debug(message = nil, **payload, &block) ⇒ true

Log an entry with DEBUG severity

Returns:

  • (true)

See Also:

Since:

  • 1.0.0



122
123
124
# File 'lib/dry/logger/dispatcher.rb', line 122

def debug(message = nil, **payload, &block)
  log(:debug, message, **payload, &block)
end

#each_backend(&block) ⇒ 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.0.0



291
292
293
294
295
# File 'lib/dry/logger/dispatcher.rb', line 291

def each_backend(&block)
  mutex.synchronize do
    backends.each(&block)
  end
end

#error(message = nil, **payload, &block) ⇒ true

Log an entry with ERROR severity

Returns:

  • (true)

See Also:

Since:

  • 1.0.0



149
150
151
# File 'lib/dry/logger/dispatcher.rb', line 149

def error(message = nil, **payload, &block)
  log(:error, message, **payload, &block)
end

#fatal(message = nil, **payload, &block) ⇒ true

Log an entry with FATAL severity

Returns:

  • (true)

See Also:

Since:

  • 1.0.0



158
159
160
# File 'lib/dry/logger/dispatcher.rb', line 158

def fatal(message = nil, **payload, &block)
  log(:fatal, message, **payload, &block)
end

#forward(meth) ⇒ true

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.

Pass logging to all configured backends

Returns:

  • (true)

Since:

  • 1.0.0



302
303
304
305
# File 'lib/dry/logger/dispatcher.rb', line 302

def forward(meth, ...)
  each_backend { |backend| backend.public_send(meth, ...) }
  true
end

#info(message = nil, **payload, &block) ⇒ true

Log an entry with INFO severity

Returns:

  • (true)

See Also:

Since:

  • 1.0.0



131
132
133
# File 'lib/dry/logger/dispatcher.rb', line 131

def info(message = nil, **payload, &block)
  log(:info, message, **payload, &block)
end

#inspectObject

Since:

  • 1.0.0



285
286
287
# File 'lib/dry/logger/dispatcher.rb', line 285

def inspect
  %(#<#{self.class} id=#{id} options=#{options} backends=#{backends}>)
end

#levelInteger

Return severity level

Returns:

  • (Integer)

Since:

  • 1.0.0



173
174
175
# File 'lib/dry/logger/dispatcher.rb', line 173

def level
  LEVELS[options[:level]]
end

#log(severity, message = nil, **payload) { ... } ⇒ true

Pass logging to all configured backends

Examples:

logging a message

logger.log(:info, "Hello World")

logging a message by passing a block

logger.log(:debug, "Sidecar") { "Hello World" }

logging payload

logger.log(:info, verb: "GET", path: "/users")

logging message and payload

logger.log(:info, "User index request", verb: "GET", path: "/users")

logging exception

begin
  # things that may raise
rescue => e
  logger.log(:error, e)
  raise e
end

Parameters:

  • severity (Symbol)

    The log severity name

  • message (String) (defaults to: nil)

    Optional message

  • payload (Hash)

    Optional log entry payload

Yields:

Yield Returns:

  • (String)

    Message to be logged

Returns:

  • (true)

Since:

  • 1.0.0



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/dry/logger/dispatcher.rb', line 208

def log(severity, message = nil, **payload, &block)
  case message
  when Hash then log(severity, **message, &block)
  else
    if block
      progname = message
      message = block.call
    end
    progname ||= id

    entry = Entry.new(
      clock: clock,
      progname: progname,
      severity: severity,
      tags: @tags,
      message: message,
      payload: {**context, **payload}
    )

    each_backend do |backend|
      backend.__send__(severity, entry) if backend.log?(entry)
    rescue StandardError => e
      on_crash.(progname: id, exception: e, message: message, payload: payload)
    end
  end

  true
rescue StandardError => e
  on_crash.(progname: id, exception: e, message: message, payload: payload)
  true
end

#tagged(*tags) ⇒ Object

(EXPERIMENTAL) Tagged logging withing the provided block

Examples:

logger.tagged("red") do
  logger.info "Hello World"
  # Hello World tag=red
end

logger.info "Hello Again"
# Hello Again

Since:

  • 1.0.0



253
254
255
256
257
258
# File 'lib/dry/logger/dispatcher.rb', line 253

def tagged(*tags)
  @tags.concat(tags)
  yield
ensure
  @tags = []
end

#unknown(message = nil, **payload, &block) ⇒ true

Log an entry with UNKNOWN severity

Returns:

  • (true)

See Also:

Since:

  • 1.0.0



113
114
115
# File 'lib/dry/logger/dispatcher.rb', line 113

def unknown(message = nil, **payload, &block)
  log(:unknown, message, **payload, &block)
end

#warn(message = nil, **payload, &block) ⇒ true

Log an entry with WARN severity

Returns:

  • (true)

See Also:

Since:

  • 1.0.0



140
141
142
# File 'lib/dry/logger/dispatcher.rb', line 140

def warn(message = nil, **payload, &block)
  log(:warn, message, **payload, &block)
end