semantic_logger 4.11.0 → 4.14.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|