Module: SemanticLogger

Defined in:
lib/semantic_logger/base.rb,
lib/semantic_logger/log.rb,
lib/semantic_logger/utils.rb,
lib/semantic_logger/levels.rb,
lib/semantic_logger/logger.rb,
lib/semantic_logger/version.rb,
lib/semantic_logger/appender.rb,
lib/semantic_logger/loggable.rb,
lib/semantic_logger/appenders.rb,
lib/semantic_logger/processor.rb,
lib/semantic_logger/formatters.rb,
lib/semantic_logger/subscriber.rb,
lib/semantic_logger/test/rspec.rb,
lib/semantic_logger/ansi_colors.rb,
lib/semantic_logger/appender/io.rb,
lib/semantic_logger/appender/tcp.rb,
lib/semantic_logger/appender/udp.rb,
lib/semantic_logger/appender/file.rb,
lib/semantic_logger/appender/http.rb,
lib/semantic_logger/appender/loki.rb,
lib/semantic_logger/metric/statsd.rb,
lib/semantic_logger/test/minitest.rb,
lib/semantic_logger/appender/async.rb,
lib/semantic_logger/appender/kafka.rb,
lib/semantic_logger/formatters/ecs.rb,
lib/semantic_logger/formatters/raw.rb,
lib/semantic_logger/sync_processor.rb,
lib/semantic_logger/appender/sentry.rb,
lib/semantic_logger/appender/splunk.rb,
lib/semantic_logger/appender/syslog.rb,
lib/semantic_logger/formatters/base.rb,
lib/semantic_logger/formatters/json.rb,
lib/semantic_logger/formatters/loki.rb,
lib/semantic_logger/metric/signalfx.rb,
lib/semantic_logger/queue_processor.rb,
lib/semantic_logger/semantic_logger.rb,
lib/semantic_logger/appender/bugsnag.rb,
lib/semantic_logger/appender/graylog.rb,
lib/semantic_logger/appender/mongodb.rb,
lib/semantic_logger/appender/wrapper.rb,
lib/semantic_logger/core_ext/process.rb,
lib/semantic_logger/formatters/color.rb,
lib/semantic_logger/metric/new_relic.rb,
lib/semantic_logger/appender/rabbitmq.rb,
lib/semantic_logger/formatters/logfmt.rb,
lib/semantic_logger/formatters/syslog.rb,
lib/semantic_logger/appender/new_relic.rb,
lib/semantic_logger/formatters/default.rb,
lib/semantic_logger/formatters/fluentd.rb,
lib/semantic_logger/formatters/pattern.rb,
lib/semantic_logger/reporters/minitest.rb,
lib/semantic_logger/appender/opensearch.rb,
lib/semantic_logger/formatters/one_line.rb,
lib/semantic_logger/formatters/signalfx.rb,
lib/semantic_logger/appender/honeybadger.rb,
lib/semantic_logger/appender/sentry_ruby.rb,
lib/semantic_logger/appender/splunk_http.rb,
lib/semantic_logger/debug_as_trace_logger.rb,
lib/semantic_logger/formatters/syslog_cee.rb,
lib/semantic_logger/appender/elasticsearch.rb,
lib/semantic_logger/concerns/compatibility.rb,
lib/semantic_logger/appender/new_relic_logs.rb,
lib/semantic_logger/appender/open_telemetry.rb,
lib/semantic_logger/test/capture_log_events.rb,
lib/semantic_logger/appender/cloudwatch_logs.rb,
lib/semantic_logger/formatters/new_relic_logs.rb,
lib/semantic_logger/formatters/open_telemetry.rb,
lib/semantic_logger/appender/elasticsearch_base.rb,
lib/semantic_logger/appender/elasticsearch_http.rb,
lib/semantic_logger/appender/honeybadger_insights.rb,
lib/semantic_logger/jruby/garbage_collection_logger.rb

Overview

Send log messages to honeybadger events/insights API

Example:

SemanticLogger.add_appender(appender: :honeybadger_insights)

Defined Under Namespace

Modules: AnsiColors, Appender, Concerns, CoreExt, Formatters, JRuby, Levels, Loggable, Metric, Reporters, Test, Utils Classes: Appenders, Base, DebugAsTraceLogger, Log, Logger, Processor, QueueProcessor, Subscriber, SyncProcessor

Constant Summary collapse

VERSION =
"5.0.0".freeze
LEVELS =

Logging levels in order of most detailed to most severe

Levels::LEVELS

