semantic_logger 4.11.0 → 4.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/lib/semantic_logger/appender/async.rb +1 -1
- data/lib/semantic_logger/appender/async_batch.rb +0 -2
- data/lib/semantic_logger/appender/http.rb +29 -4
- data/lib/semantic_logger/appender/kafka.rb +9 -3
- data/lib/semantic_logger/appender/new_relic_logs.rb +57 -0
- data/lib/semantic_logger/appender/sentry_ruby.rb +1 -1
- data/lib/semantic_logger/appender.rb +1 -0
- data/lib/semantic_logger/base.rb +1 -1
- data/lib/semantic_logger/formatters/base.rb +0 -1
- data/lib/semantic_logger/formatters/logfmt.rb +6 -1
- data/lib/semantic_logger/formatters/new_relic_logs.rb +109 -0
- data/lib/semantic_logger/formatters/syslog_cee.rb +1 -1
- data/lib/semantic_logger/formatters.rb +12 -10
- data/lib/semantic_logger/levels.rb +18 -22
- data/lib/semantic_logger/log.rb +3 -3
- data/lib/semantic_logger/logger.rb +0 -1
- data/lib/semantic_logger/semantic_logger.rb +29 -6
- data/lib/semantic_logger/sync_processor.rb +23 -8
- data/lib/semantic_logger/test/capture_log_events.rb +6 -1
- data/lib/semantic_logger/test/minitest.rb +53 -0
- data/lib/semantic_logger/version.rb +1 -1
- data/lib/semantic_logger.rb +16 -43
- metadata +11 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 966d1357f842de3f83f7b0c479152a401906da47588a8f64525ea0fee406a017
|
4
|
+
data.tar.gz: 3528480641795abc6f38fe4617f4599be81b276ab4184c719b1f6ee7e555fb07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e75514558375d84db0943fbca39295c1011f9def7a86ddc2592c1de7cd0a460c61158ecbdfa35954ec768baa3bfc7b7b068ca802723b6daf64a050a31814c60
|
7
|
+
data.tar.gz: 9c351b2d1eb79c5cfbde72304e6557e0d18526746be4ef3777bb1130a2a675a069321954e617d799c7d6dc2ddc60fd425cc33b9bd9ec148d04931336aa048286
|
data/README.md
CHANGED
@@ -55,6 +55,7 @@ and are therefore not automatically included by this gem:
|
|
55
55
|
- Bugsnag Appender: gem 'bugsnag'
|
56
56
|
- MongoDB Appender: gem 'mongo' 1.9.2 or above
|
57
57
|
- NewRelic Appender: gem 'newrelic_rpm'
|
58
|
+
- NewRelicLogs Appender: gem 'newrelic_rpm'
|
58
59
|
- Syslog Appender: gem 'syslog_protocol' 0.9.2 or above
|
59
60
|
- Syslog Appender to a remote syslogng server over TCP or UDP: gem 'net_tcp_client'
|
60
61
|
- Splunk Appender: gem 'splunk-sdk-ruby'
|
@@ -21,7 +21,7 @@ module SemanticLogger
|
|
21
21
|
class Http < SemanticLogger::Subscriber
|
22
22
|
attr_accessor :username, :compress, :header,
|
23
23
|
:open_timeout, :read_timeout, :continue_timeout
|
24
|
-
attr_reader :http, :url, :server, :port, :path, :ssl_options
|
24
|
+
attr_reader :http, :url, :server, :port, :path, :ssl_options, :proxy_url
|
25
25
|
|
26
26
|
# Create HTTP(S) log appender
|
27
27
|
#
|
@@ -48,6 +48,11 @@ module SemanticLogger
|
|
48
48
|
# password: [String]
|
49
49
|
# Password for basic Authentication.
|
50
50
|
#
|
51
|
+
# header: [Hash]
|
52
|
+
# Custom HTTP headers to send with each request.
|
53
|
+
# Default: {} ( do not send any custom headers)
|
54
|
+
# Example: {"Authorization" => "Bearer BEARER_TOKEN"}
|
55
|
+
#
|
51
56
|
# compress: [true|false]
|
52
57
|
# Whether to compress the JSON string with GZip.
|
53
58
|
# Default: false
|
@@ -57,6 +62,16 @@ module SemanticLogger
|
|
57
62
|
# ca_file, ca_path, cert, cert_store, ciphers, key, ssl_timeout,
|
58
63
|
# ssl_version, verify_callback, verify_depth and verify_mode.
|
59
64
|
#
|
65
|
+
# proxy_url: [String]
|
66
|
+
# URL of proxy server to use for HTTP(s) connections. Should
|
67
|
+
# include username and password if required.
|
68
|
+
# Example: http://user@pass:example.com/some_path
|
69
|
+
# To enable SSL include https in the URL.
|
70
|
+
# Example: https://example.com/some_path
|
71
|
+
# If this is set to :ENV, Net::HTTP will use the environment http_proxy*
|
72
|
+
# variables if they are set. If set to nil then no proxy will be used,
|
73
|
+
# even if the environment variables are set.
|
74
|
+
#
|
60
75
|
# level: [:trace | :debug | :info | :warn | :error | :fatal]
|
61
76
|
# Override the log level for this appender.
|
62
77
|
# Default: SemanticLogger.default_level
|
@@ -85,6 +100,8 @@ module SemanticLogger
|
|
85
100
|
ssl: {},
|
86
101
|
username: nil,
|
87
102
|
password: nil,
|
103
|
+
header: {},
|
104
|
+
proxy_url: :ENV,
|
88
105
|
open_timeout: 2.0,
|
89
106
|
read_timeout: 1.0,
|
90
107
|
continue_timeout: 1.0,
|
@@ -92,6 +109,7 @@ module SemanticLogger
|
|
92
109
|
&block)
|
93
110
|
|
94
111
|
@url = url
|
112
|
+
@proxy_url = proxy_url
|
95
113
|
@ssl_options = ssl
|
96
114
|
@username = username
|
97
115
|
@password = password
|
@@ -106,7 +124,7 @@ module SemanticLogger
|
|
106
124
|
"Content-Type" => "application/json",
|
107
125
|
"Connection" => "keep-alive",
|
108
126
|
"Keep-Alive" => "300"
|
109
|
-
}
|
127
|
+
}.merge(header)
|
110
128
|
@header["Content-Encoding"] = "gzip" if @compress
|
111
129
|
|
112
130
|
uri = URI.parse(@url)
|
@@ -129,6 +147,9 @@ module SemanticLogger
|
|
129
147
|
else
|
130
148
|
@port ||= HTTP.http_default_port
|
131
149
|
end
|
150
|
+
|
151
|
+
@proxy_uri = URI.parse(@proxy_url) if @proxy_url && @proxy_url != :ENV
|
152
|
+
|
132
153
|
@http = nil
|
133
154
|
|
134
155
|
super(**args, &block)
|
@@ -144,7 +165,11 @@ module SemanticLogger
|
|
144
165
|
nil
|
145
166
|
end
|
146
167
|
|
147
|
-
@http =
|
168
|
+
@http = if @proxy_uri
|
169
|
+
Net::HTTP.new(server, port, @proxy_uri.host, @proxy_uri.port, @proxy_uri.user, @proxy_uri.password)
|
170
|
+
else
|
171
|
+
Net::HTTP.new(server, port, @proxy_url)
|
172
|
+
end
|
148
173
|
|
149
174
|
if @ssl_options
|
150
175
|
@http.methods.grep(/\A(\w+)=\z/) do |meth|
|
@@ -207,7 +232,7 @@ module SemanticLogger
|
|
207
232
|
end
|
208
233
|
request.basic_auth(@username, @password) if @username
|
209
234
|
response = @http.request(request)
|
210
|
-
if response.
|
235
|
+
if response.is_a?(Net::HTTPSuccess)
|
211
236
|
true
|
212
237
|
else
|
213
238
|
# Failures are logged to the global semantic logger failsafe logger (Usually stderr or file)
|
@@ -24,7 +24,7 @@ module SemanticLogger
|
|
24
24
|
class Kafka < SemanticLogger::Subscriber
|
25
25
|
attr_accessor :seed_brokers, :client_id, :connect_timeout, :socket_timeout,
|
26
26
|
:ssl_ca_cert, :ssl_client_cert, :ssl_client_cert_key, :ssl_ca_certs_from_system,
|
27
|
-
:delivery_threshold, :delivery_interval,
|
27
|
+
:delivery_threshold, :delivery_interval, :required_acks,
|
28
28
|
:topic, :partition, :partition_key, :key
|
29
29
|
|
30
30
|
# Send log messages to Kafka in JSON format.
|
@@ -90,6 +90,10 @@ module SemanticLogger
|
|
90
90
|
# Number of seconds between triggering a delivery of messages to Apache Kafka.
|
91
91
|
# Default: 5
|
92
92
|
#
|
93
|
+
# required_acks: [Integer]
|
94
|
+
# Number of replicas that must acknowledge receipt of each log message to the topic
|
95
|
+
# Default: 1
|
96
|
+
#
|
93
97
|
# Semantic Logger Parameters:
|
94
98
|
#
|
95
99
|
# level: [:trace | :debug | :info | :warn | :error | :fatal]
|
@@ -121,7 +125,7 @@ module SemanticLogger
|
|
121
125
|
def initialize(seed_brokers:, client_id: "semantic-logger", connect_timeout: nil, socket_timeout: nil,
|
122
126
|
ssl_ca_cert: nil, ssl_client_cert: nil, ssl_client_cert_key: nil, ssl_ca_certs_from_system: false,
|
123
127
|
topic: "log_messages", partition: nil, partition_key: nil, key: nil,
|
124
|
-
delivery_threshold: 100, delivery_interval: 10,
|
128
|
+
delivery_threshold: 100, delivery_interval: 10, required_acks: 1,
|
125
129
|
metrics: true, **args, &block)
|
126
130
|
|
127
131
|
@seed_brokers = seed_brokers
|
@@ -138,6 +142,7 @@ module SemanticLogger
|
|
138
142
|
@key = key
|
139
143
|
@delivery_threshold = delivery_threshold
|
140
144
|
@delivery_interval = delivery_interval
|
145
|
+
@required_acks = required_acks
|
141
146
|
|
142
147
|
super(metrics: metrics, **args, &block)
|
143
148
|
reopen
|
@@ -158,7 +163,8 @@ module SemanticLogger
|
|
158
163
|
|
159
164
|
@producer = @kafka.async_producer(
|
160
165
|
delivery_threshold: delivery_threshold,
|
161
|
-
delivery_interval: delivery_interval
|
166
|
+
delivery_interval: delivery_interval,
|
167
|
+
required_acks: required_acks
|
162
168
|
)
|
163
169
|
end
|
164
170
|
|
@@ -0,0 +1,57 @@
|
|
1
|
+
begin
|
2
|
+
require "newrelic_rpm"
|
3
|
+
rescue LoadError
|
4
|
+
raise LoadError, 'Gem newrelic_rpm is required for logging to New Relic. Please add the gem "newrelic_rpm" to your Gemfile.'
|
5
|
+
end
|
6
|
+
|
7
|
+
require "semantic_logger/formatters/new_relic_logs"
|
8
|
+
|
9
|
+
# Send log messages to NewRelic
|
10
|
+
#
|
11
|
+
# All log entries will appear under
|
12
|
+
# "Logs" in New Relic
|
13
|
+
#
|
14
|
+
# == Caveats
|
15
|
+
#
|
16
|
+
# * The NewRelic agent only sends logs to NewRelic when log forwarding is enabled. There is however an open
|
17
|
+
# issue to get this fixed: https://github.com/newrelic/newrelic-ruby-agent/issues/1614. Please see the guide
|
18
|
+
# for a workaround.
|
19
|
+
#
|
20
|
+
# Example:
|
21
|
+
# SemanticLogger.add_appender(appender: :new_relic_logs)
|
22
|
+
module SemanticLogger
|
23
|
+
module Appender
|
24
|
+
class NewRelicLogs < SemanticLogger::Subscriber
|
25
|
+
# Create Appender
|
26
|
+
#
|
27
|
+
# Parameters
|
28
|
+
# level: [:trace | :debug | :info | :warn | :error | :fatal]
|
29
|
+
# Override the log level for this appender.
|
30
|
+
# Default: SemanticLogger.default_level
|
31
|
+
#
|
32
|
+
# formatter: [Object|Proc]
|
33
|
+
# An instance of a class that implements #call, or a Proc to be used to format
|
34
|
+
# the output from this appender
|
35
|
+
# Default: SemanticLogger::Formatters::NewRelicLogs
|
36
|
+
#
|
37
|
+
# filter: [Regexp|Proc]
|
38
|
+
# RegExp: Only include log messages where the class name matches the supplied.
|
39
|
+
# regular expression. All other messages will be ignored.
|
40
|
+
# Proc: Only include log messages where the supplied Proc returns true
|
41
|
+
# The Proc must return true or false.
|
42
|
+
def initialize(formatter: SemanticLogger::Formatters::NewRelicLogs.new, **args, &block)
|
43
|
+
super(formatter: formatter, **args, &block)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Send an error notification to New Relic
|
47
|
+
def log(log)
|
48
|
+
self.class.log_newrelic(formatter.call(log, self).to_json, log.level.to_s.upcase)
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.log_newrelic(message, level)
|
53
|
+
::NewRelic::Agent.agent.log_event_aggregator.record(message, level)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -40,7 +40,7 @@ module SemanticLogger
|
|
40
40
|
def initialize(level: :error, **args, &block)
|
41
41
|
# Replace the Sentry Ruby logger so that we can identify its log
|
42
42
|
# messages and not forward them to Sentry
|
43
|
-
::Sentry.init { |config| config.logger = SemanticLogger[::Sentry] }
|
43
|
+
::Sentry.init { |config| config.logger = SemanticLogger[::Sentry] } unless ::Sentry.initialized?
|
44
44
|
super(level: level, **args, &block)
|
45
45
|
end
|
46
46
|
|
@@ -15,6 +15,7 @@ module SemanticLogger
|
|
15
15
|
autoload :Http, "semantic_logger/appender/http"
|
16
16
|
autoload :MongoDB, "semantic_logger/appender/mongodb"
|
17
17
|
autoload :NewRelic, "semantic_logger/appender/new_relic"
|
18
|
+
autoload :NewRelicLogs, "semantic_logger/appender/new_relic_logs"
|
18
19
|
autoload :Rabbitmq, "semantic_logger/appender/rabbitmq"
|
19
20
|
autoload :Splunk, "semantic_logger/appender/splunk"
|
20
21
|
autoload :SplunkHttp, "semantic_logger/appender/splunk_http"
|
data/lib/semantic_logger/base.rb
CHANGED
@@ -77,7 +77,7 @@ module SemanticLogger
|
|
77
77
|
# # Log an exception in a semantic way
|
78
78
|
# logger.info("Parsing received XML", exc)
|
79
79
|
#
|
80
|
-
SemanticLogger::LEVELS.each_with_index do |level, index|
|
80
|
+
SemanticLogger::Levels::LEVELS.each_with_index do |level, index|
|
81
81
|
class_eval <<~METHODS, __FILE__, __LINE__ + 1
|
82
82
|
def #{level}(message=nil, payload=nil, exception=nil, &block)
|
83
83
|
if level_index <= #{index}
|
@@ -23,7 +23,6 @@ module SemanticLogger
|
|
23
23
|
# See Time#strftime for the format of this string.
|
24
24
|
# :iso_8601 Outputs an ISO8601 Formatted timestamp.
|
25
25
|
# :ms Output in miliseconds since epoch.
|
26
|
-
# nil: Returns Empty string for time ( no time is output ).
|
27
26
|
# Default: '%Y-%m-%d %H:%M:%S.%<precision>N'
|
28
27
|
# log_host: [Boolean]
|
29
28
|
# Whether or not to include hostname in logs
|
@@ -62,7 +62,12 @@ module SemanticLogger
|
|
62
62
|
|
63
63
|
def flatten_log
|
64
64
|
flattened = @parsed.map do |key, value|
|
65
|
-
|
65
|
+
case value
|
66
|
+
when Hash, Array
|
67
|
+
"#{key}=#{value.to_s.to_json}"
|
68
|
+
else
|
69
|
+
"#{key}=#{value.to_json}"
|
70
|
+
end
|
66
71
|
end
|
67
72
|
|
68
73
|
flattened.join(" ")
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
begin
|
4
|
+
require "newrelic_rpm"
|
5
|
+
rescue LoadError
|
6
|
+
raise LoadError, 'Gem newrelic_rpm is required for logging to New Relic. Please add the gem "newrelic_rpm" to your Gemfile.'
|
7
|
+
end
|
8
|
+
|
9
|
+
raise "NewRelic::Agent.linking_metadata is not defined. Please update newrelic_rpm gem version" unless NewRelic::Agent.respond_to?(:linking_metadata)
|
10
|
+
|
11
|
+
raise "NewRelic::Agent::Tracer.current_span_id is not defined. Please update newrelic_rpm gem version" unless NewRelic::Agent::Tracer.respond_to?(:current_span_id)
|
12
|
+
|
13
|
+
raise "NewRelic::Agent::Tracer.current_trace_id is not defined. Please update newrelic_rpm gem version" unless NewRelic::Agent::Tracer.respond_to?(:current_trace_id)
|
14
|
+
|
15
|
+
module SemanticLogger
|
16
|
+
module Formatters
|
17
|
+
# Formatter for reporting to NewRelic's Logger
|
18
|
+
#
|
19
|
+
# New Relic's logs do not support custom attributes out of the box, and therefore these
|
20
|
+
# have to be put into a single JSON serialized string under the +message+ key.
|
21
|
+
#
|
22
|
+
# In particular the following fields of the log object are serialized under the +message+
|
23
|
+
# key that's sent to NewRelic:
|
24
|
+
#
|
25
|
+
# * message
|
26
|
+
# * tags
|
27
|
+
# * named_tags
|
28
|
+
# * payload
|
29
|
+
# * metric
|
30
|
+
# * metric_amount
|
31
|
+
# * environment
|
32
|
+
# * application
|
33
|
+
#
|
34
|
+
# == New Relic Attributes not Supported
|
35
|
+
# * thread.id
|
36
|
+
# * class.name
|
37
|
+
# * method.name
|
38
|
+
#
|
39
|
+
# == Reference
|
40
|
+
# * Logging specification
|
41
|
+
# * https://github.com/newrelic/newrelic-exporter-specs/tree/master/logging
|
42
|
+
#
|
43
|
+
# * Metadata APIs
|
44
|
+
# * https://www.rubydoc.info/gems/newrelic_rpm/NewRelic/Agent#linking_metadata-instance_method
|
45
|
+
# * https://www.rubydoc.info/gems/newrelic_rpm/NewRelic/Agent/Tracer#current_trace_id-class_method
|
46
|
+
# * https://www.rubydoc.info/gems/newrelic_rpm/NewRelic/Agent/Tracer#current_span_id-class_method
|
47
|
+
#
|
48
|
+
class NewRelicLogs < Raw
|
49
|
+
def initialize(**args)
|
50
|
+
args.delete(:time_key)
|
51
|
+
args.delete(:time_format)
|
52
|
+
|
53
|
+
super(time_key: :timestamp, time_format: :ms, **args)
|
54
|
+
end
|
55
|
+
|
56
|
+
def call(log, logger)
|
57
|
+
hash = super(log, logger)
|
58
|
+
|
59
|
+
message = {
|
60
|
+
message: hash[:message].to_s,
|
61
|
+
tags: hash[:tags] || [],
|
62
|
+
named_tags: hash[:named_tags] || {},
|
63
|
+
|
64
|
+
**hash.slice(:metric, :metric_amount, :environment, :application, :payload)
|
65
|
+
}
|
66
|
+
|
67
|
+
message.merge!(duration: hash[:duration_ms]) if hash.key?(:duration_ms)
|
68
|
+
message.merge!(duration_human: hash[:duration]) if hash.key?(:duration)
|
69
|
+
|
70
|
+
result = {
|
71
|
+
**new_relic_metadata,
|
72
|
+
message: message.to_json,
|
73
|
+
timestamp: hash[:timestamp].to_i,
|
74
|
+
"log.level": log.level.to_s.upcase,
|
75
|
+
"logger.name": log.name,
|
76
|
+
"thread.name": log.thread_name.to_s
|
77
|
+
}
|
78
|
+
|
79
|
+
if hash[:exception]
|
80
|
+
result.merge!(
|
81
|
+
"error.message": hash[:exception][:message],
|
82
|
+
"error.class": hash[:exception][:name],
|
83
|
+
"error.stack": hash[:exception][:stack_trace].join("\n")
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
if hash[:file]
|
88
|
+
result.merge!(
|
89
|
+
"file.name": hash[:file],
|
90
|
+
"line.number": hash[:line].to_s
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
result
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def new_relic_metadata
|
100
|
+
{
|
101
|
+
"trace.id": NewRelic::Agent::Tracer.current_trace_id,
|
102
|
+
"span.id": NewRelic::Agent::Tracer.current_span_id,
|
103
|
+
**NewRelic::Agent.linking_metadata
|
104
|
+
}.reject { |_k, v| v.nil? }.
|
105
|
+
map { |k, v| [k.to_sym, v] }.to_h
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -23,7 +23,7 @@ module SemanticLogger
|
|
23
23
|
#
|
24
24
|
# Example:
|
25
25
|
# # Log via udp to a remote syslog server on host: `server1` and port `8514`, using the CEE format.
|
26
|
-
# SemanticLogger.add_appender(appender: :syslog, formatter: syslog_cee, url: 'udp://server1:8514')
|
26
|
+
# SemanticLogger.add_appender(appender: :syslog, formatter: :syslog_cee, url: 'udp://server1:8514')
|
27
27
|
def initialize(facility: ::Syslog::LOG_USER, level_map: SemanticLogger::Formatters::Syslog::LevelMap.new, max_size: Integer)
|
28
28
|
@facility = facility
|
29
29
|
@level_map = level_map.is_a?(SemanticLogger::Formatters::Syslog::LevelMap) ? level_map : SemanticLogger::Formatters::Syslog::LevelMap.new(level_map)
|
@@ -1,15 +1,17 @@
|
|
1
1
|
module SemanticLogger
|
2
2
|
module Formatters
|
3
|
-
autoload :Base,
|
4
|
-
autoload :Color,
|
5
|
-
autoload :Default,
|
6
|
-
autoload :Json,
|
7
|
-
autoload :Raw,
|
8
|
-
autoload :OneLine,
|
9
|
-
autoload :Signalfx,
|
10
|
-
autoload :Syslog,
|
11
|
-
autoload :Fluentd,
|
12
|
-
autoload :Logfmt,
|
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"
|
13
15
|
|
14
16
|
# Return formatter that responds to call.
|
15
17
|
#
|
@@ -1,35 +1,31 @@
|
|
1
|
+
require "logger"
|
2
|
+
|
1
3
|
module SemanticLogger
|
2
4
|
module Levels
|
3
5
|
# Logging levels in order of most detailed to most severe
|
4
6
|
LEVELS = %i[trace debug info warn error fatal].freeze
|
5
7
|
|
8
|
+
# Map the built-in `Logger` levels to SemanticLogger levels.
|
9
|
+
MAPPED_LEVELS =
|
10
|
+
::Logger::Severity.constants.each_with_object([]) do |constant, levels|
|
11
|
+
logger_value = ::Logger::Severity.const_get(constant)
|
12
|
+
levels[logger_value] = LEVELS.find_index(constant.downcase.to_sym) || LEVELS.find_index(:error)
|
13
|
+
end.freeze
|
14
|
+
|
6
15
|
# Internal method to return the log level as an internal index
|
7
16
|
# Also supports mapping the ::Logger levels to SemanticLogger levels
|
8
17
|
def self.index(level)
|
9
18
|
return if level.nil?
|
10
19
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
begin
|
21
|
-
levels = []
|
22
|
-
::Logger::Severity.constants.each do |constant|
|
23
|
-
levels[::Logger::Severity.const_get(constant)] =
|
24
|
-
LEVELS.find_index(constant.downcase.to_sym) || LEVELS.find_index(:error)
|
25
|
-
end
|
26
|
-
levels
|
27
|
-
end
|
28
|
-
@map_levels[level]
|
29
|
-
end
|
30
|
-
raise "Invalid level:#{level.inspect} being requested. Must be one of #{LEVELS.inspect}" unless index
|
31
|
-
|
32
|
-
index
|
20
|
+
case level
|
21
|
+
when Symbol
|
22
|
+
LEVELS.index(level)
|
23
|
+
when String
|
24
|
+
LEVELS.index(level.downcase.to_sym)
|
25
|
+
when Integer
|
26
|
+
MAPPED_LEVELS[level]
|
27
|
+
end ||
|
28
|
+
raise(ArgumentError, "Invalid level:#{level.inspect} being requested. Must be one of #{LEVELS.inspect}")
|
33
29
|
end
|
34
30
|
|
35
31
|
# Returns the symbolic level for the supplied level index
|
data/lib/semantic_logger/log.rb
CHANGED
@@ -219,11 +219,11 @@ module SemanticLogger
|
|
219
219
|
|
220
220
|
seconds = duration / 1000
|
221
221
|
if seconds >= 86_400.0 # 1 day
|
222
|
-
"#{(seconds / 86_400).to_i}d #{Time.at(seconds).strftime('%-Hh %-Mm')}"
|
222
|
+
"#{(seconds / 86_400).to_i}d #{Time.at(seconds).utc.strftime('%-Hh %-Mm')}"
|
223
223
|
elsif seconds >= 3600.0 # 1 hour
|
224
|
-
Time.at(seconds).strftime("%-Hh %-Mm")
|
224
|
+
Time.at(seconds).utc.strftime("%-Hh %-Mm")
|
225
225
|
elsif seconds >= 60.0 # 1 minute
|
226
|
-
Time.at(seconds).strftime("%-Mm %-Ss")
|
226
|
+
Time.at(seconds).utc.strftime("%-Mm %-Ss")
|
227
227
|
elsif seconds >= 1.0 # 1 second
|
228
228
|
"#{format('%.3f', seconds)}s"
|
229
229
|
else
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require "concurrent"
|
2
1
|
require "socket"
|
3
2
|
|
4
3
|
module SemanticLogger
|
@@ -253,9 +252,9 @@ module SemanticLogger
|
|
253
252
|
# When the log_level_signal is raised on this process, the global default log level
|
254
253
|
# rotates through the following log levels in the following order, starting
|
255
254
|
# from the current global default level:
|
256
|
-
# :warn, :info, :debug, :trace
|
255
|
+
# :fatal, :error, :warn, :info, :debug, :trace
|
257
256
|
#
|
258
|
-
# If the current level is :trace it wraps around back to :
|
257
|
+
# If the current level is :trace it wraps around back to :fatal
|
259
258
|
#
|
260
259
|
# 2. Logging a Ruby thread dump
|
261
260
|
#
|
@@ -279,10 +278,11 @@ module SemanticLogger
|
|
279
278
|
def self.add_signal_handler(log_level_signal = "USR2", thread_dump_signal = "TTIN", gc_log_microseconds = 100_000)
|
280
279
|
if log_level_signal
|
281
280
|
Signal.trap(log_level_signal) do
|
282
|
-
|
283
|
-
|
284
|
-
|
281
|
+
current_level_index = LEVELS.find_index(default_level)
|
282
|
+
new_level_index = current_level_index == 0 ? LEVELS.size - 1 : current_level_index - 1
|
283
|
+
new_level = LEVELS[new_level_index]
|
285
284
|
self.default_level = new_level
|
285
|
+
self["SemanticLogger"].warn "Changed global default log level to #{new_level.inspect}"
|
286
286
|
end
|
287
287
|
end
|
288
288
|
|
@@ -516,4 +516,27 @@ module SemanticLogger
|
|
516
516
|
@backtrace_level = :error
|
517
517
|
@backtrace_level_index = Levels.index(@backtrace_level)
|
518
518
|
@sync = false
|
519
|
+
|
520
|
+
# @formatter:off
|
521
|
+
module Metric
|
522
|
+
autoload :NewRelic, "semantic_logger/metric/new_relic"
|
523
|
+
autoload :Signalfx, "semantic_logger/metric/signalfx"
|
524
|
+
autoload :Statsd, "semantic_logger/metric/statsd"
|
525
|
+
end
|
526
|
+
|
527
|
+
module Reporters
|
528
|
+
autoload :Minitest, "semantic_logger/reporters/minitest"
|
529
|
+
end
|
530
|
+
|
531
|
+
module Test
|
532
|
+
autoload :CaptureLogEvents, "semantic_logger/test/capture_log_events"
|
533
|
+
autoload :Minitest, "semantic_logger/test/minitest"
|
534
|
+
end
|
535
|
+
|
536
|
+
if defined?(JRuby)
|
537
|
+
module JRuby
|
538
|
+
autoload :GarbageCollectionLogger, "semantic_logger/jruby/garbage_collection_logger"
|
539
|
+
end
|
540
|
+
end
|
541
|
+
# @formatter:on
|
519
542
|
end
|
@@ -1,14 +1,28 @@
|
|
1
1
|
module SemanticLogger
|
2
|
-
#
|
2
|
+
# The SyncProcessor performs logging in the current thread.
|
3
|
+
#
|
4
|
+
# Appenders are designed to only be used by one thread at a time, so all calls
|
5
|
+
# are mutex protected in case SyncProcessor is being used in a multi-threaded environment.
|
3
6
|
class SyncProcessor
|
4
|
-
|
7
|
+
def add(*args, &block)
|
8
|
+
@mutex.synchronize { @appenders.add(*args, &block) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def log(*args, &block)
|
12
|
+
@mutex.synchronize { @appenders.log(*args, &block) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def flush
|
16
|
+
@mutex.synchronize { @appenders.flush }
|
17
|
+
end
|
18
|
+
|
19
|
+
def close
|
20
|
+
@mutex.synchronize { @appenders.close }
|
21
|
+
end
|
5
22
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
def_delegator :@appenders, :flush
|
10
|
-
def_delegator :@appenders, :close
|
11
|
-
def_delegator :@appenders, :reopen
|
23
|
+
def reopen(*args)
|
24
|
+
@mutex.synchronize { @appenders.reopen(*args) }
|
25
|
+
end
|
12
26
|
|
13
27
|
# Allow the internal logger to be overridden from its default of $stderr
|
14
28
|
# Can be replaced with another Ruby logger or Rails logger, but never to
|
@@ -33,6 +47,7 @@ module SemanticLogger
|
|
33
47
|
attr_reader :appenders
|
34
48
|
|
35
49
|
def initialize(appenders = nil)
|
50
|
+
@mutex = Mutex.new
|
36
51
|
@appenders = appenders || Appenders.new(self.class.logger.dup)
|
37
52
|
end
|
38
53
|
|
@@ -24,10 +24,15 @@ module SemanticLogger
|
|
24
24
|
# By default collect all log levels, and collect metric only log events.
|
25
25
|
def initialize(level: :trace, metrics: true)
|
26
26
|
super(level: level, metrics: true)
|
27
|
+
@events = []
|
27
28
|
end
|
28
29
|
|
29
30
|
def log(log)
|
30
|
-
|
31
|
+
@events << log
|
32
|
+
end
|
33
|
+
|
34
|
+
def clear
|
35
|
+
@events.clear
|
31
36
|
end
|
32
37
|
end
|
33
38
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module SemanticLogger
|
2
|
+
module Test
|
3
|
+
module Minitest
|
4
|
+
# Returns [Array<SemanticLogger::Log>] the log events from Semantic Logger
|
5
|
+
# captured whilst executing the supplied block.
|
6
|
+
def semantic_logger_events(klass = nil, &block)
|
7
|
+
logger = SemanticLogger::Test::CaptureLogEvents.new
|
8
|
+
if klass
|
9
|
+
klass.stub(:logger, logger, &block)
|
10
|
+
else
|
11
|
+
SemanticLogger.silence(:trace) do
|
12
|
+
SemanticLogger::Logger.stub(:processor, logger, &block)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
logger.events
|
16
|
+
end
|
17
|
+
|
18
|
+
# Verify a single log event has all the required attributes.
|
19
|
+
def assert_semantic_logger_event(event, level: nil, name: nil, message: nil, message_includes: nil,
|
20
|
+
payload: nil, payload_includes: nil,
|
21
|
+
thread_name: nil, tags: nil, named_tags: nil, context: nil,
|
22
|
+
metric: nil, metric_amount: nil, dimensions: nil)
|
23
|
+
msg = message || message_includes || "no message"
|
24
|
+
assert event, "Log event missing for message: '#{msg}'"
|
25
|
+
assert_equal message, event.message if message
|
26
|
+
assert_includes event.message, message_includes if message_includes
|
27
|
+
assert_equal name, event.name, -> { "Mismatched log name for message: '#{msg}'" } if name
|
28
|
+
assert_equal level, event.level, -> { "Mismatched log level for message: '#{msg}'" } if level
|
29
|
+
|
30
|
+
if payload_includes
|
31
|
+
payload_includes.each_pair do |key, expected_value|
|
32
|
+
value = event.payload[key]
|
33
|
+
if expected_value.nil?
|
34
|
+
assert_nil value, -> { "Mismatched key: #{key.inspect} in log payload: #{event.payload} for message: '#{msg}'" }
|
35
|
+
else
|
36
|
+
assert_equal expected_value, value, -> { "Mismatched key: #{key.inspect} in log payload: #{event.payload} for message: '#{msg}'" }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
elsif payload
|
40
|
+
assert_equal payload, event.payload, -> { "Mismatched log payload: #{event.payload} for message: '#{msg}'" }
|
41
|
+
end
|
42
|
+
|
43
|
+
assert_equal thread_name, event.thread_name, -> { "Mismatched thread_name for message: '#{msg}'" } if thread_name
|
44
|
+
assert_equal tags, event.tags, -> { "Mismatched tags for message: '#{msg}'" } if tags
|
45
|
+
assert_equal named_tags, event.named_tags, -> { "Mismatched named_tags for message: '#{msg}'" } if named_tags
|
46
|
+
assert_equal context, event.context, -> { "Mismatched context for message: '#{msg}'" } if context
|
47
|
+
assert_equal metric, event.metric, -> { "Mismatched metric for message: '#{msg}'" } if metric
|
48
|
+
assert_equal metric_amount, event.metric_amount, -> { "Mismatched metric_amount for message: '#{msg}'" } if metric_amount
|
49
|
+
assert_equal dimensions, event.dimensions, -> { "Mismatched dimensions for message: '#{msg}'" } if dimensions
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/semantic_logger.rb
CHANGED
@@ -1,49 +1,22 @@
|
|
1
|
+
require "concurrent"
|
1
2
|
require "semantic_logger/core_ext/thread"
|
2
3
|
require "semantic_logger/version"
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
autoload :SyncProcessor, "semantic_logger/sync_processor"
|
19
|
-
autoload :Utils, "semantic_logger/utils"
|
20
|
-
|
21
|
-
module Concerns
|
22
|
-
autoload :Compatibility, "semantic_logger/concerns/compatibility"
|
23
|
-
end
|
24
|
-
|
25
|
-
module Metric
|
26
|
-
autoload :NewRelic, "semantic_logger/metric/new_relic"
|
27
|
-
autoload :Signalfx, "semantic_logger/metric/signalfx"
|
28
|
-
autoload :Statsd, "semantic_logger/metric/statsd"
|
29
|
-
end
|
30
|
-
|
31
|
-
module Reporters
|
32
|
-
autoload :Minitest, "semantic_logger/reporters/minitest"
|
33
|
-
end
|
34
|
-
|
35
|
-
module Test
|
36
|
-
autoload :CaptureLogEvents, "semantic_logger/test/capture_log_events"
|
37
|
-
end
|
38
|
-
|
39
|
-
if defined?(JRuby)
|
40
|
-
module JRuby
|
41
|
-
autoload :GarbageCollectionLogger, "semantic_logger/jruby/garbage_collection_logger"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
4
|
+
require "semantic_logger/utils"
|
5
|
+
require "semantic_logger/ansi_colors"
|
6
|
+
require "semantic_logger/levels"
|
7
|
+
require "semantic_logger/base"
|
8
|
+
require "semantic_logger/formatters"
|
9
|
+
require "semantic_logger/log"
|
10
|
+
require "semantic_logger/subscriber"
|
11
|
+
require "semantic_logger/loggable"
|
12
|
+
require "semantic_logger/concerns/compatibility"
|
13
|
+
require "semantic_logger/appender"
|
14
|
+
require "semantic_logger/appenders"
|
15
|
+
require "semantic_logger/processor"
|
16
|
+
require "semantic_logger/sync_processor"
|
17
|
+
require "semantic_logger/logger"
|
18
|
+
require "semantic_logger/debug_as_trace_logger"
|
45
19
|
require "semantic_logger/semantic_logger"
|
46
|
-
# @formatter:on
|
47
20
|
|
48
21
|
# Flush all appenders at exit, waiting for outstanding messages on the queue
|
49
22
|
# to be written first.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: semantic_logger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Reid Morrison
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-07-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -49,6 +49,7 @@ files:
|
|
49
49
|
- lib/semantic_logger/appender/kafka.rb
|
50
50
|
- lib/semantic_logger/appender/mongodb.rb
|
51
51
|
- lib/semantic_logger/appender/new_relic.rb
|
52
|
+
- lib/semantic_logger/appender/new_relic_logs.rb
|
52
53
|
- lib/semantic_logger/appender/rabbitmq.rb
|
53
54
|
- lib/semantic_logger/appender/sentry.rb
|
54
55
|
- lib/semantic_logger/appender/sentry_ruby.rb
|
@@ -70,6 +71,7 @@ files:
|
|
70
71
|
- lib/semantic_logger/formatters/fluentd.rb
|
71
72
|
- lib/semantic_logger/formatters/json.rb
|
72
73
|
- lib/semantic_logger/formatters/logfmt.rb
|
74
|
+
- lib/semantic_logger/formatters/new_relic_logs.rb
|
73
75
|
- lib/semantic_logger/formatters/one_line.rb
|
74
76
|
- lib/semantic_logger/formatters/raw.rb
|
75
77
|
- lib/semantic_logger/formatters/signalfx.rb
|
@@ -90,12 +92,17 @@ files:
|
|
90
92
|
- lib/semantic_logger/sync.rb
|
91
93
|
- lib/semantic_logger/sync_processor.rb
|
92
94
|
- lib/semantic_logger/test/capture_log_events.rb
|
95
|
+
- lib/semantic_logger/test/minitest.rb
|
93
96
|
- lib/semantic_logger/utils.rb
|
94
97
|
- lib/semantic_logger/version.rb
|
95
98
|
homepage: https://logger.rocketjob.io
|
96
99
|
licenses:
|
97
100
|
- Apache-2.0
|
98
|
-
metadata:
|
101
|
+
metadata:
|
102
|
+
bug_tracker_uri: https://github.com/reidmorrison/semantic_logger/issues
|
103
|
+
documentation_uri: https://logger.rocketjob.io
|
104
|
+
source_code_uri: https://github.com/reidmorrison/semantic_logger/tree/4.14.0
|
105
|
+
rubygems_mfa_required: 'true'
|
99
106
|
post_install_message:
|
100
107
|
rdoc_options: []
|
101
108
|
require_paths:
|
@@ -111,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
118
|
- !ruby/object:Gem::Version
|
112
119
|
version: '0'
|
113
120
|
requirements: []
|
114
|
-
rubygems_version: 3.
|
121
|
+
rubygems_version: 3.4.9
|
115
122
|
signing_key:
|
116
123
|
specification_version: 4
|
117
124
|
summary: Feature rich logging framework, and replacement for existing Ruby & Rails
|