semantic_logger 4.3.1 → 4.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/lib/semantic_logger.rb +7 -1
  3. data/lib/semantic_logger/appender.rb +3 -0
  4. data/lib/semantic_logger/appender/async.rb +29 -10
  5. data/lib/semantic_logger/appender/rabbitmq.rb +120 -0
  6. data/lib/semantic_logger/appenders.rb +89 -0
  7. data/lib/semantic_logger/base.rb +3 -3
  8. data/lib/semantic_logger/concerns/compatibility.rb +2 -2
  9. data/lib/semantic_logger/formatters.rb +1 -0
  10. data/lib/semantic_logger/formatters/base.rb +28 -6
  11. data/lib/semantic_logger/formatters/color.rb +4 -3
  12. data/lib/semantic_logger/formatters/fluentd.rb +37 -0
  13. data/lib/semantic_logger/formatters/json.rb +4 -2
  14. data/lib/semantic_logger/formatters/raw.rb +2 -2
  15. data/lib/semantic_logger/formatters/signalfx.rb +4 -3
  16. data/lib/semantic_logger/levels.rb +38 -0
  17. data/lib/semantic_logger/log.rb +11 -6
  18. data/lib/semantic_logger/loggable.rb +1 -1
  19. data/lib/semantic_logger/logger.rb +43 -1
  20. data/lib/semantic_logger/processor.rb +10 -130
  21. data/lib/semantic_logger/reporters/minitest.rb +49 -0
  22. data/lib/semantic_logger/semantic_logger.rb +40 -75
  23. data/lib/semantic_logger/version.rb +1 -1
  24. metadata +9 -81
  25. data/test/appender/async_batch_test.rb +0 -60
  26. data/test/appender/async_test.rb +0 -44
  27. data/test/appender/bugsnag_test.rb +0 -81
  28. data/test/appender/elasticsearch_http_test.rb +0 -74
  29. data/test/appender/elasticsearch_test.rb +0 -248
  30. data/test/appender/file_test.rb +0 -120
  31. data/test/appender/graylog_test.rb +0 -82
  32. data/test/appender/honeybadger_test.rb +0 -45
  33. data/test/appender/http_test.rb +0 -63
  34. data/test/appender/kafka_test.rb +0 -35
  35. data/test/appender/mongodb_test.rb +0 -104
  36. data/test/appender/new_relic_test.rb +0 -80
  37. data/test/appender/newrelic_rpm.rb +0 -14
  38. data/test/appender/sentry_test.rb +0 -47
  39. data/test/appender/splunk_http_test.rb +0 -79
  40. data/test/appender/splunk_test.rb +0 -83
  41. data/test/appender/syslog_test.rb +0 -61
  42. data/test/appender/tcp_test.rb +0 -66
  43. data/test/appender/udp_test.rb +0 -59
  44. data/test/appender/wrapper_test.rb +0 -95
  45. data/test/concerns/compatibility_test.rb +0 -117
  46. data/test/debug_as_trace_logger_test.rb +0 -81
  47. data/test/formatters/color_test.rb +0 -153
  48. data/test/formatters/default_test.rb +0 -175
  49. data/test/formatters/one_line_test.rb +0 -60
  50. data/test/formatters/signalfx_test.rb +0 -197
  51. data/test/formatters_test.rb +0 -36
  52. data/test/in_memory_appender.rb +0 -8
  53. data/test/in_memory_appender_helper.rb +0 -43
  54. data/test/in_memory_batch_appender.rb +0 -8
  55. data/test/in_memory_metrics_appender.rb +0 -13
  56. data/test/loggable_test.rb +0 -103
  57. data/test/logger_test.rb +0 -334
  58. data/test/measure_test.rb +0 -346
  59. data/test/metric/new_relic_test.rb +0 -35
  60. data/test/metric/signalfx_test.rb +0 -77
  61. data/test/semantic_logger_test.rb +0 -303
  62. data/test/test_helper.rb +0 -31
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 285869f2b402ea378eab2606d3d72f7b7be3db56102bea2c530a98411a077d6c
4
- data.tar.gz: cab30b7d7bcfda6083716a530aeedf20192b1fa1c3a83c7cb237d475516d0ca7
3
+ metadata.gz: 88a1f36f6ef4d857e13b696e283f6bbd643329a0ca7f3fd9ac4c9ef1e670aaae
4
+ data.tar.gz: 01a175a96d750f9692bb28512d914434e442336c68eadd9f7b9f409a4d2f4a2b
5
5
  SHA512:
