semantic_logger 4.6.0.beta1 → 4.7.2

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/Rakefile +7 -7
  4. data/lib/semantic_logger.rb +23 -22
  5. data/lib/semantic_logger/appender.rb +32 -33
  6. data/lib/semantic_logger/appender/async.rb +9 -8
  7. data/lib/semantic_logger/appender/async_batch.rb +4 -2
  8. data/lib/semantic_logger/appender/bugsnag.rb +7 -7
  9. data/lib/semantic_logger/appender/elasticsearch.rb +10 -10
  10. data/lib/semantic_logger/appender/elasticsearch_http.rb +4 -4
  11. data/lib/semantic_logger/appender/file.rb +2 -1
  12. data/lib/semantic_logger/appender/graylog.rb +15 -10
  13. data/lib/semantic_logger/appender/honeybadger.rb +3 -3
  14. data/lib/semantic_logger/appender/http.rb +20 -18
  15. data/lib/semantic_logger/appender/kafka.rb +5 -5
  16. data/lib/semantic_logger/appender/mongodb.rb +6 -6
  17. data/lib/semantic_logger/appender/new_relic.rb +2 -2
  18. data/lib/semantic_logger/appender/rabbitmq.rb +5 -5
  19. data/lib/semantic_logger/appender/sentry.rb +7 -7
  20. data/lib/semantic_logger/appender/splunk.rb +5 -5
  21. data/lib/semantic_logger/appender/splunk_http.rb +3 -4
  22. data/lib/semantic_logger/appender/syslog.rb +20 -14
  23. data/lib/semantic_logger/appender/tcp.rb +5 -5
  24. data/lib/semantic_logger/appender/udp.rb +2 -2
  25. data/lib/semantic_logger/appenders.rb +11 -11
  26. data/lib/semantic_logger/base.rb +42 -18
  27. data/lib/semantic_logger/formatters.rb +11 -11
  28. data/lib/semantic_logger/formatters/base.rb +8 -3
  29. data/lib/semantic_logger/formatters/color.rb +10 -6
  30. data/lib/semantic_logger/formatters/default.rb +18 -5
  31. data/lib/semantic_logger/formatters/fluentd.rb +3 -3
  32. data/lib/semantic_logger/formatters/json.rb +1 -1
  33. data/lib/semantic_logger/formatters/raw.rb +31 -7
  34. data/lib/semantic_logger/formatters/signalfx.rb +10 -9
  35. data/lib/semantic_logger/formatters/syslog.rb +7 -6
  36. data/lib/semantic_logger/formatters/syslog_cee.rb +7 -6
  37. data/lib/semantic_logger/jruby/garbage_collection_logger.rb +4 -2
  38. data/lib/semantic_logger/levels.rb +9 -7
  39. data/lib/semantic_logger/log.rb +52 -60
  40. data/lib/semantic_logger/logger.rb +6 -8
  41. data/lib/semantic_logger/metric/new_relic.rb +3 -3
  42. data/lib/semantic_logger/metric/signalfx.rb +3 -3
  43. data/lib/semantic_logger/metric/statsd.rb +7 -7
  44. data/lib/semantic_logger/processor.rb +7 -5
  45. data/lib/semantic_logger/reporters/minitest.rb +4 -4
  46. data/lib/semantic_logger/semantic_logger.rb +24 -11
  47. data/lib/semantic_logger/subscriber.rb +6 -5
  48. data/lib/semantic_logger/sync.rb +12 -0
  49. data/lib/semantic_logger/sync_processor.rb +43 -0
  50. data/lib/semantic_logger/utils.rb +6 -6
  51. data/lib/semantic_logger/version.rb +1 -1
  52. metadata +7 -5
@@ -126,7 +126,7 @@ module SemanticLogger
126
126
  # Log a thread backtrace
127
127
  def backtrace(thread: Thread.current,
128
128
  level: :warn,
129
- message: 'Backtrace:',
129
+ message: "Backtrace:",
130
130
  payload: nil,
131
131
  metric: nil,
132
132
  metric_amount: nil)
@@ -190,7 +190,8 @@ module SemanticLogger
190
190
  # Allow named tags to be passed into the logger
191
191
  if tags.size == 1
192
192
  tag = tags[0]
193
- return yield if tag.nil? || tag == ''
193
+ return yield if tag.nil? || tag == ""
194
+
194
195
  return tag.is_a?(Hash) ? SemanticLogger.named_tagged(tag, &block) : SemanticLogger.fast_tag(tag.to_s, &block)
195
196
  end
196
197
 
@@ -240,7 +241,7 @@ module SemanticLogger
240
241
 
