semantic_logger 4.0.0 → 4.1.0

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +55 -8
  3. data/lib/semantic_logger.rb +1 -2
  4. data/lib/semantic_logger/ansi_colors.rb +1 -2
  5. data/lib/semantic_logger/appender.rb +17 -15
  6. data/lib/semantic_logger/appender/bugsnag.rb +5 -4
  7. data/lib/semantic_logger/appender/elasticsearch.rb +102 -16
  8. data/lib/semantic_logger/appender/elasticsearch_http.rb +76 -0
  9. data/lib/semantic_logger/appender/file.rb +9 -25
  10. data/lib/semantic_logger/appender/graylog.rb +43 -38
  11. data/lib/semantic_logger/appender/honeybadger.rb +3 -5
  12. data/lib/semantic_logger/appender/http.rb +12 -15
  13. data/lib/semantic_logger/appender/kafka.rb +183 -0
  14. data/lib/semantic_logger/appender/mongodb.rb +3 -3
  15. data/lib/semantic_logger/appender/new_relic.rb +3 -7
  16. data/lib/semantic_logger/appender/sentry.rb +2 -5
  17. data/lib/semantic_logger/appender/splunk.rb +7 -10
  18. data/lib/semantic_logger/appender/splunk_http.rb +16 -16
  19. data/lib/semantic_logger/appender/syslog.rb +43 -122
  20. data/lib/semantic_logger/appender/tcp.rb +28 -9
  21. data/lib/semantic_logger/appender/udp.rb +4 -7
  22. data/lib/semantic_logger/appender/wrapper.rb +3 -7
  23. data/lib/semantic_logger/base.rb +47 -7
  24. data/lib/semantic_logger/formatters/base.rb +29 -10
  25. data/lib/semantic_logger/formatters/color.rb +75 -45
  26. data/lib/semantic_logger/formatters/default.rb +53 -28
  27. data/lib/semantic_logger/formatters/json.rb +7 -8
  28. data/lib/semantic_logger/formatters/raw.rb +97 -1
  29. data/lib/semantic_logger/formatters/syslog.rb +46 -80
  30. data/lib/semantic_logger/formatters/syslog_cee.rb +57 -0
  31. data/lib/semantic_logger/log.rb +17 -67
  32. data/lib/semantic_logger/logger.rb +17 -27
  33. data/lib/semantic_logger/processor.rb +70 -46
  34. data/lib/semantic_logger/semantic_logger.rb +130 -69
  35. data/lib/semantic_logger/subscriber.rb +18 -32
  36. data/lib/semantic_logger/version.rb +1 -1
  37. data/test/appender/elasticsearch_http_test.rb +75 -0
  38. data/test/appender/elasticsearch_test.rb +34 -27
  39. data/test/appender/file_test.rb +2 -2
  40. data/test/appender/honeybadger_test.rb +1 -1
  41. data/test/appender/kafka_test.rb +36 -0
  42. data/test/appender/new_relic_test.rb +1 -1
  43. data/test/appender/sentry_test.rb +1 -1
  44. data/test/appender/syslog_test.rb +2 -2
  45. data/test/appender/wrapper_test.rb +1 -1
  46. data/test/formatters/color_test.rb +154 -0
  47. data/test/formatters/default_test.rb +176 -0
  48. data/test/loggable_test.rb +1 -1
  49. data/test/logger_test.rb +47 -4
  50. data/test/measure_test.rb +2 -2
  51. data/test/semantic_logger_test.rb +34 -6
  52. data/test/test_helper.rb +8 -0
  53. metadata +14 -3
@@ -7,7 +7,7 @@ module SemanticLogger
7
7
  attr_accessor :formatter
8
8
  attr_writer :application, :host
9
9
 
10
- # Returns the current log level if set, otherwise it logs everything it receives
10
+ # Returns the current log level if set, otherwise it logs everything it receives.
11
11
  def level
12
12
  @level || :trace
13
13
  end