Class Method Summary collapse

Class Method Details

.[](klass) ⇒ Object

Return a logger for the supplied class or class_name.

When SemanticLogger.cache_loggers is enabled (opt-in, default off) and a Class or Module is supplied, the same Logger instance is returned for every call with that class. This makes it possible to obtain a logger once and later change its level (or filter) and have every holder of that logger see the change.

A String is always given its own new Logger instance, even when caching is enabled: callers that pass a string typically want an independent logger (for example to set a different level per call site). Anonymous classes (those with no name) are never cached, to avoid pinning short-lived dynamically created classes in memory.



20
21
22
23
24
# File 'lib/semantic_logger/semantic_logger.rb', line 20

def self.[](klass)
  return Logger.new(klass) if !@cache_loggers || klass.is_a?(String) || klass.name.nil?

  logger_cache.compute_if_absent(klass) { Logger.new(klass) }
end

.add_appender(**args) ⇒ Object

Add a new logging appender as a new destination for all log messages emitted from Semantic Logger

Appenders will be written to in the order that they are added

If a block is supplied then it will be used to customize the format of the messages sent to that appender. See SemanticLogger::Logger.new for more information on custom formatters

Parameters file_name: [String] File name to write log messages to.

Or,
io: [IO]
An IO Stream to log to.
For example $stdout, $stderr, etc.

Or,
appender: [Symbol|SemanticLogger::Subscriber]
A symbol identifying the appender to create.
For example:
  :bugsnag, :elasticsearch, :graylog, :http, :mongodb, :new_relic, :splunk_http, :syslog, :wrapper
     Or,
An instance of an appender derived from SemanticLogger::Subscriber
For example:
  SemanticLogger::Appender::Http.new(url: 'http://localhost:8088/path')

Or,
logger: [Logger|Log4r]
An instance of a Logger or a Log4r logger.

level: [:trace | :debug | :info | :warn | :error | :fatal]
Override the log level for this appender.
Default: SemanticLogger.default_level

formatter: [Symbol|Object|Proc]
Any of the following symbol values: :default, :color, :json, :logfmt, etc...
  Or,
An instance of a class that implements #call
  Or,
A Proc to be used to format the output from this appender
Default: :default

filter: [Regexp|Proc]
RegExp: Only include log messages where the class name matches the supplied.
regular expression. All other messages will be ignored.
Proc: Only include log messages where the supplied Proc returns true
      The Proc must return true or false.

Examples:

# Send all logging output to Standard Out (Screen)
SemanticLogger.add_appender(io: $stdout)

# Send all logging output to a file
SemanticLogger.add_appender(file_name: 'logfile.log')

# Send all logging output to a file and only :info and above to standard output
SemanticLogger.add_appender(file_name: 'logfile.log')
SemanticLogger.add_appender(io: $stdout, level: :info)

Log to log4r, Logger, etc.:

# Send Semantic logging output to an existing logger
require 'logger'
require 'semantic_logger'

# Built-in Ruby logger
log = Logger.new($stdout)
log.level = Logger::DEBUG

SemanticLogger.default_level = :debug
SemanticLogger.add_appender(logger: log)

logger = SemanticLogger['Example']
logger.info "Hello World"
logger.debug("Login time", user: 'Joe', duration: 100, ip_address: '127.0.0.1')


198
199
200
201
202
203
# File 'lib/semantic_logger/semantic_logger.rb', line 198

def self.add_appender(**args, &)
  appender = appenders.add(**args, &)
  # Start appender thread if it is not already running
  Logger.processor.start
  appender
end

.add_signal_handler(log_level_signal = "USR2", thread_dump_signal = "TTIN", gc_log_microseconds = 100_000) ⇒ Object

Add signal handlers for Semantic Logger

Two signal handlers will be registered by default:

  1. Changing the log_level:

The log level can be changed without restarting the process by sending the log_level_signal, which by default is 'USR2'

When the log_level_signal is raised on this process, the global default log level
rotates through the following log levels in the following order, starting
from the current global default level:
:fatal, :error, :warn, :info, :debug, :trace

If the current level is :trace it wraps around back to :fatal
  1. Logging a Ruby thread dump

When the signal is raised on this process, Semantic Logger will write the list of threads to the log file, along with their back-traces when available

For JRuby users this thread dump differs form the standard QUIT triggered
Java thread dump which includes system threads and Java stack traces.

It is recommended to name any threads you create in the application, by
calling the following from within the thread itself:
 Thread.current.name = 'My Worker'