241
242
  # Write log data to underlying data storage
242
243
  def log(_log_)
243
- raise NotImplementedError, 'Logging Appender must implement #log(log)'
244
+ raise NotImplementedError, "Logging Appender must implement #log(log)"
244
245
  end
245
246
 
246
247
  # Whether this log entry meets the criteria to be logged by this appender.
@@ -269,7 +270,7 @@ module SemanticLogger
269
270
  # The Proc must return true or false
270
271
  def initialize(klass, level = nil, filter = nil)
271
272
  # Support filtering all messages to this logger using a Regular Expression or Proc
272
- raise ':filter must be a Regexp or Proc' unless filter.nil? || filter.is_a?(Regexp) || filter.is_a?(Proc)
273
+ raise ":filter must be a Regexp or Proc" unless filter.nil? || filter.is_a?(Regexp) || filter.is_a?(Proc)
273
274
 
274
275
  @filter = filter.is_a?(Regexp) ? filter.freeze : filter
275
276
  @name = klass.is_a?(String) ? klass : klass.name
@@ -302,20 +303,42 @@ module SemanticLogger
302
303
  end
303
304
 
304
305
  # Log message at the specified level
305
- def log_internal(level, index, message = nil, payload = nil, exception = nil, &block)
306
- log = Log.new(name, level, index)
306
+ def log_internal(level, index, message = nil, payload = nil, exception = nil)
307
+ # Handle variable number of arguments by detecting exception object and payload hash.
308
+ if exception.nil? && payload.nil? && message.respond_to?(:backtrace) && message.respond_to?(:message)
309
+ exception = message
310
+ message = nil
311
+ elsif exception.nil? && payload && payload.respond_to?(:backtrace) && payload.respond_to?(:message)
312
+ exception = payload
313
+ payload = nil
314
+ elsif payload && !payload.is_a?(Hash)
315
+ message = message.nil? ? payload : "#{message} -- #{payload}"
316
+ payload = nil
317
+ end
318
+
319
+ log = Log.new(name, level, index)
307
320
  should_log =
308
321
  if payload.nil? && exception.nil? && message.is_a?(Hash)
309
- # Check if someone just logged a hash payload instead of meaning to call semantic logger
310
- if message.key?(:message) || message.key?(:payload) || message.key?(:exception) || message.key?(:metric)
311
- log.assign(message)
312
- else
313
- log.assign_positional(nil, message, nil, &block)
314
- end
322
+ # Everything as keyword arguments.
323
+ log.assign(**log.extract_arguments(message))
324
+ elsif exception.nil? && message && payload && payload.is_a?(Hash)
325
+ # Message with keyword arguments as the rest.
326
+ log.assign(message: message, **log.extract_arguments(payload))
315
327
  else
316
- log.assign_positional(message, payload, exception, &block)
328
+ # No keyword arguments.
329
+ log.assign(message: message, payload: payload, exception: exception)
317
330
  end
318
331
 
332
+ # Add result of block to message or payload if not nil
333
+ if block_given?
334
+ result = yield(log)
335
+ if result.is_a?(String)
336
+ log.message = log.message.nil? ? result : "#{log.message} -- #{result}"
337
+ elsif result.is_a?(Hash)
338
+ log.assign_hash(result)
339
+ end
340
+ end
341
+
319
342
  # Log level may change during assign due to :on_exception_level
320
343
  self.log(log) if should_log && should_log?(log)
321
344
  end
@@ -341,8 +364,8 @@ module SemanticLogger
341
364
  yield(params)
342
365
  end
343
366
  end
344
- rescue Exception => exc
345
- exception = exc
367
+ rescue Exception => e
368
+ exception = e
346
369
  ensure
347
370
  # Must use ensure block otherwise a `return` in the yield above will skip the log entry
348
371
  log = Log.new(name, level, index)
@@ -352,7 +375,7 @@ module SemanticLogger
352
375
  if block_given?
353
376
  1_000.0 * (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start)
354
377
  else
355
- params[:duration] || raise('Mandatory block missing when :duration option is not supplied')
378
+ params[:duration] || raise("Mandatory block missing when :duration option is not supplied")
356
379
  end
357
380
 
358
381
  # Extract options after block completes so that block can modify any of the options
@@ -374,6 +397,7 @@ module SemanticLogger
374
397
  # Log level may change during assign due to :on_exception_level
375
398
  self.log(log) if should_log && should_log?(log)
376
399
  raise exception if exception
400
+
377
401
  result
378
402
  end
379
403
  end
@@ -392,8 +416,8 @@ module SemanticLogger
392
416
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
393
417
  begin
