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: {}, **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



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

def initialize(id, backends: [], tags: [], context: {}, **options)
  @id = id
  @backends = backends
  @options = {**options, progname: id}
  @mutex = Mutex.new
  @default_tags = tags.freeze
  @default_context = context.freeze
  @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



24
25
26
# File 'lib/dry/logger/dispatcher.rb', line 24

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



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

def clock
  @clock
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



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

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



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

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



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

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



28
29
30
# File 'lib/dry/logger/dispatcher.rb', line 28

def options
  @options
end

Class Method Details

.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



69
70
71
72
73
74
# File 'lib/dry/logger/dispatcher.rb', line 69

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



273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/dry/logger/dispatcher.rb', line 273

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

#contextObject

Shared payload context

Examples:

logger.context[:component] = "test"

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

Since:

  • 1.0.0



238
239
240
241
# File 'lib/dry/logger/dispatcher.rb', line 238

def context
  @context_key ||= :"context_#{object_id}"
  ExecutionContext[@context_key] ||= @default_context.dup
end

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

Log an entry with DEBUG severity

Returns:

  • (true)

See Also:

Since:

  • 1.0.0



103
104
105
# File 'lib/dry/logger/dispatcher.rb', line 103

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



294
295
296
297
298
# File 'lib/dry/logger/dispatcher.rb', line 294

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



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

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



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

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



305
306
307
308
# File 'lib/dry/logger/dispatcher.rb', line 305

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



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

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

#inspectObject

Since:

  • 1.0.0



288
289
290
# File 'lib/dry/logger/dispatcher.rb', line 288

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

#levelInteger

Return severity level

Returns:

  • (Integer)

Since:

  • 1.0.0



154
155
156
# File 'lib/dry/logger/dispatcher.rb', line 154

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



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/dry/logger/dispatcher.rb', line 189

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: current_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

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



256
257
258
259
260
261
# File 'lib/dry/logger/dispatcher.rb', line 256

def tagged(*tags)
  tags_stack.push(tags)
  yield
ensure
  tags_stack.pop
end

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

Log an entry with UNKNOWN severity

Returns:

  • (true)

See Also:

Since:

  • 1.0.0



94
95
96
# File 'lib/dry/logger/dispatcher.rb', line 94

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



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

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