@@ -22,17 +22,17 @@ module SemanticLogger
22
22
  # NOOP
23
23
  end
24
24
 
25
- # Returns [SemanticLogger::Formatters::Default] formatter default for this subscriber
25
+ # Returns [SemanticLogger::Formatters::Default] default formatter for this subscriber.
26
26
  def default_formatter
27
27
  SemanticLogger::Formatters::Default.new
28
28
  end
29
29
 
30
- # Allow application name to be set globally or per subscriber
30
+ # Allow application name to be set globally or on a per subscriber basis.
31
31
  def application
32
32
  @application || SemanticLogger.application
33
33
  end
34
34
 
35
- # Allow host name to be set globally or per subscriber
35
+ # Allow host name to be set globally or on a per subscriber basis.
36
36
  def host
37
37
  @host || SemanticLogger.host
38
38
  end
@@ -57,37 +57,32 @@ module SemanticLogger
57
57
  # Proc: Only include log messages where the supplied Proc returns true
58
58
  # The Proc must return true or false.
59
59
  #
60
- # host: [String]
61
- # Name of this host to appear in log messages.
62
- # Default: SemanticLogger.host
63
- #
64
60
  # application: [String]
65
61
  # Name of this application to appear in log messages.
66
62
  # Default: SemanticLogger.application
67
- def initialize(options={}, &block)
68
- # Backward compatibility
69
- options = {level: options} unless options.is_a?(Hash)
70
- options = options.dup
71
- level = options.delete(:level)
72
- filter = options.delete(:filter)
73
- @formatter = extract_formatter(options.delete(:formatter), &block)
74
- @application = options.delete(:application)
75
- @host = options.delete(:host)
76
- raise(ArgumentError, "Unknown options: #{options.inspect}") if options.size > 0
63
+ #
64
+ # host: [String]
65
+ # Name of this host to appear in log messages.
66
+ # Default: SemanticLogger.host
67
+ def initialize(level: nil, formatter: nil, filter: nil, application: nil, host: nil, &block)
68
+ @formatter = extract_formatter(formatter, &block)
69
+ @application = application
70
+ @host = host
77
71
 
78
- # Subscribers don't take a class name, so use this class name if an subscriber
79
- # is logged to directly
72
+ # Subscribers don't take a class name, so use this class name if a subscriber
73
+ # is logged to directly.
80
74
  super(self.class, level, filter)
81
75
  end
82
76
 
83
- # Return the level index for fast comparisons
77
+ # Return the level index for fast comparisons.
84
78
  # Returns the lowest level index if the level has not been explicitly
85
- # set for this instance
79
+ # set for this instance.
86
80
  def level_index
87
81
  @level_index || 0
88
82
  end
89
83
 
90
- # Return formatter that responds to call
84
+ # Return formatter that responds to call.
85
+ #
91
86
  # Supports formatter supplied as:
92
87
  # - Symbol
93
88
  # - Hash ( Symbol => { options })
@@ -114,14 +109,5 @@ module SemanticLogger
114
109
  end
115
110
  end
116
111
 
117
- SUBSCRIBER_OPTIONS = [:level, :formatter, :filter, :application, :host].freeze
118
-
119
- # Returns [Hash] the subscriber common options from the supplied Hash
120
- def extract_subscriber_options!(options)
121
- subscriber_options = {}
122
- SUBSCRIBER_OPTIONS.each { |key| subscriber_options[key] = options.delete(key) if options.has_key?(key) }
123
- subscriber_options
124
- end
125
-
126
112
  end
127
113
  end
@@ -1,3 +1,3 @@
1
1
  module SemanticLogger #:nodoc
2
- VERSION = '4.0.0'
2
+ VERSION = '4.1.0'
3
3
  end
