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