394
418
  yield
395
- rescue Exception => exc
396
- exception = exc
419
+ rescue Exception => e
420
+ exception = e
397
421
  ensure
398
422
  log = Log.new(name, level, index)
399
423
  # May return false due to elastic logging
@@ -1,15 +1,15 @@
1
1
  module SemanticLogger
2
2
  module Formatters
3
3
  # @formatter:off
4
- autoload :Base, 'semantic_logger/formatters/base'
5
- autoload :Color, 'semantic_logger/formatters/color'
6
- autoload :Default, 'semantic_logger/formatters/default'
7
- autoload :Json, 'semantic_logger/formatters/json'
8
- autoload :Raw, 'semantic_logger/formatters/raw'
9
- autoload :OneLine, 'semantic_logger/formatters/one_line'
10
- autoload :Signalfx, 'semantic_logger/formatters/signalfx'
11
- autoload :Syslog, 'semantic_logger/formatters/syslog'
12
- autoload :Fluentd, 'semantic_logger/formatters/fluentd'
4
+ autoload :Base, "semantic_logger/formatters/base"
5
+ autoload :Color, "semantic_logger/formatters/color"
6
+ autoload :Default, "semantic_logger/formatters/default"
7
+ autoload :Json, "semantic_logger/formatters/json"
8
+ autoload :Raw, "semantic_logger/formatters/raw"
9
+ autoload :OneLine, "semantic_logger/formatters/one_line"
10
+ autoload :Signalfx, "semantic_logger/formatters/signalfx"
11
+ autoload :Syslog, "semantic_logger/formatters/syslog"
12
+ autoload :Fluentd, "semantic_logger/formatters/fluentd"
13
13
  # @formatter:on
14
14
 
15
15
  # Return formatter that responds to call.
@@ -22,10 +22,10 @@ module SemanticLogger
22
22
  # - Any object that responds to :call
23
23
  def self.factory(formatter)
24
24
  if formatter.is_a?(Symbol)
25
- SemanticLogger::Utils.constantize_symbol(formatter, 'SemanticLogger::Formatters').new
25
+ SemanticLogger::Utils.constantize_symbol(formatter, "SemanticLogger::Formatters").new
26
26
  elsif formatter.is_a?(Hash) && formatter.size.positive?
27
27
  fmt, options = formatter.first
28
- SemanticLogger::Utils.constantize_symbol(fmt.to_sym, 'SemanticLogger::Formatters').new(options)
28
+ SemanticLogger::Utils.constantize_symbol(fmt.to_sym, "SemanticLogger::Formatters").new(**options)
29
29
  elsif formatter.respond_to?(:call)
30
30
  formatter
31
31
  else
@@ -1,8 +1,8 @@
1
- require 'time'
1
+ require "time"
2
2
  module SemanticLogger
3
3
  module Formatters
4
4
  class Base
5
- attr_accessor :time_format, :log_host, :log_application, :log_environment, :precision
5
+ attr_accessor :log, :logger, :time_format, :log_host, :log_application, :log_environment, :precision
6
6
 
7
7
  # Time precision varies by Ruby interpreter
8
8
  # JRuby 9.1.8.0 supports microseconds
@@ -61,6 +61,11 @@ module SemanticLogger
61
61
  format_time(log.time) if time_format
62
62
  end
63
63
 
64
+ # Process ID
65
+ def pid
66
+ $$
67
+ end
68
+
64
69
  private
65
70
 
66
71
  # Return the Time as a formatted string
@@ -77,7 +82,7 @@ module SemanticLogger
77
82
  when :seconds
78
83
  time.to_f
79
84
  when nil
80
- ''
85
+ ""
81
86
  else
82
87
  time.strftime(time_format)
83
88
  end
@@ -1,8 +1,12 @@
1
- # Load AwesomePrint if available
1
+ # Load Amazing Print, or Awesome Print if available
2
2
  begin
3
- require 'awesome_print'
3
+ require "amazing_print"
4
4
  rescue LoadError
5
- nil
5
+ begin
6
+ require "awesome_print"
7
+ rescue LoadError
8
+ nil
9
+ end
6
10
  end
7
11
 
8
12
  module SemanticLogger
@@ -61,9 +65,9 @@ module SemanticLogger
61
65
  #
62
66
  # Parameters:
63
67
  # ap: [Hash]
64
- # Any valid AwesomePrint option for rendering data.
68
+ # Any valid Amazing Print option for rendering data.
65
69
  # These options can also be changed be creating a `~/.aprc` file.
66
- # See: https://github.com/michaeldv/awesome_print
70
+ # See: https://github.com/amazing-print/amazing_print
67
71
  #