@@ -0,0 +1,75 @@
1
+ require_relative '../test_helper'
2
+
3
+ # Unit Test for SemanticLogger::Appender::Elasticsearch
4
+ module Appender
5
+ class ElasticsearchHttpTest < Minitest::Test
6
+ response_mock = Struct.new(:code, :body)
7
+
8
+ describe SemanticLogger::Appender::ElasticsearchHttp do
9
+ before do
10
+ Net::HTTP.stub_any_instance(:start, true) do
11
+ @appender = SemanticLogger::Appender::ElasticsearchHttp.new(
12
+ url: 'http://localhost:9200'
13
+ )
14
+ end
15
+ @message = 'AppenderElasticsearchTest log message'
16
+ end
17
+
18
+ it 'logs to daily indexes' do
19
+ index = nil
20
+ @appender.stub(:post, -> json, ind { index = ind }) do
21
+ @appender.info @message
22
+ end
23
+ assert_equal "/semantic_logger-#{Time.now.utc.strftime('%Y.%m.%d')}/log", index
24
+ end
25
+
26
+ SemanticLogger::LEVELS.each do |level|
27
+ it "send #{level}" do
28
+ request = nil
29
+ @appender.http.stub(:request, -> r { request = r; response_mock.new('200', 'ok') }) do
30
+ @appender.send(level, @message)
31
+ end
32
+ message = JSON.parse(request.body)
33
+ assert_equal @message, message['message']
34
+ assert_equal level.to_s, message['level']
35
+ refute message['exception']
36
+ end
37
+
38
+ it "sends #{level} exceptions" do
39
+ exc = nil
40
+ begin
41
+ Uh oh
42
+ rescue Exception => e
43
+ exc = e
44
+ end
45
+ request = nil
46
+ @appender.http.stub(:request, -> r { request = r; response_mock.new('200', 'ok') }) do
47
+ @appender.send(level, 'Reading File', exc)
48
+ end
49
+ hash = JSON.parse(request.body)
50
+ assert 'Reading File', hash['message']
51
+ assert exception = hash['exception']
52
+ assert 'NameError', exception['name']
53
+ assert 'undefined local variable or method', exception['message']
54
+ assert_equal level.to_s, hash['level']
55
+ assert exception['stack_trace'].first.include?(__FILE__), exception
56
+ end
57
+
58
+ it "sends #{level} custom attributes" do
59
+ request = nil
60
+ @appender.http.stub(:request, -> r { request = r; response_mock.new('200', 'ok') }) do
61
+ @appender.send(level, @message, {key1: 1, key2: 'a'})
62
+ end
63
+ message = JSON.parse(request.body)
64
+ assert_equal @message, message['message']
65
+ assert_equal level.to_s, message['level']
66
+ refute message['stack_trace']
67
+ assert payload = message['payload'], message
68
+ assert_equal 1, payload['key1'], message
69
+ assert_equal 'a', payload['key2'], message
70
+ end
71
+ end
72
+
73
+ end
74
+ end
75
+ end
@@ -3,36 +3,40 @@ require_relative '../test_helper'
3
3
  # Unit Test for SemanticLogger::Appender::Elasticsearch
4
4
  module Appender
5
5
  class ElasticsearchTest < Minitest::Test
6
- response_mock = Struct.new(:code, :body)
7
-
8
6
  describe SemanticLogger::Appender::Elasticsearch do
9
7
  before do
10
- Net::HTTP.stub_any_instance(:start, true) do
8
+ skip('Concurrent::TimerTask issue is preventing the process from stopping.') if defined? JRuby
9
+ Elasticsearch::Transport::Client.stub_any_instance(:bulk, true) do
11
10
  @appender = SemanticLogger::Appender::Elasticsearch.new(
12
- url: 'http://localhost:9200'
11
+ url: 'http://localhost:9200',
12
+ batch_size: 1 # immediate flush
13
13
  )
14
14
  end
15
15
  @message = 'AppenderElasticsearchTest log message'
16
16
  end
17
17
 
18
+ after do
19
+ @appender.close if @appender
20
+ end
21
+
18
22
  it 'logs to daily indexes' do
