Class: SemanticLogger::Appender::OpenTelemetry

Inherits:
Subscriber
  • Object
show all
Defined in:
lib/semantic_logger/appender/open_telemetry.rb

Constant Summary collapse

CAPTURE_CONTEXT =
->(log) { log.set_context(:open_telemetry, ::OpenTelemetry::Context.current) }

Instance Attribute Summary collapse

Attributes inherited from Subscriber

#application, #environment, #formatter, #host, #metrics

Instance Method Summary collapse

Methods inherited from Subscriber

#batch_by_default?, #console_output?, #console_stream, #default_formatter, #level, #should_log?

Constructor Details

#initialize(name: "SemanticLogger", version: SemanticLogger::VERSION, formatter: SemanticLogger::Formatters::OpenTelemetry.new, metrics: true, **args) ⇒ OpenTelemetry

Create a Open Telemetry Logger appender instance.

Metric only log events are sent to the Open Telemetry Metrics API instead of the Logs API. I.e. A metric without a message or an exception. To disable this default behavior set metrics: false

Example SemanticLogger.add_appender(appender: :open_telemetry)



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/semantic_logger/appender/open_telemetry.rb', line 27

def initialize(name: "SemanticLogger",
               version: SemanticLogger::VERSION,
               formatter: SemanticLogger::Formatters::OpenTelemetry.new,
               metrics: true,
               **args,
               &)
  # Base#initialize (via Subscriber) overwrites @name with the class name,
  # so call super first and then assign our own attributes.
  super(formatter: formatter, metrics: metrics, **args, &)

  @name      = name
  @version   = version
  @provider  = ::OpenTelemetry.logger_provider
  @logger    = @provider.logger(name: @name, version: @version)

  # Capture the current Open Telemetry context when a log entry is captured.
  # Prevents duplicate subscribers as long as it is from a constant.
  SemanticLogger.on_log(CAPTURE_CONTEXT)
end

Instance Attribute Details

#loggerObject (readonly)

Returns the value of attribute logger.



15
16
17
# File 'lib/semantic_logger/appender/open_telemetry.rb', line 15

def logger
  @logger
end

#nameObject (readonly)

Returns the value of attribute name.



15
16
17
# File 'lib/semantic_logger/appender/open_telemetry.rb', line 15

def name
  @name
end

#providerObject (readonly)

Returns the value of attribute provider.



15
16
17
# File 'lib/semantic_logger/appender/open_telemetry.rb', line 15

def provider
  @provider
end

#versionObject (readonly)

Returns the value of attribute version.



15
16
17
# File 'lib/semantic_logger/appender/open_telemetry.rb', line 15

def version
  @version
end

Instance Method Details

#closeObject

Close the appender and release resources.



78
79
80
81
82
83
84
85
86
# File 'lib/semantic_logger/appender/open_telemetry.rb', line 78

def close
  return unless @provider

  @provider.shutdown if @provider.respond_to?(:shutdown)
rescue StandardError => e
  SemanticLogger::Processor.logger.warn("Shutdown failed: #{e.class}: #{e.message}")
ensure
  @provider = nil
end

#flushObject

Flush all pending logs.



68
69
70
71
72
73
74
75
# File 'lib/semantic_logger/appender/open_telemetry.rb', line 68

def flush
  return unless @provider

  @provider.force_flush if @provider.respond_to?(:force_flush)
rescue StandardError => e
  # Swallow to avoid noisy shutdown exceptions.
  SemanticLogger::Processor.logger.warn("Flush failed: #{e.class}: #{e.message}")
end

#log(log) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/semantic_logger/appender/open_telemetry.rb', line 47

def log(log)
  # return log_metric(log) if metrics && log.metric_only?

  body        = formatter.call(log, self)
  level       = body.delete(:level)
  level_index = body.delete(:level_index)
  time        = body.delete(:time)
  payload     = body.delete(:payload)

  @logger.on_emit(
    severity_text:   level,
    severity_number: level_index,
    timestamp:       time,
    body:            body.transform_keys!(&:to_s),
    attributes:      payload,
    context:         (log.context && log.context[:open_telemetry]) || ::OpenTelemetry::Context.current
  )
  true
end