6
- metadata.gz: e67d39bfbedb72f64b191f75d5786f521d311d78fb243bb97cbfa948333fcfa21f89ebcfa6a9ac34696a24c359bd8b67a9617228a25a1958bbf3092ed6324472
7
- data.tar.gz: c446a8410247e2b8393f401182f0bc1a266d329ce1190328a3f7253bf5b64273c87c5db05a4bb4f808caf9435b0e8a8d2a37a69c9ac245b43f3215f67f1f9710
6
+ metadata.gz: e06dd57a7ee95bfc5aea5d4b2948101a1fbdb00dd76ac1b9ac0b68a4a3f666670b227d559451d4137e510d1c63b9ec9bd8f99326bfe765f9a610294221c2259f
7
+ data.tar.gz: 0e2b66a5da5f5e2d21c185555f3502e7982d8d197ec9bade63092acae1750dcf1d8191de71dc8fbe0598d844b2c5f85931c407030a599260f41ad35470802a14
@@ -1,14 +1,15 @@
1
1
  require 'semantic_logger/core_ext/thread'
2
2
  require 'semantic_logger/version'
3
- require 'semantic_logger/semantic_logger'
4
3
 
5
4
  # @formatter:off
6
5
  module SemanticLogger
7
6
  autoload :AnsiColors, 'semantic_logger/ansi_colors'
8
7
  autoload :Appender, 'semantic_logger/appender'
8
+ autoload :Appenders, 'semantic_logger/appenders'
9
9
  autoload :Base, 'semantic_logger/base'
10
10
  autoload :DebugAsTraceLogger, 'semantic_logger/debug_as_trace_logger'
11
11
  autoload :Formatters, 'semantic_logger/formatters'
12
+ autoload :Levels, 'semantic_logger/levels'
12
13
  autoload :Log, 'semantic_logger/log'
13
14
  autoload :Logger, 'semantic_logger/logger'
14
15
  autoload :Loggable, 'semantic_logger/loggable'
@@ -26,12 +27,17 @@ module SemanticLogger
26
27
  autoload :Statsd, 'semantic_logger/metric/statsd'
27
28
  end
28
29
 
30
+ module Reporters
31
+ autoload :Minitest, 'semantic_logger/reporters/minitest'
32
+ end
33
+
29
34
  if defined?(JRuby)
30
35
  module JRuby
31
36
  autoload :GarbageCollectionLogger, 'semantic_logger/jruby/garbage_collection_logger'
32
37
  end
33
38
  end
34
39
  end
40
+ require 'semantic_logger/semantic_logger'
35
41
  # @formatter:on
36
42
 
37
43
  # Flush all appenders at exit, waiting for outstanding messages on the queue
@@ -14,6 +14,7 @@ module SemanticLogger
14
14
  autoload :Http, 'semantic_logger/appender/http'
15
15
  autoload :MongoDB, 'semantic_logger/appender/mongodb'
16
16
  autoload :NewRelic, 'semantic_logger/appender/new_relic'
17
+ autoload :Rabbitmq, 'semantic_logger/appender/rabbitmq'
17
18
  autoload :Splunk, 'semantic_logger/appender/splunk'
18
19
  autoload :SplunkHttp, 'semantic_logger/appender/splunk_http'
19
20
  autoload :Syslog, 'semantic_logger/appender/syslog'
@@ -56,6 +57,8 @@ module SemanticLogger
56
57
  elsif async == true
57
58
  proxy_options[:appender] = appender
58
59
  Appender::Async.new(proxy_options)
60
+
61
+
59
62
  else
60
63
  appender
61
64
  end
@@ -6,8 +6,8 @@ module SemanticLogger
6
6
  class Async
7
7
  extend Forwardable
8
8
 
9
- attr_accessor :logger, :lag_check_interval, :lag_threshold_s
10
- attr_reader :queue, :appender
9
+ attr_accessor :lag_check_interval, :lag_threshold_s
10
+ attr_reader :queue, :appender, :max_queue_size
11
11
 
12
12
  # Forward methods that can be called directly
13
13
  def_delegator :@appender, :name
@@ -18,6 +18,7 @@ module SemanticLogger
18
18
  def_delegator :@appender, :level
19
19
  def_delegator :@appender, :level=
20
20
  def_delegator :@appender, :logger
21
+ def_delegator :@appender, :logger=
21
22
 
22
23
  # Appender proxy to allow an existing appender to run asynchronously in a separate thread.
23
24
  #
@@ -43,17 +44,24 @@ module SemanticLogger
43
44
  @lag_check_interval = lag_check_interval
44
45
  @lag_threshold_s = lag_threshold_s
45
46
  @thread = nil