Also adds JRuby Garbage collection logging so that any garbage collections that exceed the time threshold will be logged. Default: 100 ms Currently only supported when running JRuby

Note:

To only register one of the signal handlers, set the other to nil
Set gc_log_microseconds to nil to not enable JRuby Garbage collections


340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
# File 'lib/semantic_logger/semantic_logger.rb', line 340

def self.add_signal_handler(log_level_signal = "USR2", thread_dump_signal = "TTIN", gc_log_microseconds = 100_000)
  if log_level_signal
    Signal.trap(log_level_signal) do
      current_level_index = LEVELS.find_index(default_level)
      new_level_index = current_level_index == 0 ? LEVELS.size - 1 : current_level_index - 1
      new_level = LEVELS[new_level_index]
      self.default_level = new_level
      self["SemanticLogger"].warn "Changed global default log level to #{new_level.inspect}"
    end
  end

  if thread_dump_signal
    Signal.trap(thread_dump_signal) do
      logger = SemanticLogger["Thread Dump"]
      Thread.list.each do |thread|
        # MRI re-uses the main thread for signals, JRuby uses `SIGTTIN handler` thread.
        next if defined?(JRuby) && (thread == Thread.current)

        logger.backtrace(thread: thread)
      end
    end
  end

  if gc_log_microseconds && defined?(JRuby)
    listener = SemanticLogger::JRuby::GarbageCollectionLogger.new(gc_log_microseconds)
    Java::JavaLangManagement::ManagementFactory.getGarbageCollectorMXBeans.each do |gcbean|
      gcbean.add_notification_listener(listener, nil, nil)
    end
  end

  true
end

.appendersObject

Returns [SemanticLogger::Subscriber] a copy of the list of active appenders for debugging etc. Use SemanticLogger.add_appender and SemanticLogger.remove_appender to manipulate the active appenders list



223
224
225
# File 'lib/semantic_logger/semantic_logger.rb', line 223

def self.appenders
  Logger.processor.appenders
end

.applicationObject

Returns [String] name of this application for logging purposes Note: Not all appenders use application



97
98
99
# File 'lib/semantic_logger/semantic_logger.rb', line 97

def self.application
  @application
end

.application=(application) ⇒ Object

Override the default application



102
103
104
# File 'lib/semantic_logger/semantic_logger.rb', line 102

def self.application=(application)
  @application = application
end

.backtrace_levelObject

Returns the current backtrace level



74
75
76
# File 'lib/semantic_logger/semantic_logger.rb', line 74

def self.backtrace_level
  @backtrace_level
end

.backtrace_level=(level) ⇒ Object

Sets the level at which backtraces should be captured for every log message.

By enabling backtrace capture the filename and line number of where message was logged can be written to the log file. Additionally, the backtrace can be forwarded to error management services such as Bugsnag.

Warning:

Capturing backtraces is very expensive and should not be done all
the time. It is recommended to run it at :error level in production.


67
68
69
70
71
# File 'lib/semantic_logger/semantic_logger.rb', line 67

def self.backtrace_level=(level)
  @backtrace_level = level
  # For performance reasons pre-calculate the level index
  @backtrace_level_index = level.nil? ? 65_535 : Levels.index(level)
end

.backtrace_level_indexObject

Returns the current backtrace level index For internal use only



80
81
82
# File 'lib/semantic_logger/semantic_logger.rb', line 80

def self.backtrace_level_index
  @backtrace_level_index
end

.cache_loggers=(cache_loggers) ⇒ Object

