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



277
278
279
280
281
282
283
284
285
286
287
288
# File 'lib/dry/logger/dispatcher.rb', line 277

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



298
299
300
301
302
# File 'lib/dry/logger/dispatcher.rb', line 298

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



309
310
311
312
# File 'lib/dry/logger/dispatcher.rb', line 309

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



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

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
239
240
241
242
243
244
245
# File 'lib/dry/logger/dispatcher.rb', line 208

def log(severity, message = nil, **payload, &block) # rubocop:disable Metrics/PerceivedComplexity
  return true if LEVELS[severity] < level

  case message
  when Hash then log(severity, **message, &block)
  else
    if block
      progname = message
      block_result = block.call
      case block_result
      when Hash then payload = block_result
      else
        message = block_result
      end
    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 => exception
      on_crash.(progname: id, exception: exception, message: message, payload: payload)
    end
  end

  true
rescue StandardError => exception
  on_crash.(progname: id, exception: exception, 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



260
261
262
263
264
265
# File 'lib/dry/logger/dispatcher.rb', line 260

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