46
-
47
- if max_queue_size == -1
48
- @queue = Queue.new
49
- @capped = false
50
- else
51
- @queue = SizedQueue.new(max_queue_size)
52
- @capped = true
53
- end
47
+ @max_queue_size = max_queue_size
48
+ create_queue
54
49
  thread
55
50
  end
56
51
 
52
+ # Re-open appender after a fork
53
+ def reopen
54
+ # Workaround CRuby crash on fork by recreating queue on reopen
55
+ # https://github.com/rocketjob/semantic_logger/issues/103
56
+ @queue&.close
57
+ create_queue
58
+
59
+ appender.reopen if appender.respond_to?(:reopen)
60
+
61
+ @thread.kill if @thread&.alive?
62
+ @thread = Thread.new { process }
63
+ end
64
+
57
65
  # Returns [true|false] if the queue has a capped size.
58
66
  def capped?
59
67
  @capped
@@ -91,6 +99,16 @@ module SemanticLogger
91
99
 
92
100
  private
93
101
 
102
+ def create_queue
103
+ if max_queue_size == -1
104
+ @queue = Queue.new
105
+ @capped = false
106
+ else
107
+ @queue = SizedQueue.new(max_queue_size)
108
+ @capped = true
109
+ end
110
+ end
111
+
94
112
  # Separate thread for batching up log messages before writing.
95
113
  def process
96
114
  # This thread is designed to never go down unless the main thread terminates
@@ -140,6 +158,7 @@ module SemanticLogger
140
158
  break unless process_message(message)
141
159
  end
142
160
  end
161
+ logger.trace 'Async: Queue Closed'
143
162
  end
144
163
 
145
164
  # Returns false when message processing should be stopped
