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