68
72
  # Note: The option :multiline is set to false if not supplied.
69
73
  # Note: Has no effect if Awesome Print is not installed.
@@ -105,7 +109,7 @@ module SemanticLogger
105
109
  def payload
106
110
  return unless log.payload?
107
111
 
108
- if !defined?(AwesomePrint) || !log.payload.respond_to?(:ai)
112
+ if !log.payload.respond_to?(:ai)
109
113
  super
110
114
  else
111
115
  begin
@@ -2,8 +2,6 @@ module SemanticLogger
2
2
  module Formatters
3
3
  # Default non-colored text log output
4
4
  class Default < Base
5
- attr_accessor :log, :logger
6
-
7
5
  # Formatting methods, must return nil, or a string
8
6
  # Nil values are ignored
9
7
 
@@ -12,9 +10,24 @@ module SemanticLogger
12
10
  log.level_to_s
13
11
  end
14
12
 
15
- # Process info
13
+ # Name of the thread that logged the message.
14
+ def thread_name
15
+ format("%.30s", log.thread_name)
16
+ end
17
+
18
+ # Ruby file name and line number that logged the message.
19
+ def file_name_and_line
20
+ file, line = log.file_name_and_line(true)
21
+ "#{file}:#{line}" if file
22
+ end
23
+
24
+ # Returns [String] the available process info
25
+ # Example:
26
+ # [18934:thread_name test_logging.rb:51]
16
27
  def process_info
17
- "[#{log.process_info}]"
28
+ process_id = "#{pid}:" if pid
29
+ fname = file_name_and_line
30
+ fname ? "[#{process_id}#{thread_name} #{fname}]" : "[#{process_id}#{thread_name}]"
18
31
  end
19
32
 
20
33
  # Tags
@@ -67,7 +80,7 @@ module SemanticLogger
67
80
  self.log = log
68
81
  self.logger = logger
69
82
 
70
- [time, level, process_info, tags, named_tags, duration, name, message, payload, exception].compact.join(' ')
83
+ [time, level, process_info, tags, named_tags, duration, name, message, payload, exception].compact.join(" ")
71
84
  end
72
85
  end
73
86
  end
@@ -1,4 +1,4 @@
1
- require 'json'
1
+ require "json"
2
2
 
3
3
  module SemanticLogger
4
4
  module Formatters
@@ -13,8 +13,8 @@ module SemanticLogger
13
13
  end
14
14
 
15
15
  def level
16
- hash['severity'] = log.level
17
- hash['severity_index'] = log.level_index
16
+ hash["severity"] = log.level
17
+ hash["severity_index"] = log.level_index
18
18
  end
19
19
 
20
20
  def process_info
@@ -1,4 +1,4 @@
1
- require 'json'
1
+ require "json"
2
2
  module SemanticLogger
3
3
  module Formatters
4
4
  class Json < Raw
@@ -1,9 +1,9 @@
1
- require 'json'
1
+ require "json"
2
2
  module SemanticLogger
3
3
  module Formatters
4
4
  class Raw < Base
5
5
  # Fields are added by populating this hash.
6
- attr_accessor :hash, :log, :logger, :time_key
6
+ attr_accessor :hash, :time_key
7
7
 
8
8
  # By default Raw formatter does not reformat the time
9
9
  def initialize(time_format: :none, time_key: :time, **args)
@@ -37,11 +37,18 @@ module SemanticLogger
37
37
  hash[:level_index] = log.level_index
38
38
  end
39
39
 
40
- # Process info
41
- def process_info
42
- hash[:pid] = $$
40
+ # Process ID
41
+ def pid
42
+ hash[:pid] = super
43
+ end
44
+
45
+ # Name of the thread that logged the message.
46
+ def thread_name
43
47
  hash[:thread] = log.thread_name
48
+ end
44
49
 
50
+ # Ruby file name and line number that logged the message.
51
+ def file_name_and_line
45
52
  file, line = log.file_name_and_line
46
53
  return unless file
47
54
 
@@ -85,6 +92,7 @@ module SemanticLogger
85
92
  # Exception
86
93
  def exception
87
94
  return unless log.exception
95
+
88
96
  root = hash
89
97
  log.each_exception do |exception, i|
90
98
  name = i.zero? ? :exception : :cause
@@ -93,7 +101,7 @@ module SemanticLogger
93
101
  message: exception.message,
94
102
  stack_trace: exception.backtrace
95
103
  }
96
- root = root[name]
104
+ root = root[name]
97
105
  end
98
106
  end
99
107
 
@@ -109,7 +117,23 @@ module SemanticLogger
109
117
  self.log = log