Whether SemanticLogger[Class] returns a shared, cached Logger instance per class. Disabled by default. Strings are never cached (see #[]).



28
29
30
31
# File 'lib/semantic_logger/semantic_logger.rb', line 28

def self.cache_loggers=(cache_loggers)
  @cache_loggers = cache_loggers
  clear_logger_cache unless cache_loggers
end

.cache_loggers?Boolean

Returns whether logger caching is enabled.

Returns:

  • (Boolean)


34
35
36
# File 'lib/semantic_logger/semantic_logger.rb', line 34

def self.cache_loggers?
  @cache_loggers
end

.clear_appenders!Object

Clear out all previously registered appenders



215
216
217
# File 'lib/semantic_logger/semantic_logger.rb', line 215

def self.clear_appenders!
  Logger.processor.close
end

.clear_logger_cacheObject

Discard all cached loggers so that subsequent SemanticLogger[Class] calls build fresh instances. Primarily useful in tests, or after redefining a class that was previously cached.



41
42
43
# File 'lib/semantic_logger/semantic_logger.rb', line 41

def self.clear_logger_cache
  @logger_cache&.clear
end

.closeObject

Close all appenders and flush any outstanding messages.



234
235
236
# File 'lib/semantic_logger/semantic_logger.rb', line 234

def self.close
  Logger.processor.close
end

.default_levelObject

Returns the global default log level



53
54
55
# File 'lib/semantic_logger/semantic_logger.rb', line 53

def self.default_level
  @default_level
end

.default_level=(level) ⇒ Object

Sets the global default log level



46
47
48
49
50
# File 'lib/semantic_logger/semantic_logger.rb', line 46

def self.default_level=(level)
  @default_level = level
  # For performance reasons pre-calculate the level index
  @default_level_index = Levels.index(level)
end

.default_level_indexObject



579
580
581
# File 'lib/semantic_logger/semantic_logger.rb', line 579

def self.default_level_index
  Thread.current[:semantic_logger_silence] || @default_level_index
end

.environmentObject

Returns [String] name of this environment for logging purposes Note: Not all appenders use environment



108
109
110
# File 'lib/semantic_logger/semantic_logger.rb', line 108

def self.environment
  @environment
end

.environment=(environment) ⇒ Object

Override the default environment



113
114
115
# File 'lib/semantic_logger/semantic_logger.rb', line 113

def self.environment=(environment)
  @environment = environment
end

.fast_tag(tag) ⇒ Object

If the tag being supplied is definitely a string then this fast tag api can be used for short lived tags



375
376
377
378
379
380
381
382
383
384
385
# File 'lib/semantic_logger/semantic_logger.rb', line 375

def self.fast_tag(tag)
  return yield if tag.nil? || tag == ""

  t = Thread.current[:semantic_logger_tags] ||= []
  begin
    t << tag
    yield
  ensure
    t.pop
  end
end

.flushObject

Flush all queued log entries disk, database, etc. All queued log messages are written and then each appender is flushed in turn.



229
230
231
# File 'lib/semantic_logger/semantic_logger.rb', line 229

def self.flush
  Logger.processor.flush
end

.hostObject

Returns [String] name of this host for logging purposes Note: Not all appenders use host



86
87
88
# File 'lib/semantic_logger/semantic_logger.rb', line 86

def self.host
  @host ||= Socket.gethostname.force_encoding("UTF-8")
end

.host=(host) ⇒ Object

Override the default host name



91
92
93
# File 'lib/semantic_logger/semantic_logger.rb', line 91

def self.host=(host)
  @host = host
end

.lag_check_intervalObject

Returns the check_interval which is the number of messages between checks to determine if the appender thread is falling behind.



563
564
565
# File 'lib/semantic_logger/semantic_logger.rb', line 563

def self.lag_check_interval
  Logger.processor.lag_check_interval
end

.lag_check_interval=(lag_check_interval) ⇒ Object

Set the check_interval which is the number of messages between checks to determine if the appender thread is falling behind.



569
570
571
# File 'lib/semantic_logger/semantic_logger.rb', line 569

def self.lag_check_interval=(lag_check_interval)
  Logger.processor.lag_check_interval = lag_check_interval
end

.lag_threshold_sObject

Returns the amount of time in seconds to determine if the appender thread is falling behind.



575
576
577
# File 'lib/semantic_logger/semantic_logger.rb', line 575

def self.lag_threshold_s
  Logger.processor.lag_threshold_s
end

.named_tagged(hash) ⇒ Object

:nodoc

Raises:

  • (ArgumentError)


451
452
453
454
455
456
457
458
459
460
461
# File 'lib/semantic_logger/semantic_logger.rb', line 451

def self.named_tagged(hash)
  return yield if hash.nil? || hash.empty?
  raise(ArgumentError, "#named_tagged only accepts named parameters (Hash)") unless hash.is_a?(Hash)

  begin
    push_named_tags(hash)
    yield
  ensure
    pop_named_tags
  end
end

.named_tagsObject

Returns [Hash] a copy of the named tags currently active for this thread.



464
465
466
467
468
469
470
471
472
473
474
# File 'lib/semantic_logger/semantic_logger.rb', line 464

def self.named_tags
  if (list = Thread.current[:semantic_logger_named_tags]) && !list.empty?
    if list.size > 1
      list.reduce({}) { |sum, h| sum.merge(h) }
    else
      list.first.clone
    end
  else
    {}
  end
end

.on_log(object = nil) ⇒ Object

Supply a callback to be called whenever a log entry is created. Useful for capturing appender specific context information.

Parameters object: [Object | Proc] [Proc] the block to call. [Object] any object on which to call #call.

Example:

SemanticLogger.on_log do |log|
log.set_context(:honeybadger, Honeybadger.get_context)
end

Example:

module CaptureContext
def call(log)
  log.set_context(:honeybadger, Honeybadger.get_context)
end
end
SemanticLogger.on_log(CaptureContext)

Note:

  • This callback is called within the thread of the application making the logging call.
  • If these callbacks are slow they will slow down the application.


301
302
303
# File 'lib/semantic_logger/semantic_logger.rb', line 301

def self.on_log(object = nil, &)
  Logger.subscribe(object, &)
end

.pop_named_tags(quantity = 1) ⇒ Object



481
482
483
484
# File 'lib/semantic_logger/semantic_logger.rb', line 481

def self.pop_named_tags(quantity = 1)
  t = Thread.current[:semantic_logger_named_tags]
  t&.pop(quantity)
end

.pop_tags(quantity = 1) ⇒ Object

Remove specified number of tags from the current tag list



445
446
447
448
# File 'lib/semantic_logger/semantic_logger.rb', line 445

def self.pop_tags(quantity = 1)
  t = Thread.current[:semantic_logger_tags]
  t&.pop(quantity)
end

.push_named_tags(hash) ⇒ Object



476
477
478
479
# File 'lib/semantic_logger/semantic_logger.rb', line 476

def self.push_named_tags(hash)
  (Thread.current[:semantic_logger_named_tags] ||= []) << hash
  hash
end

.push_tags(*tags) ⇒ Object

Add tags to the current scope

Note:

  • This method does not flatten the array or remove any empty elements, or duplicates since the performance penalty is excessive.
  • To get the flattening behavior use the slower api:
    `logger.push_tags`


439
440
441
442
# File 'lib/semantic_logger/semantic_logger.rb', line 439

def self.push_tags(*tags)
  (Thread.current[:semantic_logger_tags] ||= []).concat(tags)
  tags
end

.queue_sizeObject

Returns [Integer] the number of log entries waiting to be written to the appenders.

When this number grows it is because the logging appender thread is not able to write to the appenders fast enough. Either reduce the amount of logging, increase the log level, reduce the number of appenders, or look into speeding up the appenders themselves



536
537
538
# File 'lib/semantic_logger/semantic_logger.rb', line 536

def self.queue_size
  Logger.processor.queue.size
end

.remove_appender(appender) ⇒ Object

Remove an existing appender Currently only supports appender instances



207
208
209
210
211
212
# File 'lib/semantic_logger/semantic_logger.rb', line 207

def self.remove_appender(appender)
  return unless appender

  appenders.delete(appender)
  appender.close
end

.reopen(force: false) ⇒ Object

Re-open any open file handles etc. to resources.

Called automatically in the child process after a fork (see reopen_on_fork?), and may also be called manually.

To avoid reopening twice after a single fork (for example when the automatic fork hook and a framework's after_fork callback both fire), reopen is a no-op if it has already run in the current process. Pass force: true to override this guard and reopen unconditionally, for example when re-opening file handles in the same process after an external log rotation.

Note:

Not all appender's implement reopen.
Check the code for each appender you are using before relying on this behavior.


252
253
254
255
256
257
# File 'lib/semantic_logger/semantic_logger.rb', line 252

def self.reopen(force: false)
  return if !force && @reopened_pid == ::Process.pid

  Logger.processor.reopen
  @reopened_pid = ::Process.pid
end

.reopen_on_fork=(reopen_on_fork) ⇒ Object

Enable or disable automatic reopening of appenders after a fork.

# Opt out of the automatic behavior and manage reopen manually:
SemanticLogger.reopen_on_fork = false


273
274
275
# File 'lib/semantic_logger/semantic_logger.rb', line 273

def self.reopen_on_fork=(reopen_on_fork)
  @reopen_on_fork = reopen_on_fork
end

.reopen_on_fork?Boolean

Whether appenders are automatically reopened in the child process after a fork.

Enabled by default. A Process._fork hook (Ruby 3.1+) calls SemanticLogger.reopen in the child after fork, Process.daemon, IO.popen, Kernel#system, and backticks, so framework specific after_fork hooks (Puma, Unicorn, Resque, Spring, etc.) are no longer required.

Returns:

  • (Boolean)


265
266
267
# File 'lib/semantic_logger/semantic_logger.rb', line 265

def self.reopen_on_fork?
  @reopen_on_fork != false
end

.silence(new_level = :error) ⇒ Object

Silence noisy log levels by changing the default_level within the block

This setting is thread-safe and only applies to the current thread

Any threads spawned within the block will not be affected by this setting

#silence can be used to both raise and lower the log level within the supplied block.

Example:

# Perform trace level logging within the block when the default is higher
SemanticLogger.default_level = :info

logger.debug 'this will _not_ be logged'

SemanticLogger.silence(:trace) do
logger.debug "this will be logged"
end

Parameters new_level The new log level to apply within the block Default: :error

Example:

# Silence all logging for this thread below :error level
SemanticLogger.silence do
logger.info "this will _not_ be logged"
logger.warn "this neither"
logger.error "but errors will be logged"
end

Note:

#silence does not affect any loggers which have had their log level set
explicitly. I.e. That do not rely on the global default level


522
523
524
525
526
527
528
# File 'lib/semantic_logger/semantic_logger.rb', line 522

def self.silence(new_level = :error)
  current_index                            = Thread.current[:semantic_logger_silence]
  Thread.current[:semantic_logger_silence] = Levels.index(new_level)
  yield
ensure
  Thread.current[:semantic_logger_silence] = current_index
end

.statsObject

Returns [Hash] operational statistics for the logging pipeline.

Useful for exporting Semantic Logger's own health to a monitoring system such as Prometheus, statsd, etc. The returned Hash contains:

queue_size:     [Integer] Number of log messages waiting on the main pipeline queue.
capped:         [Boolean] Whether the main queue has a maximum size.
max_queue_size: [Integer] Maximum queue size, or nil when uncapped.
thread_active:  [Boolean] Whether the main pipeline thread is running.
processed:      [Integer] Cumulative number of log messages processed since startup.
dropped:        [Integer] Cumulative number of log messages dropped at the main queue.
appenders:      [Array<Hash>] Per-appender statistics. Appenders that run their own
                            async thread report their queue_size and processed/dropped
                            counts; appenders that log inline report `async: false`.

All counters are cumulative since process startup. They are thread-safe to read and are maintained without adding any locking to the logging hot path.



557
558
559
# File 'lib/semantic_logger/semantic_logger.rb', line 557

def self.stats
  Logger.processor.stats
end

.sync!Object

Run Semantic Logger in Synchronous mode.

I.e. Instead of logging messages in a separate thread for better performance, log them using the current thread.



587
588
589
# File 'lib/semantic_logger/semantic_logger.rb', line 587

def self.sync!
  Logger.sync!
end

.sync?Boolean

Running in synchronous mode?

Returns:

  • (Boolean)


592
593
594
# File 'lib/semantic_logger/semantic_logger.rb', line 592

def self.sync?
  Logger.sync?
end

.tagged(*tags) ⇒ Object

Add the tags or named tags to the list of tags to log for this thread whilst the supplied block is active.

Returns result of block.

Tagged example:

SemanticLogger.tagged(12345, 'jack') do
logger.debug('Hello World')
end

Named Tags (Hash) example:

SemanticLogger.tagged(tracking_number: 12345) do
logger.debug('Hello World')
end

Notes:

  • Tags should be a list without any empty values, or contain any array.
    • logger.tagged is a slower api that will flatten the example below: logger.tagged([['first', nil], nil, ['more'], 'other']) to the equivalent of: logger.tagged('first', 'more', 'other')


407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'lib/semantic_logger/semantic_logger.rb', line 407

def self.tagged(*tags, &)
  return yield if tags.empty?

  # Allow named tags to be passed into the logger
  if tags.size == 1
    tag = tags[0]
    return tag.is_a?(Hash) ? named_tagged(tag, &) : fast_tag(tag, &)
  end

  begin
    push_tags(*tags)
    yield
  ensure
    pop_tags(tags.size)
  end
end

.tagsObject

Returns a copy of the [Array] of [String] tags currently active for this thread Returns nil if no tags are set



426
427
428
429
430
# File 'lib/semantic_logger/semantic_logger.rb', line 426

def self.tags
  # Since tags are stored on a per thread basis this list is thread-safe
  t = Thread.current[:semantic_logger_tags]
  t.nil? ? [] : t.clone
end