19
23
  index = nil
20
- @appender.stub(:post, -> json, ind { index = ind }) do
24
+ @appender.stub(:enqueue, ->(ind, json){ index = ind['index']['_index'] } ) do
21
25
  @appender.info @message
22
26
  end
23
- assert_equal "/semantic_logger-#{Time.now.utc.strftime('%Y.%m.%d')}/log", index
27
+ assert_equal "semantic_logger-#{Time.now.strftime('%Y.%m.%d')}", index
24
28
  end
25
29
 
26
30
  SemanticLogger::LEVELS.each do |level|
27
31
  it "send #{level}" do
28
32
  request = nil
29
- @appender.http.stub(:request, -> r { request = r; response_mock.new('200', 'ok') }) do
33
+ @appender.client.stub(:bulk, -> r { request = r; {"status" => 201 } }) do
30
34
  @appender.send(level, @message)
31
35
  end
32
- message = JSON.parse(request.body)
33
- assert_equal @message, message['message']
34
- assert_equal level.to_s, message['level']
35
- refute message['exception']
36
+
37
+ message = request[:body][1]
38
+ assert_equal @message, message[:message]
39
+ assert_equal level, message[:level]
36
40
  end
37
41
 
38
42
  it "sends #{level} exceptions" do
@@ -43,30 +47,33 @@ module Appender
43
47
  exc = e
44
48
  end
45
49
  request = nil
46
- @appender.http.stub(:request, -> r { request = r; response_mock.new('200', 'ok') }) do
50
+ @appender.client.stub(:bulk, -> r { request = r; {"status" => 201 } }) do
47
51
  @appender.send(level, 'Reading File', exc)
48
52
  end
49
- hash = JSON.parse(request.body)
50
- assert 'Reading File', hash['message']
51
- assert exception = hash['exception']
52
- assert 'NameError', exception['name']
53
- assert 'undefined local variable or method', exception['message']
54
- assert_equal level.to_s, hash['level']
55
- assert exception['stack_trace'].first.include?(__FILE__), exception
53
+
54
+ hash = request[:body][1]
55
+
56
+ assert 'Reading File', hash[:message]
57
+ assert exception = hash[:exception]
58
+ assert 'NameError', exception[:name]
59
+ assert 'undefined local variable or method', exception[:message]
60
+ assert_equal level, hash[:level]
61
+ assert exception[:stack_trace].first.include?(__FILE__), exception
56
62
  end
57
63
 
58
64
  it "sends #{level} custom attributes" do
59
65
  request = nil
60
- @appender.http.stub(:request, -> r { request = r; response_mock.new('200', 'ok') }) do
66
+ @appender.client.stub(:bulk, -> r { request = r; {"status" => 201 } }) do
61
67
  @appender.send(level, @message, {key1: 1, key2: 'a'})
62
68
  end
63
- message = JSON.parse(request.body)
64
- assert_equal @message, message['message']
65
- assert_equal level.to_s, message['level']
66
- refute message['stack_trace']
67
- assert payload = message['payload'], message
68
- assert_equal 1, payload['key1'], message
69
- assert_equal 'a', payload['key2'], message
69
+
70
+ message = request[:body][1]
71
+ assert_equal @message, message[:message]
72
+ assert_equal level, message[:level]
73
+ refute message[:stack_trace]
74
+ assert payload = message[:payload], message
75
+ assert_equal 1, payload[:key1], message
76
+ assert_equal 'a', payload[:key2], message
70
77
  end
71
78
  end
72
79
 
@@ -10,7 +10,7 @@ module Appender
10
10
  SemanticLogger.default_level = :trace
11
11
  @time = Time.new
12
12
  @io = StringIO.new
13
- @appender = SemanticLogger::Appender::File.new(@io)
13
+ @appender = SemanticLogger::Appender::File.new(io: @io)
14
14
  @hash = {session_id: 'HSSKLEU@JDK767', tracking_number: 12345}