@@ -0,0 +1,120 @@
1
+ begin
2
+ require 'bunny'
3
+ rescue LoadError
4
+ raise 'Gem bunny is required for logging to RabbitMQ. Please add the gem "bunny" to your Gemfile.'
5
+ end
6
+
7
+ # Forward all log messages to RabbitMQ.
8
+ #
9
+ # Example:
10
+ #
11
+ # SemanticLogger.add_appender(
12
+ # appender: :rabbitmq,
13
+ #
14
+ # # Name of the queue in RabbitMQ where to publish the logs. This queue will be bound to "amqp.direct" exchange.
15
+ # queue: 'semantic_logger',
16
+ #
17
+ # # This host will be used for RabbitMQ connection.
18
+ # # NOTE this is different than :host option which is used by the logger directly.
19
+ # rabbitmq_host: '127.0.0.1',
20
+ #
21
+ # # RabbitMQ credentials
22
+ # username: 'my-username',
23
+ # password: 'my-secrect-pass',
24
+ #
25
+ # # All other options accepted by Bunny.new call
26
+ # vhost: 'production',
27
+ # )
28
+ module SemanticLogger
29
+ module Appender
30
+ class Rabbitmq < SemanticLogger::Subscriber
31
+ # Create RabbitMQ appender using Bunny gem
32
+ #
33
+ # Parameters:
34
+ #
35
+ # queue_name: [String]
36
+ # Name of RabbitMQ queue where to stream logs to.
37
+ # This will be a queue bound to AMQP Default exchange
38
+ # Default: semantic_logger
39
+ #
40
+ # level: [:trace | :debug | :info | :warn | :error | :fatal]
41
+ # Override the log level for this appender.
42
+ # Default: SemanticLogger.default_level
43
+ #
44
+ # formatter: [Object|Proc|Symbol|Hash]
45
+ # An instance of a class that implements #call, or a Proc to be used to format
46
+ # the output from this appender
47
+ # Default: :json (See: #call)
48
+ #
49
+ # filter: [Regexp|Proc]
50
+ # RegExp: Only include log messages where the class name matches the supplied.
51
+ # regular expression. All other messages will be ignored.
52
+ # Proc: Only include log messages where the supplied Proc returns true
53
+ # The Proc must return true or false.
54
+ #
55
+ # host: [String]
56
+ # Name of this host to appear in log messages.
57
+ # Default: SemanticLogger.host
58
+ #
59
+ # application: [String]
60
+ # Name of this application to appear in log messages.
61
+ # Default: SemanticLogger.application
62
+ #
63
+ # RabbitMQ Parameters:
64
+ #
65
+ # rabbitmq_host: [String]
66
+ # Host for AMQP connection. in Bunny this is called :host but here it has
67
+ # been remapped to avoid conflicting with SemanticLogger's :host param.
68
+ # Default: localhost
69
+ #
70
+ # username: [String]
71
+ # Username for AMQP connection
72
+ # Default: nil
73
+ #
74
+ # password: [String]
75
+ # Password for AMQP connection
76
+ # Default: nil
77
+ #
78
+ # more parameters supported by Bunny: http://rubybunny.info/articles/connecting.html
79
+ def initialize(queue_name: 'semantic_logger', rabbitmq_host: nil, metrics: false, **args, &block)
80
+ @queue_name = queue_name
81
+ @rabbitmq_args = args.dup
82
+ @rabbitmq_args[:host] = rabbitmq_host
83
+ @rabbitmq_args[:logger] = logger
84
+
85
+ super(level: level, formatter: formatter, filter: filter, application: application, host: host, metrics: metrics, &block)
86
+ reopen
87
+ end
88
+
89
+ def reopen
90
+ @connection = Bunny.new(@rabbitmq_args)
91
+ @connection.start
92
+ @channel = @connection.create_channel
93
+ end
94
+
95
+ def close
96
+ @channel&.close
97
+ @channel = nil
98
+ @connection&.close
99
+ @connection = nil
100
+ end
101
+
102
+ def log(log)
103
+ queue.publish(formatter.call(log, self))
104
+ end
105
+
106
+ def flush
107
+ # NOOP
108
+ end
109
+
110
+ # Use JSON Formatter by default.
111
+ def default_formatter
112
+ SemanticLogger::Formatters::Json.new
113
+ end
114
+
115
+ def queue
116
+ @queue ||= @channel.queue(@queue_name)
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,89 @@
1
+ module SemanticLogger
2
+ # Manage a collection of appenders.
3
+ class Appenders < Concurrent::Array
4
+ attr_accessor :logger
5
+
6
+ def initialize(logger = Processor.logger.dup)
7
+ @logger = logger
8
+ @logger.name = self.class.name
9
+ end
10
+
11
+ def add(options, deprecated_level = nil, &block)
12
+ options = options.is_a?(Hash) ? options.dup : convert_old_appender_args(options, deprecated_level)
13
+ appender = SemanticLogger::Appender.factory(options, &block)
14
+ self << appender
15
+ appender
16
+ end
17
+
18
+ def log(log)
19
+ each do |appender|
20
+ begin
21
+ appender.log(log) if appender.should_log?(log)
22
+ rescue Exception => exc
23
+ logger.error "Failed to log to appender: #{appender.inspect}", exc
24
+ end
25
+ end
26
+ end
27
+
28
+ def flush
29
+ each do |appender|
30
+ begin
31
+ logger.trace "Flushing appender: #{appender.name}"
32
+ appender.flush
33
+ rescue Exception => exc
34
+ logger.error "Failed to flush appender: #{appender.inspect}", exc
35
+ end
36
+ end
37
+ logger.trace 'All appenders flushed'
38
+ end
39
+
40
+ def close
41
+ each do |appender|
42
+ begin
43
+ logger.trace "Closing appender: #{appender.name}"
44
+ appender.flush
45
+ appender.close
46
+ appenders.delete(appender)
47
+ rescue Exception => exc
48
+ logger.error "Failed to close appender: #{appender.inspect}", exc
49
+ end
50
+ end
51
+ logger.trace 'All appenders closed and removed from appender list'
52
+ end
53
+
54
+ # After a fork the appender thread is not running, start it if it is not running.
55
+ def reopen
56
+ each do |appender|
57
+ begin
58
+ next unless appender.respond_to?(:reopen)
59
+
60
+ logger.trace "Reopening appender: #{appender.name}"
61
+ appender.reopen
62
+ rescue Exception => exc
63
+ logger.error "Failed to re-open appender: #{appender.inspect}", exc
64
+ end
65
+ end
66
+ logger.trace 'All appenders re-opened'
67
+ end
68
+
69
+ private
70
+
71
+ # Backward compatibility
72
+ def convert_old_appender_args(appender, level)
73
+ options = {}
74
+ options[:level] = level if level
75
+
76
+ if appender.is_a?(String)
77
+ options[:file_name] = appender
78
+ elsif appender.is_a?(IO)
79
+ options[:io] = appender
80
+ elsif appender.is_a?(Symbol) || appender.is_a?(Subscriber)
81
+ options[:appender] = appender
82
+ else
83
+ options[:logger] = appender
84
+ end
85
+ warn "[DEPRECATED] SemanticLogger.add_appender parameters have changed. Please use: #{options.inspect}"
86
+ options
87
+ end
88
+ end
89
+ end
@@ -23,8 +23,8 @@ module SemanticLogger
23
23
  @level_index = nil