110
118
  self.logger = logger
111
119
 
112
- host; application; environment; time; level; process_info; duration; tags; named_tags; name; message; payload; exception; metric
120
+ host
121
+ application
122
+ environment
123
+ time
124
+ level
125
+ pid
126
+ thread_name
127
+ file_name_and_line
128
+ duration
129
+ tags
130
+ named_tags
131
+ name
132
+ message
133
+ payload
134
+ exception
135
+ metric
136
+
113
137
  hash
114
138
  end
115
139
  end
@@ -1,13 +1,13 @@
1
- require 'json'
1
+ require "json"
2
2
  module SemanticLogger
3
3
  module Formatters
4
4
  class Signalfx < Base
5
- attr_accessor :token, :dimensions, :hash, :log, :logger, :gauge_name, :counter_name
5
+ attr_accessor :token, :dimensions, :hash, :gauge_name, :counter_name
6
6
 
7
7
  def initialize(token:,
8
8
  dimensions: nil,
9
- gauge_name: 'Application.average',
10
- counter_name: 'Application.counter',
9
+ gauge_name: "Application.average",
10
+ counter_name: "Application.counter",
11
11
  time_format: :ms,
12
12
  **args)
13
13
 
@@ -23,19 +23,19 @@ module SemanticLogger
23
23
  # Strip leading '/'
24
24
  # Convert remaining '/' to '.'
25
25
  def metric
26
- name = log.metric.to_s.sub(/\A\/+/, '')
26
+ name = log.metric.to_s.sub(%r{\A/+}, "")
27
27
  if log.dimensions
28
- name.tr!('/', '.')
28
+ name.tr!("/", ".")
29
29
  hash[:metric] = name
30
30
  else
31
31
  # Extract class and action from metric name
32
- names = name.split('/')
32
+ names = name.split("/")
33
33
  h = (hash[:dimensions] ||= {})
34
34
  if names.size > 1
35
35
  h[:action] = names.pop
36
- h[:class] = names.join('::')
36
+ h[:class] = names.join("::")
37
37
  else
38
- h[:class] = 'Unknown'
38
+ h[:class] = "Unknown"
39
39
  h[:action] = names.first || log.metric
40
40
  end
41
41
 
@@ -67,6 +67,7 @@ module SemanticLogger
67
67
  name = name.to_sym
68
68
  value = value.to_s
69
69
  next if value.empty?
70
+
70
71
  h[name] = value if dimensions&.include?(name)
71
72
  end
72
73
  end
@@ -1,13 +1,13 @@
1
1
  begin
2
- require 'syslog_protocol'
2
+ require "syslog_protocol"
3
3
  rescue LoadError
4
- raise 'Gem syslog_protocol is required for remote logging using the Syslog protocol. Please add the gem "syslog_protocol" to your Gemfile.'
4
+ raise LoadError, 'Gem syslog_protocol is required for remote logging using the Syslog protocol. Please add the gem "syslog_protocol" to your Gemfile.'
5
5
  end
6
6
 
7
7
  module SemanticLogger
8
8
  module Formatters
9
9
  class Syslog < Default
10
- attr_accessor :level_map, :facility
10
+ attr_accessor :level_map, :facility, :max_size
11
11
 
12
12
  # Default level map for every log level
13
13
  #
@@ -50,9 +50,10 @@ module SemanticLogger
50
50
  # Example:
51
51
  # # Change the warn level to LOG_NOTICE level instead of a the default of LOG_WARNING.
52
52
  # SemanticLogger.add_appender(appender: :syslog, level_map: {warn: ::Syslog::LOG_NOTICE})
53
- def initialize(facility: ::Syslog::LOG_USER, level_map: LevelMap.new)
53
+ def initialize(facility: ::Syslog::LOG_USER, level_map: LevelMap.new, max_size: Integer)
54
54
  @facility = facility
55
55
  @level_map = level_map.is_a?(LevelMap) ? level_map : LevelMap.new(level_map)
56
+ @max_size = max_size
56
57
  super()
57
58
  end
58
59
 
@@ -73,11 +74,11 @@ module SemanticLogger
73
74
  packet = SyslogProtocol::Packet.new
74
75
  packet.hostname = logger.host
75
76
  packet.facility = facility
76
- packet.tag = logger.application.delete(' ')
77
+ packet.tag = logger.application.delete(" ")
77
78
  packet.content = message
78
79
  packet.time = log.time
79
80
  packet.severity = level_map[log.level]
80
- packet.to_s
81
+ packet.assemble(@max_size)
81
82
  end
82
83
  end
83
84
  end