15
15
  @hash_str = @hash.inspect.sub("{", "\\{").sub("}", "\\}")
16
16
  @thread_name = Thread.current.name
@@ -86,7 +86,7 @@ module Appender
86
86
 
87
87
  describe 'custom formatter' do
88
88
  before do
89
- @appender = SemanticLogger::Appender::File.new(@io) do |log|
89
+ @appender = SemanticLogger::Appender::File.new(io: @io) do |log|
90
90
  tags = log.tags.collect { |tag| "[#{tag}]" }.join(' ') + ' ' if log.tags && (log.tags.size > 0)
91
91
 
92
92
  message = log.message.to_s
@@ -5,7 +5,7 @@ module Appender
5
5
  class HoneybadgerTest < Minitest::Test
6
6
  describe SemanticLogger::Appender::Honeybadger do
7
7
  before do
8
- @appender = SemanticLogger::Appender::Honeybadger.new(:trace)
8
+ @appender = SemanticLogger::Appender::Honeybadger.new(level: :trace)
9
9
  @message = 'AppenderHoneybadgerTest log message'
10
10
  SemanticLogger.backtrace_level = :error
11
11
  end
@@ -0,0 +1,36 @@
1
+ require_relative '../test_helper'
2
+
3
+ module Appender
4
+ class KafkaTest < Minitest::Test
5
+ describe SemanticLogger::Appender::Kafka do
6
+ before do
7
+ @appender = SemanticLogger::Appender::Kafka.new(
8
+ seed_brokers: ['http://localhost:9092']
9
+ )
10
+ @message = 'AppenderKafkaTest log message'
11
+ end
12
+
13
+ after do
14
+ @appender.close if @appender
15
+ end
16
+
17
+ it 'sends log messages in JSON format' do
18
+ message = nil
19
+ options = nil
20
+ ::Kafka::Producer.stub_any_instance(:produce, -> value, **opts { message = value; options = opts }) do
21
+ @appender.info(@message)
22
+ @appender.flush
23
+ end
24
+
25
+ h = JSON.parse(message)
26
+ assert_equal 'info', h['level']
27
+ assert_equal @message, h['message']
28
+ assert_equal "SemanticLogger::Appender::Kafka", h['name']
29
+ assert_equal $$, h['pid']
30
+
31
+ assert_equal 'log_messages', options[:topic]
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -8,7 +8,7 @@ module Appender
8
8
  describe SemanticLogger::Appender::NewRelic do
9
9
 
10
10
  before do
11
- @appender = SemanticLogger::Appender::NewRelic.new(:error)
11
+ @appender = SemanticLogger::Appender::NewRelic.new
12
12
  @message = 'AppenderNewRelicTest log message'
13
13
  end
14
14
 
@@ -5,7 +5,7 @@ module Appender
5
5
  class SentryTest < Minitest::Test
6
6
  describe SemanticLogger::Appender::Sentry do
7
7
  before do
8
- @appender = SemanticLogger::Appender::Sentry.new(:trace)
8
+ @appender = SemanticLogger::Appender::Sentry.new(level: :trace)
9
9
  @message = 'AppenderRavenTest log message'
10
10
  SemanticLogger.backtrace_level = :error
11
11
  end
@@ -22,7 +22,7 @@ module Appender
22
22
  message = nil
23
23
  Net::TCPClient.stub_any_instance(:closed?, false) do
24
24
  Net::TCPClient.stub_any_instance(:connect, nil) do
25
- syslog_appender = SemanticLogger::Appender::Syslog.new(server: 'tcp://localhost:88888', level: :debug)
25
+ syslog_appender = SemanticLogger::Appender::Syslog.new(url: 'tcp://localhost:88888', level: :debug)
26
26
  syslog_appender.remote_syslog.stub(:write, Proc.new { |data| message = data }) do
27
27
  syslog_appender.debug 'AppenderSyslogTest log message'
28
28
  end
@@ -33,7 +33,7 @@ module Appender
33
33
 
