semantic_logger 4.2.0 → 4.2.1
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 +3 -3
- data/Rakefile +1 -1
- data/lib/semantic_logger/ansi_colors.rb +11 -12
- data/lib/semantic_logger/appender.rb +4 -5
- data/lib/semantic_logger/appender/async.rb +24 -16
- data/lib/semantic_logger/appender/async_batch.rb +1 -4
- data/lib/semantic_logger/appender/bugsnag.rb +67 -63
- data/lib/semantic_logger/appender/elasticsearch.rb +154 -157
- data/lib/semantic_logger/appender/elasticsearch_http.rb +59 -55
- data/lib/semantic_logger/appender/file.rb +1 -3
- data/lib/semantic_logger/appender/graylog.rb +114 -110
- data/lib/semantic_logger/appender/honeybadger.rb +54 -51
- data/lib/semantic_logger/appender/http.rb +194 -190
- data/lib/semantic_logger/appender/kafka.rb +152 -149
- data/lib/semantic_logger/appender/mongodb.rb +3 -3
- data/lib/semantic_logger/appender/new_relic.rb +52 -49
- data/lib/semantic_logger/appender/sentry.rb +59 -54
- data/lib/semantic_logger/appender/splunk.rb +108 -103
- data/lib/semantic_logger/appender/splunk_http.rb +82 -79
- data/lib/semantic_logger/appender/syslog.rb +4 -5
- data/lib/semantic_logger/appender/tcp.rb +8 -29
- data/lib/semantic_logger/appender/udp.rb +2 -3
- data/lib/semantic_logger/appender/wrapper.rb +2 -2
- data/lib/semantic_logger/base.rb +18 -16
- data/lib/semantic_logger/concerns/compatibility.rb +0 -1
- data/lib/semantic_logger/core_ext/thread.rb +0 -1
- data/lib/semantic_logger/formatters.rb +3 -5
- data/lib/semantic_logger/formatters/base.rb +2 -3
- data/lib/semantic_logger/formatters/color.rb +29 -12
- data/lib/semantic_logger/formatters/default.rb +10 -10
- data/lib/semantic_logger/formatters/json.rb +0 -2
- data/lib/semantic_logger/formatters/one_line.rb +2 -2
- data/lib/semantic_logger/formatters/raw.rb +7 -10
- data/lib/semantic_logger/formatters/signalfx.rb +3 -5
- data/lib/semantic_logger/formatters/syslog.rb +2 -3
- data/lib/semantic_logger/formatters/syslog_cee.rb +2 -3
- data/lib/semantic_logger/jruby/garbage_collection_logger.rb +8 -5
- data/lib/semantic_logger/log.rb +17 -17
- data/lib/semantic_logger/loggable.rb +6 -9
- data/lib/semantic_logger/logger.rb +0 -1
- data/lib/semantic_logger/metric/new_relic.rb +58 -55
- data/lib/semantic_logger/metric/signalfx.rb +108 -106
- data/lib/semantic_logger/metric/statsd.rb +2 -3
- data/lib/semantic_logger/processor.rb +9 -9
- data/lib/semantic_logger/semantic_logger.rb +50 -30
- data/lib/semantic_logger/subscriber.rb +0 -1
- data/lib/semantic_logger/utils.rb +37 -37
- data/lib/semantic_logger/version.rb +2 -2
- data/test/appender/async_batch_test.rb +0 -1
- data/test/appender/async_test.rb +0 -1
- data/test/appender/bugsnag_test.rb +7 -8
- data/test/appender/elasticsearch_http_test.rb +5 -6
- data/test/appender/elasticsearch_test.rb +14 -10
- data/test/appender/file_test.rb +5 -6
- data/test/appender/graylog_test.rb +8 -8
- data/test/appender/honeybadger_test.rb +6 -7
- data/test/appender/http_test.rb +4 -5
- data/test/appender/kafka_test.rb +5 -6
- data/test/appender/mongodb_test.rb +11 -13
- data/test/appender/new_relic_test.rb +8 -9
- data/test/appender/newrelic_rpm.rb +1 -1
- data/test/appender/sentry_test.rb +7 -8
- data/test/appender/splunk_http_test.rb +4 -4
- data/test/appender/splunk_test.rb +1 -3
- data/test/appender/syslog_test.rb +3 -5
- data/test/appender/tcp_test.rb +4 -5
- data/test/appender/udp_test.rb +4 -5
- data/test/appender/wrapper_test.rb +2 -3
- data/test/concerns/compatibility_test.rb +0 -1
- data/test/debug_as_trace_logger_test.rb +0 -1
- data/test/formatters/color_test.rb +5 -6
- data/test/formatters/default_test.rb +16 -17
- data/test/formatters/one_line_test.rb +1 -2
- data/test/formatters/signalfx_test.rb +8 -11
- data/test/formatters_test.rb +3 -3
- data/test/in_memory_appender.rb +0 -1
- data/test/in_memory_appender_helper.rb +1 -1
- data/test/in_memory_batch_appender.rb +0 -1
- data/test/in_memory_metrics_appender.rb +0 -1
- data/test/loggable_test.rb +2 -3
- data/test/logger_test.rb +11 -14
- data/test/measure_test.rb +13 -15
- data/test/metric/new_relic_test.rb +2 -3
- data/test/metric/signalfx_test.rb +4 -5
- data/test/semantic_logger_test.rb +28 -3
- data/test/test_helper.rb +6 -7
- metadata +34 -34
@@ -30,7 +30,6 @@
|
|
30
30
|
# ExternalSupplier.prepend SemanticLogger::Loggable
|
31
31
|
module SemanticLogger
|
32
32
|
module Loggable
|
33
|
-
|
34
33
|
def self.included(base)
|
35
34
|
base.extend ClassMethods
|
36
35
|
base.class_eval do
|
@@ -85,14 +84,14 @@ module SemanticLogger
|
|
85
84
|
|
86
85
|
index = SemanticLogger.level_to_index(level)
|
87
86
|
|
88
|
-
logger_measure_module.module_eval(
|
87
|
+
logger_measure_module.module_eval(<<~MEASURE_METHOD, __FILE__, __LINE__ + 1)
|
89
88
|
def #{method_name}(*args, &block)
|
90
89
|
if logger.send(:level_index) <= #{index}
|
91
90
|
logger.send(
|
92
91
|
:measure_method,
|
93
|
-
index: #{index},
|
94
|
-
level: #{level.inspect},
|
95
|
-
message: #{message.inspect},
|
92
|
+
index: #{index},
|
93
|
+
level: #{level.inspect},
|
94
|
+
message: #{message.inspect},
|
96
95
|
min_duration: #{min_duration},
|
97
96
|
metric: #{metric.inspect},
|
98
97
|
log_exception: #{log_exception.inspect},
|
@@ -104,8 +103,8 @@ module SemanticLogger
|
|
104
103
|
super(*args, &block)
|
105
104
|
end
|
106
105
|
end
|
107
|
-
|
108
|
-
#{"#{visibility} :#{method_name}" unless visibility == :public}
|
106
|
+
MEASURE_METHOD
|
107
|
+
# {"#{visibility} :#{method_name}" unless visibility == :public}
|
109
108
|
true
|
110
109
|
end
|
111
110
|
|
@@ -121,8 +120,6 @@ module SemanticLogger
|
|
121
120
|
mod
|
122
121
|
end
|
123
122
|
end
|
124
|
-
|
125
123
|
end
|
126
|
-
|
127
124
|
end
|
128
125
|
end
|
@@ -11,65 +11,68 @@ end
|
|
11
11
|
#
|
12
12
|
# Example:
|
13
13
|
# SemanticLogger.add_appender(metric: :new_relic)
|
14
|
-
|
15
|
-
|
14
|
+
module SemanticLogger
|
15
|
+
module Metric
|
16
|
+
class NewRelic < SemanticLogger::Subscriber
|
17
|
+
attr_accessor :prefix
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
19
|
+
# Create Appender
|
20
|
+
#
|
21
|
+
# Parameters
|
22
|
+
# :prefix [String]
|
23
|
+
# Prefix to add to every metric before forwarding to NewRelic.
|
24
|
+
# Default: 'Custom'
|
25
|
+
#
|
26
|
+
# level: [:trace | :debug | :info | :warn | :error | :fatal]
|
27
|
+
# Override the log level for this appender.
|
28
|
+
# Default: :error
|
29
|
+
#
|
30
|
+
# formatter: [Object|Proc]
|
31
|
+
# An instance of a class that implements #call, or a Proc to be used to format
|
32
|
+
# the output from this appender
|
33
|
+
# Default: Use the built-in formatter (See: #call)
|
34
|
+
#
|
35
|
+
# filter: [Regexp|Proc]
|
36
|
+
# RegExp: Only include log messages where the class name matches the supplied.
|
37
|
+
# regular expression. All other messages will be ignored.
|
38
|
+
# Proc: Only include log messages where the supplied Proc returns true
|
39
|
+
# The Proc must return true or false.
|
40
|
+
def initialize(prefix: 'Custom',
|
41
|
+
level: nil,
|
42
|
+
formatter: nil,
|
43
|
+
filter: nil,
|
44
|
+
application: nil,
|
45
|
+
host: nil,
|
46
|
+
&block)
|
45
47
|
|
46
|
-
|
47
|
-
|
48
|
-
|
48
|
+
@prefix = prefix
|
49
|
+
super(level: level, formatter: formatter, filter: filter, application: application, host: host, &block)
|
50
|
+
end
|
49
51
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
52
|
+
# Returns metric name to use.
|
53
|
+
def call(log, _logger)
|
54
|
+
metric = log.metric
|
55
|
+
# Add prefix for NewRelic
|
56
|
+
metric = "#{prefix}/#{metric}" unless metric.start_with?(prefix)
|
57
|
+
metric
|
58
|
+
end
|
57
59
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
60
|
+
def log(log)
|
61
|
+
name = formatter.call(log, self)
|
62
|
+
if (duration = log.duration)
|
63
|
+
# Convert duration to seconds
|
64
|
+
::NewRelic::Agent.record_metric(name, duration / 1000.0)
|
65
|
+
else
|
66
|
+
::NewRelic::Agent.increment_metric(name, log.metric_amount || 1)
|
67
|
+
end
|
68
|
+
true
|
69
|
+
end
|
68
70
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
71
|
+
# Only forward log entries that contain metrics.
|
72
|
+
def should_log?(log)
|
73
|
+
# Does not support metrics with dimensions.
|
74
|
+
log.metric && !log.dimensions && meets_log_level?(log) && !filtered?(log)
|
75
|
+
end
|
76
|
+
end
|
73
77
|
end
|
74
|
-
|
75
78
|
end
|
@@ -5,119 +5,121 @@
|
|
5
5
|
# metric: :signalfx,
|
6
6
|
# token: 'SIGNALFX_ORG_ACCESS_TOKEN'
|
7
7
|
# )
|
8
|
-
|
9
|
-
|
8
|
+
module SemanticLogger
|
9
|
+
module Metric
|
10
|
+
class Signalfx < SemanticLogger::Appender::Http
|
11
|
+
attr_reader :full_url
|
10
12
|
|
11
|
-
|
13
|
+
END_POINT = 'v2/datapoint'.freeze
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
15
|
+
# Create SignalFx metrics appender.
|
16
|
+
#
|
17
|
+
# Parameters:
|
18
|
+
# token: [String]
|
19
|
+
# Access Token to use for sending metrics.
|
20
|
+
# Obtain the Signalfx token via the Signalfx Web UI under `Organization` -> `Access Tokens`.
|
21
|
+
#
|
22
|
+
# dimensions: [Array<String>]
|
23
|
+
# Dimensions to forward to signalfx when they are present in the named tags of any log message.
|
24
|
+
# By default `application` and `host` are always included as dimensions in all forwarded metrics.
|
25
|
+
# Example: [:user_id, :state]
|
26
|
+
#
|
27
|
+
# filter: [Regexp|Proc]
|
28
|
+
# RegExp: Only include log messages where the class name matches the supplied
|
29
|
+
# regular expression. All other messages will be ignored.
|
30
|
+
# Proc: Only include log messages where the supplied Proc returns true.
|
31
|
+
# The Proc must return true or false.
|
32
|
+
#
|
33
|
+
# host: [String]
|
34
|
+
# Name of this host to send as a dimension.
|
35
|
+
# Default: SemanticLogger.host
|
36
|
+
#
|
37
|
+
# application: [String]
|
38
|
+
# Name of this application to send as a dimension.
|
39
|
+
# Default: SemanticLogger.application
|
40
|
+
#
|
41
|
+
# url: [String]
|
42
|
+
# Override the SignalFx service url.
|
43
|
+
# For historical data use: https://backfill.signalfx.com/v1/backfill
|
44
|
+
# Default: https://ingest.signalfx.com
|
45
|
+
#
|
46
|
+
# Notes:
|
47
|
+
#
|
48
|
+
# When sending a metric to Signalfx, it is necessary to send both a `gauge` and a `counter` when a
|
49
|
+
# duration is included in the metric, otherwise it is not possible to chart counts of the metric.
|
50
|
+
# Unfortunately this doubles the number of metrics, but it is the way Signalfx works.
|
51
|
+
# Using a `count` of a `gauge` in a chart will significantly under-count the number of occurrences.
|
52
|
+
#
|
53
|
+
# If dimensions are added to the metric, then the metric will be sent as-is and
|
54
|
+
# the above logic will _not_ be applied.
|
55
|
+
#
|
56
|
+
# Example, Gauge metric, supplying the duration in `metric_amount`:
|
57
|
+
# logger.info(metric: 'Filters.average', metric_amount: 1.2, dimensions: {user: 'jbloggs'})
|
58
|
+
#
|
59
|
+
# Example, Counter metric:
|
60
|
+
# logger.info(metric: 'Filters.count', dimensions: {user: 'jbloggs'})
|
61
|
+
#
|
62
|
+
# Example, Counter metric with a count other than 1:
|
63
|
+
# logger.info(metric: 'Filters.count', metric_amount: 23, dimensions: {user: 'jbloggs'})
|
64
|
+
#
|
65
|
+
# When a duration is supplied and no dimensions are supplied:
|
66
|
+
# logger.info(metric: 'Common/User/authorize', duration: 1.4)
|
67
|
+
#
|
68
|
+
# Then it is translated into the following 2 log entries under the covers:
|
69
|
+
# logger.info(metric: 'Application.average', metric_amount: 1.4, dimensions: {class: 'Common::User', action: 'authorize'})
|
70
|
+
# logger.info(metric: 'Application.counter', metric_amount: 1, dimensions: {class: 'Common::User', action: 'authorize'})
|
71
|
+
#
|
72
|
+
# Similarly with a measure block which automatically supplies the duration:
|
73
|
+
# logger.measure_info(metric: 'Common/User/authorize') do
|
74
|
+
# sleep 1
|
75
|
+
# end
|
76
|
+
def initialize(token:,
|
77
|
+
dimensions: nil,
|
78
|
+
url: 'https://ingest.signalfx.com',
|
79
|
+
open_timeout: 2.0,
|
80
|
+
read_timeout: 1.0,
|
81
|
+
continue_timeout: 1.0,
|
82
|
+
filter: nil,
|
83
|
+
application: nil,
|
84
|
+
host: nil,
|
85
|
+
formatter: nil,
|
86
|
+
&block)
|
85
87
|
|
86
|
-
|
88
|
+
formatter ||= SemanticLogger::Formatters::Signalfx.new(token: token, dimensions: dimensions)
|
87
89
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
90
|
+
super(
|
91
|
+
url: url,
|
92
|
+
read_timeout: read_timeout,
|
93
|
+
open_timeout: open_timeout,
|
94
|
+
continue_timeout: continue_timeout,
|
95
|
+
filter: filter,
|
96
|
+
application: application,
|
97
|
+
host: host,
|
98
|
+
formatter: formatter,
|
99
|
+
&block
|
100
|
+
)
|
99
101
|
|
100
|
-
|
101
|
-
|
102
|
-
|
102
|
+
@header['X-SF-TOKEN'] = token
|
103
|
+
@full_url = "#{url}/#{END_POINT}"
|
104
|
+
end
|
103
105
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
106
|
+
def log(log)
|
107
|
+
message = formatter.call(log, self)
|
108
|
+
logger.trace(message)
|
109
|
+
post(message, full_url)
|
110
|
+
end
|
109
111
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
112
|
+
# Logs in batches
|
113
|
+
def batch(logs)
|
114
|
+
message = formatter.batch(logs, self)
|
115
|
+
logger.trace(message)
|
116
|
+
post(message, full_url)
|
117
|
+
end
|
116
118
|
|
117
|
-
|
118
|
-
|
119
|
-
|
119
|
+
# Only forward log entries that contain metrics.
|
120
|
+
def should_log?(log)
|
121
|
+
log.metric && meets_log_level?(log) && !filtered?(log)
|
122
|
+
end
|
123
|
+
end
|
120
124
|
end
|
121
|
-
|
122
125
|
end
|
123
|
-
|
@@ -41,11 +41,11 @@ module SemanticLogger
|
|
41
41
|
|
42
42
|
def log(log)
|
43
43
|
metric = log.metric
|
44
|
-
if duration = log.duration
|
44
|
+
if (duration = log.duration)
|
45
45
|
@statsd.timing(metric, duration)
|
46
46
|
else
|
47
47
|
amount = (log.metric_amount || 1).round
|
48
|
-
if amount
|
48
|
+
if amount.negative?
|
49
49
|
amount.times { @statsd.decrement(metric) }
|
50
50
|
else
|
51
51
|
amount.times { @statsd.increment(metric) }
|
@@ -58,7 +58,6 @@ module SemanticLogger
|
|
58
58
|
# Does not support metrics with dimensions.
|
59
59
|
log.metric && !log.dimensions && meets_log_level?(log) && !filtered?(log)
|
60
60
|
end
|
61
|
-
|
62
61
|
end
|
63
62
|
end
|
64
63
|
end
|
@@ -60,8 +60,8 @@ module SemanticLogger
|
|
60
60
|
# Can be replaced with another Ruby logger or Rails logger, but never to
|
61
61
|
# SemanticLogger::Logger itself since it is for reporting problems
|
62
62
|
# while trying to log to the various appenders
|
63
|
-
|
64
|
-
|
63
|
+
class << self
|
64
|
+
attr_writer :logger
|
65
65
|
end
|
66
66
|
|
67
67
|
# Internal logger for SemanticLogger
|
@@ -86,7 +86,10 @@ module SemanticLogger
|
|
86
86
|
def on_log(object = nil, &block)
|
87
87
|
subscriber = block || object
|
88
88
|
|
89
|
-
|
89
|
+
unless subscriber.is_a?(Proc) || subscriber.respond_to?(:call)
|
90
|
+
raise('When supplying an on_log subscriber, it must support the #call method')
|
91
|
+
end
|
92
|
+
|
90
93
|
subscribers = (@log_subscribers ||= Concurrent::Array.new)
|
91
94
|
subscribers << subscriber unless subscribers.include?(subscriber)
|
92
95
|
end
|
@@ -130,13 +133,11 @@ module SemanticLogger
|
|
130
133
|
private
|
131
134
|
|
132
135
|
def self.create_instance
|
133
|
-
SemanticLogger::Appender::Async.new(
|
134
|
-
name: 'SemanticLogger::Processor',
|
135
|
-
appender: new,
|
136
|
-
max_queue_size: -1
|
137
|
-
)
|
136
|
+
SemanticLogger::Appender::Async.new(appender: new, max_queue_size: -1)
|
138
137
|
end
|
139
138
|
|
139
|
+
private_class_method :create_instance
|
140
|
+
|
140
141
|
@processor = create_instance
|
141
142
|
|
142
143
|
# Call on_log subscribers
|
@@ -152,6 +153,5 @@ module SemanticLogger
|
|
152
153
|
end
|
153
154
|
end
|
154
155
|
end
|
155
|
-
|
156
156
|
end
|
157
157
|
end
|