Skip to content

Commit ca10594

Browse files
committed
Experimental support for Open telemetry logs
1 parent 364f3b9 commit ca10594

File tree

4 files changed

+132
-12
lines changed

4 files changed

+132
-12
lines changed

lib/semantic_logger/appender.rb

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module Appender
1717
autoload :MongoDB, "semantic_logger/appender/mongodb"
1818
autoload :NewRelic, "semantic_logger/appender/new_relic"
1919
autoload :NewRelicLogs, "semantic_logger/appender/new_relic_logs"
20+
autoload :OpenTelemetry, "semantic_logger/appender/open_telemetry"
2021
autoload :Rabbitmq, "semantic_logger/appender/rabbitmq"
2122
autoload :Splunk, "semantic_logger/appender/splunk"
2223
autoload :SplunkHttp, "semantic_logger/appender/splunk_http"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
begin
2+
require "opentelemetry/logs"
3+
rescue LoadError
4+
raise LoadError, 'Gem opentelemetry-logs-sdk is required for logging to Open Telemetry. Please add the gem "opentelemetry-logs-sdk" to your Gemfile.'
5+
end
6+
7+
# Open Telemetry Appender
8+
#
9+
# Writes log messages, and metrics to Open Telemetry.
10+
#
11+
module SemanticLogger
12+
module Appender
13+
class OpenTelemetry < SemanticLogger::Subscriber
14+
attr_reader :name, :version, :logger
15+
16+
CAPTURE_CONTEXT = ->(log) { log.set_context(:open_telemetry, ::OpenTelemetry::Context.current) }
17+
18+
# Create a Open Telemetry Logger appender instance.
19+
#
20+
# Metric only log events are sent to the Open Telemetry Metrics API instead of the Logs API.
21+
# I.e. A metric without a message or an exception.
22+
# To disable this default behavior set `metrics: false`
23+
#
24+
# Example
25+
# SemanticLogger.add_appender(appender: :open_telemetry)
26+
def initialize(name: "SemanticLogger",
27+
version: SemanticLogger::VERSION,
28+
formatter: SemanticLogger::Formatters::OpenTelemetry.new,
29+
metrics: true,
30+
**args,
31+
&block)
32+
@name = name
33+
@version = version
34+
@logger = ::OpenTelemetry.logger_provider.logger(name: @name, version: @version)
35+
36+
# Capture the current Open Telemetry context when a log entry is captured.
37+
# Prevents duplicate subscribers as long as it is from a constant.
38+
SemanticLogger.on_log(CAPTURE_CONTEXT)
39+
40+
super(formatter: formatter, metrics: metrics, **args, &block)
41+
end
42+
43+
def log(log)
44+
# return log_metric(log) if metrics && log.metric_only?
45+
46+
ap formatter.call(log, self)
47+
ap log.payload
48+
49+
@logger.on_emit(
50+
severity_text: log.level.to_s,
51+
severity_number: severity_number(log.level),
52+
timestamp: log.time,
53+
body: formatter.call(log, self),
54+
attributes: log.payload,
55+
context: log.context[:open_telemetry] || ::OpenTelemetry::Context.current
56+
)
57+
true
58+
end
59+
60+
# Flush all pending logs.
61+
def flush
62+
@logger.logger_provider.force_flush
63+
end
64+
65+
# Flush pending logs and close the appender
66+
def close
67+
@logger.logger_provider.shutdown
68+
end
69+
70+
private
71+
72+
# For logging metrics only log events.
73+
# def log_metric(log)
74+
# puts "**** TODO: Metric Only Event ****"
75+
# ap formatter.call(log, self)
76+
# ap log.payload
77+
# true
78+
# end
79+
80+
def severity_number(severity)
81+
case severity.downcase
82+
when :trace
83+
::OpenTelemetry::Logs::SeverityNumber::SEVERITY_NUMBER_TRACE
84+
when :debug
85+
::OpenTelemetry::Logs::SeverityNumber::SEVERITY_NUMBER_DEBUG
86+
when :info
87+
::OpenTelemetry::Logs::SeverityNumber::SEVERITY_NUMBER_INFO
88+
when :warn
89+
::OpenTelemetry::Logs::SeverityNumber::SEVERITY_NUMBER_WARN
90+
when :error
91+
::OpenTelemetry::Logs::SeverityNumber::SEVERITY_NUMBER_ERROR
92+
when :fatal
93+
::OpenTelemetry::Logs::SeverityNumber::SEVERITY_NUMBER_FATAL
94+
else
95+
::OpenTelemetry::Logs::SeverityNumber::SEVERITY_NUMBER_UNSPECIFIED
96+
end
97+
end
98+
end
99+
end
100+
end

lib/semantic_logger/formatters.rb

+13-12
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
module SemanticLogger
22
module Formatters
3-
autoload :Base, "semantic_logger/formatters/base"
4-
autoload :Color, "semantic_logger/formatters/color"
5-
autoload :Default, "semantic_logger/formatters/default"
6-
autoload :Json, "semantic_logger/formatters/json"
7-
autoload :Raw, "semantic_logger/formatters/raw"
8-
autoload :OneLine, "semantic_logger/formatters/one_line"
9-
autoload :Signalfx, "semantic_logger/formatters/signalfx"
10-
autoload :Syslog, "semantic_logger/formatters/syslog"
11-
autoload :Fluentd, "semantic_logger/formatters/fluentd"
12-
autoload :Logfmt, "semantic_logger/formatters/logfmt"
13-
autoload :SyslogCee, "semantic_logger/formatters/syslog_cee"
14-
autoload :NewRelicLogs, "semantic_logger/formatters/new_relic_logs"
3+
autoload :Base, "semantic_logger/formatters/base"
4+
autoload :Color, "semantic_logger/formatters/color"
5+
autoload :Default, "semantic_logger/formatters/default"
6+
autoload :Json, "semantic_logger/formatters/json"
7+
autoload :Raw, "semantic_logger/formatters/raw"
8+
autoload :OneLine, "semantic_logger/formatters/one_line"
9+
autoload :OpenTelemetry, "semantic_logger/formatters/open_telemetry"
10+
autoload :Signalfx, "semantic_logger/formatters/signalfx"
11+
autoload :Syslog, "semantic_logger/formatters/syslog"
12+
autoload :Fluentd, "semantic_logger/formatters/fluentd"
13+
autoload :Logfmt, "semantic_logger/formatters/logfmt"
14+
autoload :SyslogCee, "semantic_logger/formatters/syslog_cee"
15+
autoload :NewRelicLogs, "semantic_logger/formatters/new_relic_logs"
1516

1617
# Return formatter that responds to call.
1718
#
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
require "json"
2+
module SemanticLogger
3+
module Formatters
4+
class OpenTelemetry < Raw
5+
# Remove the following fields since they are sent via the OpenTelemetry API
6+
def time
7+
end
8+
9+
# Log level
10+
def level
11+
end
12+
13+
# Payload is submitted directly as attributes
14+
def payload
15+
end
16+
end
17+
end
18+
end

0 commit comments

Comments
 (0)