34
34
  it 'handle remote syslog over UDP' do
35
35
  message = nil
36
- syslog_appender = SemanticLogger::Appender::Syslog.new(server: 'udp://localhost:88888', level: :debug)
36
+ syslog_appender = SemanticLogger::Appender::Syslog.new(url: 'udp://localhost:88888', level: :debug)
37
37
  UDPSocket.stub_any_instance(:send, -> msg, num, host, port { message = msg }) do
38
38
  syslog_appender.debug 'AppenderSyslogTest log message'
39
39
  end
@@ -11,7 +11,7 @@ module Appender
11
11
 
12
12
  @time = Time.new
13
13
  @mock_logger = MockLogger.new
14
- @appender = SemanticLogger::Appender::Wrapper.new(@mock_logger)
14
+ @appender = SemanticLogger::Appender::Wrapper.new(logger: @mock_logger)
15
15
  @hash = {session_id: 'HSSKLEU@JDK767', tracking_number: 12345}
16
16
  @hash_str = @hash.inspect.sub("{", "\\{").sub("}", "\\}")
17
17
  @thread_name = Thread.current.name
@@ -0,0 +1,154 @@
1
+ require_relative '../test_helper'
2
+
3
+ module SemanticLogger
4
+ module Formatters
5
+ class ColorTest < Minitest::Test
6
+ describe Color do
7
+ let(:log_time) do
8
+ Time.utc(2017, 1, 14, 8, 32, 5.375276)
9
+ end
10
+
11
+ let(:level) do
12
+ :debug
13
+ end
14
+
15
+ let(:log) do
16
+ # :level, :thread_name, :name, :message, :payload, :time, :duration, :tags, :level_index, :exception, :metric, :backtrace, :metric_amount, :named_tags
17
+ log = SemanticLogger::Log.new('ColorTest', level)
18
+ log.time = log_time
19
+ log
20
+ end
21
+
22
+ let(:expected_time) do
23
+ SemanticLogger::Formatters::Base::PRECISION == 3 ? '2017-01-14 08:32:05.375' : '2017-01-14 08:32:05.375276'
24
+ end
25
+
26
+ let(:set_exception) do
27
+ begin
28
+ raise 'Oh no'
29
+ rescue Exception => exc
30
+ log.exception = exc
31
+ end
32
+ end
33
+
34
+ let(:backtrace) do
35
+ [
36
+ "test/formatters/default_test.rb:35:in `block (2 levels) in <class:DefaultTest>'",
37
+ "gems/ruby-2.3.3/gems/minitest-5.10.1/lib/minitest/spec.rb:247:in `instance_eval'",
38
+ "gems/ruby-2.3.3/gems/minitest-5.10.1/lib/minitest/spec.rb:247:in `block (2 levels) in let'",
39
+ "gems/ruby-2.3.3/gems/minitest-5.10.1/lib/minitest/spec.rb:247:in `fetch'",
40
+ "ruby-2.3.3/gems/minitest-5.10.1/lib/minitest/spec.rb:247:in `block in let'",
41
+ "test/formatters/default_test.rb:65:in `block (3 levels) in <class:DefaultTest>'",
42
+ "ruby-2.3.3/gems/minitest-5.10.1/lib/minitest/test.rb:105:in `block (3 levels) in run'"
43
+ ]
44
+ end
45
+
46
+ let(:bold) do
47
+ SemanticLogger::AnsiColors::BOLD
48
+ end
49
+
50
+ let(:clear) do
51
+ SemanticLogger::AnsiColors::CLEAR
52
+ end
53
+
54
+ let(:color) do
55
+ SemanticLogger::AnsiColors::GREEN
56
+ end
57
+
58
+ let(:formatter) do
59
+ formatter = SemanticLogger::Formatters::Color.new
60
+ # Does not use the logger instance for formatting purposes
61
+ formatter.call(log, nil)
62
+ formatter
63
+ end
64
+
65
+ describe 'level' do
66
+ it 'logs single character' do
67
+ assert_equal "#{color}D#{clear}", formatter.level
68
+ end
69
+ end
70
+
71
+ describe 'tags' do
72
+ it 'logs tags' do
73
+ log.tags = %w(first second third)
74
+ assert_equal "[#{color}first#{clear}] [#{color}second#{clear}] [#{color}third#{clear}]", formatter.tags
75
+ end
76
+ end
77
+
78
+ describe 'named_tags' do
79
+ it 'logs named tags' do
80
+ log.named_tags = {first: 1, second: 2, third: 3}
81
+ assert_equal "{#{color}first: 1#{clear}, #{color}second: 2#{clear}, #{color}third: 3#{clear}}", formatter.named_tags
82
+ end
83
+ end
84
+
85
+ describe 'duration' do
86
+ it 'logs long duration' do
87
+ log.duration = 1_000_000.34567
88
+ assert_equal "(#{bold}16m 40s#{clear})", formatter.duration
89
+ end
90
+
91
+ it 'logs short duration' do
92
+ log.duration = 1.34567
93
+ duration = SemanticLogger::Formatters::Base::PRECISION == 3 ? "(#{bold}1ms#{clear})" : "(#{bold}1.346ms#{clear})"
94
+ assert_equal duration, formatter.duration
95
+ end
96
+ end
97
+
98
+ describe 'name' do
99
+ it 'logs name' do
100
+ assert_equal "#{color}ColorTest#{clear}", formatter.name
101
+ end
102
+ end
103
+
104
+ describe 'payload' do
105
+ it 'logs hash payload' do
106
+ log.payload = {first: 1, second: 2, third: 3}
107
+ assert_equal "-- #{log.payload.ai(multiline: false)}", formatter.payload
108
+ end
109
+
110
+ it 'skips nil payload' do
111
+ refute formatter.payload
112
+ end
113
+
114
+ it 'skips empty payload' do
115
+ log.payload = {}
116
+ refute formatter.payload
117
+ end
118
+ end
119
+
120
+ describe 'exception' do
121
+ it 'logs exception' do
122
+ set_exception
123
+ str = "-- Exception: #{color}RuntimeError: Oh no#{clear}\n"
124
+ assert_equal str, formatter.exception.lines.first
125
+ end
126
+
127
+ it 'skips nil exception' do
128
+ refute formatter.exception
129
+ end
130
+ end
131
+
132
+ describe 'call' do
133
+ it 'returns minimal elements' do
134
+ assert_equal "#{expected_time} #{color}D#{clear} [#{$$}:#{Thread.current.name}] #{color}ColorTest#{clear}", formatter.call(log, nil)
135
+ end
136
+
137
+ it 'retuns all elements' do
138
+ log.tags = %w(first second third)
139
+ log.named_tags = {first: 1, second: 2, third: 3}
140
+ log.duration = 1.34567
141
+ log.message = "Hello World"
142
+ log.payload = {first: 1, second: 2, third: 3}
143
+ log.backtrace = backtrace
144
+ set_exception
145
+ duration = SemanticLogger::Formatters::Base::PRECISION == 3 ? '1' : '1.346'
146
+ str = "#{expected_time} #{color}D#{clear} [#{$$}:#{Thread.current.name} default_test.rb:35] [#{color}first#{clear}] [#{color}second#{clear}] [#{color}third#{clear}] {#{color}first: 1#{clear}, #{color}second: 2#{clear}, #{color}third: 3#{clear}} (#{bold}#{duration}ms#{clear}) #{color}ColorTest#{clear} -- Hello World -- #{{:first => 1, :second => 2, :third => 3}.ai(multiline: false)} -- Exception: #{color}RuntimeError: Oh no#{clear}\n"
147
+ assert_equal str, formatter.call(log, nil).lines.first
148
+ end
149
+ end
150
+
151
+ end
152
+ end
153
+ end
154
+ end