24
24
  @level = nil
25
25
  else
26
- @level_index = SemanticLogger.send(:level_to_index, level)
27
- @level = SemanticLogger.send(:index_to_level, @level_index)
26
+ @level_index = Levels.index(level)
27
+ @level = Levels.level(@level_index)
28
28
  end
29
29
  end
30
30
 
@@ -112,7 +112,7 @@ module SemanticLogger
112
112
 
113
113
  # Dynamically supply the log level with every measurement call
114
114
  def measure(level, message, params = {}, &block)
115
- index = SemanticLogger.level_to_index(level)
115
+ index = Levels.index(level)
116
116
  if level_index <= index
117
117
  measure_internal(level, index, message, params, &block)
118
118
  elsif block
@@ -38,9 +38,9 @@ module SemanticLogger
38
38
 
39
39
  # :nodoc:
40
40
  def add(severity, message = nil, progname = nil, &block)
41
- index = SemanticLogger.send(:level_to_index, severity)
41
+ index = Levels.index(severity)
42
42
  if level_index <= index
43
- level = SemanticLogger.send(:index_to_level, index)
43
+ level = Levels.level(index)
44
44
  log_internal(level, index, message, progname, &block)
45
45
  true
46
46
  else
@@ -9,6 +9,7 @@ module SemanticLogger
9
9
  autoload :OneLine, 'semantic_logger/formatters/one_line'
10
10
  autoload :Signalfx, 'semantic_logger/formatters/signalfx'
11
11
  autoload :Syslog, 'semantic_logger/formatters/syslog'
12
+ autoload :Fluentd, 'semantic_logger/formatters/fluentd'
12
13
  # @formatter:on
13
14
 
14
15
  # Return formatter that responds to call.
@@ -2,7 +2,7 @@ require 'time'
2
2
  module SemanticLogger
3
3
  module Formatters
4
4
  class Base
5
- attr_accessor :time_format, :log_host, :log_application
5
+ attr_accessor :time_format, :log_host, :log_application, :precision
6
6
 
7
7
  # Time precision varies by Ruby interpreter
8
8
  # JRuby 9.1.8.0 supports microseconds
@@ -17,7 +17,6 @@ module SemanticLogger
17
17
  else
18
18
  6
19
19
  end
20
- TIME_FORMAT = "%Y-%m-%d %H:%M:%S.%#{PRECISION}N".freeze
21
20
 
22
21
  # Parameters
23
22
  # time_format: [String|Symbol|nil]
@@ -25,11 +24,32 @@ module SemanticLogger
25
24
  # :iso_8601 Outputs an ISO8601 Formatted timestamp.
26
25
  # :ms Output in miliseconds since epoch.
27
26
  # nil: Returns Empty string for time ( no time is output ).
28
- # Default: '%Y-%m-%d %H:%M:%S.%6N'
29
- def initialize(time_format: TIME_FORMAT, log_host: true, log_application: true)
30
- @time_format = time_format
27
+ # Default: '%Y-%m-%d %H:%M:%S.%<precision>N'
28
+ # log_host: [Boolean]
29
+ # Whether or not to include hostname in logs
30
+ # Default: true
31
+ # log_application: [Boolean]
32
+ # Whether or not to include application name in logs
33
+ # Default: true
34
+ # precision: [Integer]
35
+ # How many fractional digits to log times with.
36
+ # Default: PRECISION (6, except on older JRuby, where 3)
37
+ def initialize(time_format: nil, log_host: true, log_application: true,
38
+ precision: PRECISION)
39
+ @time_format = time_format || self.class.build_time_format(precision)
31
40
  @log_host = log_host
32
41
  @log_application = log_application
42
+ @precision = precision
43
+ end
44
+
45
+ # Return default time format string
46
+ #
47
+ # Parameters
48
+ # precision: [Integer]
49
+ # How many fractional digits to log times with.
50
+ # Default: PRECISION (6, except on older JRuby, where 3)
51
+ def self.build_time_format(precision=PRECISION)
52
+ "%Y-%m-%d %H:%M:%S.%#{precision}N"
33
53
  end
34
54
 
35
55
  # Date & time
@@ -42,8 +62,10 @@ module SemanticLogger
42
62
  # Return the Time as a formatted string
43
63
  def format_time(time)
44
64
  case time_format
65
+ when :rfc_3339
66
+ time.utc.to_datetime.rfc3339
45
67
  when :iso_8601
46
- time.utc.iso8601(PRECISION)
68
+ time.utc.iso8601(precision)
47
69
  when :ms
48
70
  (time.to_f * 1_000).to_i
49
71
  when :none