hatchet 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/RELEASE.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Release notes
2
2
 
3
+ ## 0.2.0
4
+
5
+ * Added nested diagnostic context and Rack middleware to clear it between
6
+ requests
7
+
8
+ ### Note
9
+
10
+ The `Hatchet::Message` constructor has been altered, going forward it will take
11
+ a Hash of arguments instead of fixed arguments. It is currently backwards
12
+ compatible but this will likely be dropped for 1.0.0 so it is advised you update
13
+ your libraries now.
14
+
15
+ This should only affect custom formatters which may want to take advantage of
16
+ the nested diagnostic context which is now available anyway.
17
+
3
18
  ## 0.1.0
4
19
 
5
20
  No changes from 0.0.20, just time for a minor version release.
@@ -1,7 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
- require 'logger'
4
-
5
3
  require_relative 'hatchet/level_manager'
6
4
  require_relative 'hatchet/backtrace_formatter'
7
5
  require_relative 'hatchet/thread_name_formatter'
@@ -10,6 +8,8 @@ require_relative 'hatchet/delegating_formatter'
10
8
  require_relative 'hatchet/hatchet_logger'
11
9
  require_relative 'hatchet/logger_appender'
12
10
  require_relative 'hatchet/message'
11
+ require_relative 'hatchet/middleware'
12
+ require_relative 'hatchet/nested_diagnostic_context'
13
13
  require_relative 'hatchet/plain_formatter'
14
14
  require_relative 'hatchet/simple_formatter'
15
15
  require_relative 'hatchet/standard_formatter'
@@ -66,7 +66,7 @@ module Hatchet
66
66
  # Returns a HatchetLogger for the object.
67
67
  #
68
68
  def logger
69
- @_hatchet_logger ||= HatchetLogger.new self, Hatchet.configuration
69
+ @_hatchet_logger ||= HatchetLogger.new(self, Hatchet.configuration, Hatchet::NestedDiagnosticContext.current)
70
70
  end
71
71
 
72
72
  # Public: Returns a HatchetLogger for the object.
@@ -1,5 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
+ require 'logger'
4
+
3
5
  module Hatchet
4
6
 
5
7
  # Public: Class that handles logging calls and distributes them to all its
@@ -60,15 +62,21 @@ module Hatchet
60
62
  Logger::FATAL => :fatal
61
63
  }
62
64
 
65
+ # Public: Gets the NestedDiagnosticContext for the logger.
66
+ #
67
+ attr_reader :ndc
68
+
63
69
  # Internal: Creates a new logger.
64
70
  #
65
71
  # host - The object the logger gains its context from.
66
72
  # configuration - The configuration of Hatchet.
73
+ # ndc - The nested diagnostic context of the logger.
67
74
  #
68
- def initialize(host, configuration)
69
- @context = context host
75
+ def initialize(host, configuration, ndc)
76
+ @context = host_name(host)
70
77
  @configuration = configuration
71
78
  @appenders = configuration.appenders
79
+ @ndc = ndc
72
80
  end
73
81
 
74
82
  [:debug, :info, :warn, :error, :fatal].each do |level|
@@ -103,7 +111,7 @@ module Hatchet
103
111
  #
104
112
  define_method level do |message = nil, error = nil, &block|
105
113
  return unless message or block
106
- add level, Message.new(message, error, &block)
114
+ add level, Message.new(ndc: @ndc.context.clone, message: message, error: error, &block)
107
115
  end
108
116
 
109
117
  # Public: Returns true if any of the appenders will log messages for the
@@ -193,7 +201,7 @@ module Hatchet
193
201
  # Ruby, the host itself when the host is a module, otherwise the object's
194
202
  # class.
195
203
  #
196
- def context(host)
204
+ def host_name(host)
197
205
  if host.inspect == 'main'
198
206
  'main'
199
207
  elsif [Module, Class].include? host.class
@@ -8,6 +8,9 @@ module Hatchet
8
8
  # If an error is associated with the message this will be available via the
9
9
  # #error attribute.
10
10
  #
11
+ # The nested diagnostic context of the message will be availble via the #ndc
12
+ # attribute.
13
+ #
11
14
  # Blocks will be lazily evaluated once for all appenders when required.
12
15
  #
13
16
  class Message
@@ -16,27 +19,61 @@ module Hatchet
16
19
  #
17
20
  attr_reader :error
18
21
 
19
- # Internal: Creates a new message.
22
+ # Public: Gets the nested diagnostic context values.
23
+ #
24
+ attr_reader :ndc
25
+
26
+ # Public: Creates a new message.
27
+ #
28
+ # args - The Hash used to provide context for the message (default: {}):
29
+ # :ndc - An Array of nested diagnostic context values
30
+ # (default: []).
31
+ # :message - An already evaluated message, usually a String
32
+ # (default: nil).
33
+ # :error - An error that is associated with the message
34
+ # (default: nil).
35
+ # block - An optional block which will provide a message when invoked.
36
+ #
37
+ # Examples
38
+ #
39
+ # Message.new(ndc: [], message: "Evaluated message", error: e)
40
+ # Message.new(ndc: %w{Foo Bar}) { "Lazily evaluated message" }
41
+ #
42
+ # The signature of the constructor was originally:
20
43
  #
21
44
  # message - An already evaluated message, usually a String (default: nil).
22
45
  # error - An error that is associated with the message (default: nil).
23
46
  # block - An optional block which will provide a message when invoked.
24
47
  #
25
- # One of message or block must be provided. If both are provided then the
26
- # block is preferred as it is assumed to provide more detail.
48
+ # This format is also supported for compatibility to version 0.1.0 and below
49
+ # and will be deprecated in the future.
27
50
  #
28
51
  # Examples
29
52
  #
30
- # Message.new "Evaluated message"
53
+ # Message.new("Evaluated message", e)
31
54
  # Message.new { "Lazily evaluated message" }
32
55
  #
33
- def initialize(message = nil, error = nil, &block)
34
- @block = block
35
- @error = error
36
- @message = message unless @block
56
+ # One of message or block must be provided. If both are provided then the
57
+ # block is preferred as it is assumed to provide more detail.
58
+ #
59
+ def initialize(args = {}, error = nil, &block)
60
+ if args.kind_of? Hash
61
+ # If args is a Hash then using new constructor format or no parameters
62
+ # specified. Either way, use the new format.
63
+ @ndc = args[:ndc] || []
64
+ @error = args[:error]
65
+ @message = args[:message] unless block
66
+ else
67
+ # Otherwise assume the old format and coerce args accordingly.
68
+ @ndc = []
69
+ @error = error
70
+ @message = args unless block
71
+ end
72
+
73
+ @block = block
37
74
  end
38
75
 
39
- # Internal: Returns the String representation of the message.
76
+ # Public: Returns the String representation of the message.
40
77
  #
41
78
  def to_s
42
79
  @message ||= @block.call
@@ -0,0 +1,34 @@
1
+ module Hatchet
2
+
3
+ # Public: Middleware for making sure the nested diagnostic context is cleared
4
+ # between requests.
5
+ #
6
+ class Middleware
7
+ include Hatchet
8
+
9
+ # Public: Creates a new instance of the middleware, wrapping the given
10
+ # application.
11
+ #
12
+ # app - The application to wrap.
13
+ #
14
+ def initialize(app)
15
+ @app = app
16
+ end
17
+
18
+ # Public: Calls the wrapped application with the given environment, ensuring
19
+ # the nested diagnostic context is cleared afterwards.
20
+ #
21
+ # env - The enviroment Hash for the request.
22
+ #
23
+ # Returns the status, headers, body Array returned by the wrapped
24
+ # application.
25
+ #
26
+ def call(env)
27
+ @app.call(env)
28
+ ensure
29
+ log.ndc.clear!
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,160 @@
1
+ module Hatchet
2
+
3
+ # Public: Class that manages the nested diagnostic context for a thread.
4
+ #
5
+ # All access to this class is performed through internal classes.
6
+ #
7
+ class NestedDiagnosticContext
8
+
9
+ # Internal: Gets the current context stack.
10
+ #
11
+ attr_reader :context
12
+
13
+ # Internal: Gets the NestedDiagnosticContext for the current thread, lazily
14
+ # initializing it as necessary.
15
+ #
16
+ def self.current
17
+ Thread.current[:hatchet_ndc] ||= NestedDiagnosticContext.new
18
+ end
19
+
20
+ # Internal: Creates a new instance of the class.
21
+ #
22
+ def initialize
23
+ clear!
24
+ end
25
+
26
+ # Public: Adds one or more messages onto the context stack.
27
+ #
28
+ # values - One or more messages to add to the context stack.
29
+ #
30
+ # Returns nothing.
31
+ #
32
+ def push(*values)
33
+ @context.push(*values)
34
+ end
35
+
36
+ # Public: Removes one or more message from the context stack.
37
+ #
38
+ # n - The number of messages to remove from the context stack (default:
39
+ # nil). If no number is provided then one message will be removed.
40
+ #
41
+ # Returns the message or messages removed from the context stack. If n was
42
+ # not specified it will return a single message, otherwise it will return an
43
+ # Array of up to n messages.
44
+ #
45
+ def pop(n = nil)
46
+ if n
47
+ @context.pop(n)
48
+ else
49
+ @context.pop
50
+ end
51
+ end
52
+
53
+ # Public: Adds one more or message onto the context stack for the scope of
54
+ # the given block.
55
+ #
56
+ # values - One or more messages to add to the context stack for the scope of
57
+ # the given block.
58
+ # block - The block to execute with the additional messages.
59
+ #
60
+ # Returns the result of calling the block.
61
+ #
62
+ def scope(*values, &block)
63
+ before = @context.clone
64
+ push(*values)
65
+ block.call
66
+ ensure
67
+ @context = before
68
+ end
69
+
70
+ # Public: Clears all messages from the context stack.
71
+ #
72
+ # Intend for use when the current thread is, or may, be reused in the future
73
+ # and the accumlated context is no longer wanted.
74
+ #
75
+ # Returns nothing.
76
+ #
77
+ def clear!
78
+ @context = ContextStack.new
79
+ nil
80
+ end
81
+
82
+ # Public: Class for holding the context stack of a NestedDiagnosticContext.
83
+ #
84
+ # Deliberately intended to have a similar API to Array to make testing
85
+ # easier.
86
+ #
87
+ class ContextStack
88
+
89
+ # Internal: Gets the internal stack.
90
+ #
91
+ attr_reader :stack
92
+
93
+ # Internal: Creates a new instance.
94
+ #
95
+ # stack - An Array of values to initialize the stack with (default: []).
96
+ #
97
+ def initialize(stack = [])
98
+ @stack = stack
99
+ end
100
+
101
+ # Public: Returns true if the stack contains any messages, otherwise
102
+ # returns false.
103
+ #
104
+ def any?
105
+ @stack.size != 0
106
+ end
107
+
108
+ # Internal: Returns a clone of the stack.
109
+ #
110
+ def clone
111
+ ContextStack.new(@stack.clone)
112
+ end
113
+
114
+ # Public: Returns a String created by converting each message of the stack
115
+ # to a String, separated by separator.
116
+ #
117
+ # separator - The String to separate the messages of the stack with
118
+ # (default: $,).
119
+ #
120
+ # Returns a String created by converting each message of the stack to a
121
+ # String, separated by separator.
122
+ #
123
+ def join(separator = $,)
124
+ @stack.join(separator)
125
+ end
126
+
127
+ # Internal: Pushes the given messages onto the stack.
128
+ #
129
+ # values - One or more messages to add to the context stack.
130
+ #
131
+ # Returns nothing.
132
+ #
133
+ def push(*values)
134
+ @stack.push(*values)
135
+ nil
136
+ end
137
+
138
+ # Internal: Removes one or more message from the stack.
139
+ #
140
+ # n - The number of messages to remove from the cstack (default: nil). If
141
+ # no number is provided then one message will be removed.
142
+ #
143
+ # Returns the message or messages removed from the context stack. If n was
144
+ # not specified it will return a single message, otherwise it will return
145
+ # an Array of up to n messages.
146
+ #
147
+ def pop(n = nil)
148
+ if n
149
+ @stack.pop(n)
150
+ else
151
+ @stack.pop
152
+ end
153
+ end
154
+
155
+ end
156
+
157
+ end
158
+
159
+ end
160
+
@@ -15,6 +15,13 @@ module Hatchet
15
15
  #
16
16
  self.config.hatchet = Hatchet.configuration
17
17
 
18
+ # Add the Hatchet::Middleware to the middleware stack to enable nested
19
+ # diagnostic context clearance between requests.
20
+ #
21
+ initializer "hatchet_railtie.insert_middleware" do |app|
22
+ app.config.middleware.use Hatchet::Middleware
23
+ end
24
+
18
25
  # Wrap the default Rails.logger, Rails.application.assets.logger, and all
19
26
  # log subscribers found in ActiveSupport::LogSubscriber.log_subscribers
20
27
  # collection on initialization.
@@ -31,11 +31,12 @@ module Hatchet
31
31
  #
32
32
  def format(level, context, message)
33
33
  msg = message.to_s.strip
34
+ thread = thread_context ? "[#{thread_name}] - " : nil
34
35
 
35
- if thread_context
36
- msg = "[#{thread_name}] - #{level.to_s.upcase} - #{context} - #{msg}"
36
+ if message.ndc.any?
37
+ msg = "#{thread}#{level.to_s.upcase} - #{context} #{message.ndc.join(' ')} - #{msg}"
37
38
  else
38
- msg = "#{level.to_s.upcase} - #{context} - #{msg}"
39
+ msg = "#{thread}#{level.to_s.upcase} - #{context} - #{msg}"
39
40
  end
40
41
 
41
42
  with_backtrace(message, msg)
@@ -12,6 +12,7 @@ module Hatchet
12
12
  #
13
13
  def initialize
14
14
  @secs = 0
15
+ @level_cache = {}
15
16
  end
16
17
 
17
18
  # Public: Returns the formatted message.
@@ -29,7 +30,12 @@ module Hatchet
29
30
  #
30
31
  def format(level, context, message)
31
32
  msg = message.to_s.strip
32
- msg = "#{timestamp} [#{thread_name}] #{format_level level} #{context} - #{msg}"
33
+
34
+ if message.ndc.any?
35
+ msg = "#{timestamp} [#{thread_name}] #{format_level(level)} #{context} #{message.ndc.join(' ')} - #{msg}"
36
+ else
37
+ msg = "#{timestamp} [#{thread_name}] #{format_level(level)} #{context} - #{msg}"
38
+ end
33
39
 
34
40
  with_backtrace(message, msg)
35
41
  end
@@ -58,7 +64,7 @@ module Hatchet
58
64
  # Private: Returns the level formatted for log output as a String.
59
65
  #
60
66
  def format_level(level)
61
- level.to_s.upcase.ljust(5)
67
+ @level_cache[level] ||= level.to_s.upcase.ljust(5)
62
68
  end
63
69
 
64
70
  end
@@ -4,6 +4,6 @@ module Hatchet
4
4
 
5
5
  # Public: The version of Hatchet.
6
6
  #
7
- VERSION = '0.1.0'
7
+ VERSION = '0.2.0'
8
8
 
9
9
  end
@@ -17,5 +17,6 @@ class StoringAppender
17
17
  def add(level, context, message)
18
18
  @messages << OpenStruct.new(level: level, context: context, message: message)
19
19
  end
20
+
20
21
  end
21
22
 
@@ -8,9 +8,15 @@ describe HatchetLogger do
8
8
  let(:appenders) { [appender, disabled_appender] }
9
9
  let(:configuration) { Configuration.new }
10
10
  let(:context) { Context::Class.new }
11
+ let(:ndc) { NestedDiagnosticContext.new }
12
+
13
+ def last_message
14
+ appender.messages.last.message
15
+ end
16
+
11
17
  let(:subject) do
12
18
  configuration.appenders.push(*appenders)
13
- HatchetLogger.new context, configuration
19
+ HatchetLogger.new context, configuration, ndc
14
20
  end
15
21
 
16
22
  ALL_LEVELS.each do |level|
@@ -139,5 +145,81 @@ describe HatchetLogger do
139
145
  end
140
146
  end
141
147
  end
148
+
149
+ describe 'nested diagnostic context' do
150
+
151
+ describe 'pushing context' do
152
+
153
+ it 'passes the context with the message' do
154
+ subject.ndc.push(:foo)
155
+ subject.info 'Message'
156
+ assert_equal [:foo], last_message.ndc.stack
157
+ end
158
+
159
+ it 'stacks contexts with the message' do
160
+ subject.ndc.push(:foo, :bar, :baz)
161
+ subject.info 'Message'
162
+ assert_equal [:foo, :bar, :baz], last_message.ndc.stack
163
+ end
164
+
165
+ it 'pops contexts individually' do
166
+ subject.ndc.push(:foo, :bar, :baz)
167
+
168
+ subject.info 'Message'
169
+ assert_equal [:foo, :bar, :baz], last_message.ndc.stack
170
+
171
+ subject.ndc.pop
172
+ subject.info 'Message'
173
+ assert_equal [:foo, :bar], last_message.ndc.stack
174
+
175
+ subject.ndc.pop
176
+ subject.info 'Message'
177
+ assert_equal [:foo], last_message.ndc.stack
178
+
179
+ subject.ndc.pop
180
+ subject.info 'Message'
181
+ assert_equal [], last_message.ndc.stack
182
+ end
183
+
184
+ it 'pops a specified number of contexts' do
185
+ subject.ndc.push(:foo, :bar, :baz)
186
+
187
+ subject.info 'Message'
188
+ assert_equal [:foo, :bar, :baz], last_message.ndc.stack
189
+
190
+ subject.ndc.pop(2)
191
+ subject.info 'Message'
192
+ assert_equal [:foo], last_message.ndc.stack
193
+
194
+ subject.ndc.pop(2)
195
+ subject.info 'Message'
196
+ assert_equal [], last_message.ndc.stack
197
+ end
198
+
199
+ it 'scopes contexts when used with blocks' do
200
+ subject.ndc.scope(:foo) do
201
+ subject.info 'Message'
202
+ assert_equal [:foo], last_message.ndc.stack
203
+ end
204
+
205
+ subject.info 'Message'
206
+ assert_equal [], last_message.ndc.stack
207
+ end
208
+
209
+ it 'can clear all contexts' do
210
+ subject.ndc.push(:foo, :bar, :baz)
211
+
212
+ subject.info 'Message'
213
+ assert_equal [:foo, :bar, :baz], last_message.ndc.stack
214
+
215
+ subject.ndc.clear!
216
+
217
+ subject.info 'Message'
218
+ assert_equal [], last_message.ndc.stack
219
+ end
220
+
221
+ end
222
+
223
+ end
142
224
  end
143
225
 
@@ -4,7 +4,7 @@ require_relative 'spec_helper'
4
4
 
5
5
  describe Message do
6
6
  describe 'providing an evaluted message' do
7
- let(:subject) { Message.new 'Evaluated' }
7
+ let(:subject) { Message.new(ndc: [], message: 'Evaluated') }
8
8
 
9
9
  it 'returns the given message' do
10
10
  assert_equal 'Evaluated', subject.to_s
@@ -14,7 +14,7 @@ describe Message do
14
14
  describe 'providing a block message' do
15
15
  let(:subject) do
16
16
  @evaluated = 0
17
- Message.new do
17
+ Message.new(ndc: []) do
18
18
  @evaluated += 1
19
19
  'Block'
20
20
  end
@@ -33,7 +33,7 @@ describe Message do
33
33
 
34
34
  describe 'providing both an evaluated and block message' do
35
35
  let(:subject) do
36
- Message.new 'Evaluated' do
36
+ Message.new(ndc: [], message: 'Evaluated') do
37
37
  'Block'
38
38
  end
39
39
  end
@@ -42,5 +42,47 @@ describe Message do
42
42
  assert_equal 'Block', subject.to_s
43
43
  end
44
44
  end
45
+
46
+ describe 'supporting the old constructor format' do
47
+ describe 'providing an evaluted message' do
48
+ let(:subject) { Message.new('Evaluated') }
49
+
50
+ it 'returns the given message' do
51
+ assert_equal 'Evaluated', subject.to_s
52
+ end
53
+ end
54
+
55
+ describe 'providing a block message' do
56
+ let(:subject) do
57
+ @evaluated = 0
58
+ Message.new do
59
+ @evaluated += 1
60
+ 'Block'
61
+ end
62
+ end
63
+
64
+ it 'returns the result of evaluating the block' do
65
+ assert_equal 'Block', subject.to_s
66
+ end
67
+
68
+ it 'only evaluates the block once for multiple calls' do
69
+ subject.to_s
70
+ subject.to_s
71
+ assert_equal 1, @evaluated
72
+ end
73
+ end
74
+
75
+ describe 'providing both an evaluated and block message' do
76
+ let(:subject) do
77
+ Message.new('Evaluated') do
78
+ 'Block'
79
+ end
80
+ end
81
+
82
+ it 'returns the result of evaluating the block' do
83
+ assert_equal 'Block', subject.to_s
84
+ end
85
+ end
86
+ end
45
87
  end
46
88
 
@@ -0,0 +1,115 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe Middleware do
4
+
5
+ class App
6
+ include Hatchet
7
+
8
+ def initialize
9
+ @request = 1
10
+ end
11
+
12
+ def call(env)
13
+ log.ndc.push(@request)
14
+
15
+ log.info "Start"
16
+
17
+ one = One.new
18
+ one.run(env)
19
+
20
+ log.ndc.push(:end)
21
+ log.info "Finish"
22
+
23
+ @request += 1
24
+
25
+ [:status, :headers, :body]
26
+ end
27
+
28
+ class One
29
+ include Hatchet
30
+
31
+ def run(env)
32
+ log.ndc.push(:one)
33
+ log.info env[:one]
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ let(:storing_appender) { StoringAppender.new :debug }
40
+ let(:messages) { storing_appender.messages }
41
+
42
+ let(:subject) do
43
+ Hatchet.configure do |config|
44
+ config.reset!
45
+ config.appenders << storing_appender
46
+ end
47
+
48
+ app = App.new
49
+ Middleware.new(app)
50
+ end
51
+
52
+ before do
53
+ messages.clear
54
+ end
55
+
56
+ describe "maintaining the result" do
57
+
58
+ before do
59
+ @status, @headers, @body = subject.call(one: 'Testing')
60
+ end
61
+
62
+ it "maintains the status" do
63
+ assert_equal :status, @status
64
+ end
65
+
66
+ it "maintains the headers" do
67
+ assert_equal :headers, @headers
68
+ end
69
+
70
+ it "maintains the body" do
71
+ assert_equal :body, @body
72
+ end
73
+
74
+ end
75
+
76
+ describe "accumulating context" do
77
+
78
+ before do
79
+ subject.call(one: 'Testing')
80
+ end
81
+
82
+ it "logs accumulating context" do
83
+ assert_equal "Start", messages[0].message.to_s
84
+ assert_equal [1], messages[0].message.ndc.stack
85
+
86
+ assert_equal 'Testing', messages[1].message.to_s
87
+ assert_equal [1, :one], messages[1].message.ndc.stack
88
+
89
+ assert_equal 'Finish', messages[2].message.to_s
90
+ assert_equal [1, :one, :end], messages[2].message.ndc.stack
91
+ end
92
+
93
+ end
94
+
95
+ describe "clearing context between requests" do
96
+
97
+ before do
98
+ subject.call(one: 'Testing')
99
+ subject.call(one: 'TestingAgain')
100
+ end
101
+
102
+ it "clears context from previous requests" do
103
+ assert_equal "Start", messages[3].message.to_s
104
+ assert_equal [2], messages[3].message.ndc.stack
105
+
106
+ assert_equal 'TestingAgain', messages[4].message.to_s
107
+ assert_equal [2, :one], messages[4].message.ndc.stack
108
+
109
+ assert_equal 'Finish', messages[5].message.to_s
110
+ assert_equal [2, :one, :end], messages[5].message.ndc.stack
111
+ end
112
+
113
+ end
114
+
115
+ end
@@ -10,7 +10,7 @@ describe PlainFormatter do
10
10
  describe 'without an error' do
11
11
 
12
12
  before do
13
- @message = Message.new(' Hello, World ')
13
+ @message = Message.new(ndc: [], message: ' Hello, World ')
14
14
  end
15
15
 
16
16
  it 'outputs the message in the MESSAGE format' do
@@ -24,7 +24,7 @@ describe PlainFormatter do
24
24
 
25
25
  before do
26
26
  error = OpenStruct.new(message: 'Boom!', backtrace: ['foo.rb:1:a', 'foo.rb:20:b'])
27
- @message = Message.new(' Hello, World ', error)
27
+ @message = Message.new(ndc: [], message: ' Hello, World ', error: error)
28
28
  end
29
29
 
30
30
  describe 'with backtraces enabled' do
@@ -10,7 +10,7 @@ describe SimpleFormatter do
10
10
  describe 'without an error' do
11
11
 
12
12
  before do
13
- @message = Message.new(' Hello, World ')
13
+ @message = Message.new(ndc: [], message: ' Hello, World ')
14
14
  end
15
15
 
16
16
  it 'outputs the message in the LEVEL - CONTEXT - MESSAGE format' do
@@ -24,7 +24,7 @@ describe SimpleFormatter do
24
24
 
25
25
  before do
26
26
  error = OpenStruct.new(message: 'Boom!', backtrace: ['foo.rb:1:a', 'foo.rb:20:b'])
27
- @message = Message.new(' Hello, World ', error)
27
+ @message = Message.new(ndc: [], message: ' Hello, World ', error: error)
28
28
  end
29
29
 
30
30
  describe 'with backtraces enabled' do
@@ -57,7 +57,7 @@ describe SimpleFormatter do
57
57
 
58
58
  before do
59
59
  subject.thread_context = true
60
- @message = Message.new(' Hello, World ')
60
+ @message = Message.new(ndc: [], message: ' Hello, World ')
61
61
  end
62
62
 
63
63
  it 'outputs the message in the [THREAD] - LEVEL - CONTEXT - MESSAGE format' do
@@ -67,6 +67,19 @@ describe SimpleFormatter do
67
67
 
68
68
  end
69
69
 
70
+ describe 'with ndc' do
71
+
72
+ before do
73
+ @message = Message.new(ndc: [:foo, 123], message: ' Hello, World ')
74
+ end
75
+
76
+ it 'outputs the message in the [THREAD] - LEVEL - CONTEXT NDC - MESSAGE format' do
77
+ message = subject.format(:info, 'Custom::Context', @message)
78
+ assert "INFO - Custom::Context foo 123 - Hello, World" == message, "got #{message}"
79
+ end
80
+
81
+ end
82
+
70
83
  end
71
84
 
72
85
  end
@@ -10,7 +10,8 @@ describe StandardFormatter do
10
10
 
11
11
  describe 'when formatting a message' do
12
12
  before do
13
- @message = Message.new('Hello, World')
13
+ ndc = NestedDiagnosticContext::ContextStack.new([:foo, 12])
14
+ @message = Message.new(ndc: ndc, message: 'Hello, World')
14
15
  @context = 'Custom::Context'
15
16
  @level = :info
16
17
  @formatted_message = subject.format(@level, @context, @message)
@@ -37,7 +38,7 @@ describe StandardFormatter do
37
38
  end
38
39
 
39
40
  it 'formats the message after the time as expected' do
40
- expected = "[#{Process.pid}] #{@level.to_s.upcase.ljust 5} #{@context} - #{@message}"
41
+ expected = "[#{Process.pid}] #{@level.to_s.upcase.ljust 5} #{@context} foo 12 - #{@message}"
41
42
  actual_without_time = @formatted_message[24..-1]
42
43
 
43
44
  assert_equal expected, actual_without_time
@@ -58,7 +59,7 @@ describe StandardFormatter do
58
59
 
59
60
  before do
60
61
  error = OpenStruct.new(message: 'Boom!', backtrace: ['foo.rb:1:a', 'foo.rb:20:b'])
61
- @message = Message.new(' Hello, World ', error)
62
+ @message = Message.new(ndc: [], message: ' Hello, World ', error: error)
62
63
  end
63
64
 
64
65
  describe 'with backtraces enabled' do
@@ -98,7 +99,8 @@ describe StandardFormatter do
98
99
  end
99
100
 
100
101
  took = Time.now - start
101
- limit = 0.4
102
+ limit = 0.6
103
+ puts "\nMessages took #{took} to generate\n"
102
104
  assert took < limit, "Expected messages to take less than #{limit} but took #{took}"
103
105
  end
104
106
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hatchet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-29 00:00:00.000000000 Z
12
+ date: 2013-01-10 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Logging library that provides the ability to add class/module specific
15
15
  filters
@@ -26,6 +26,8 @@ files:
26
26
  - lib/hatchet/level_manager.rb
27
27
  - lib/hatchet/logger_appender.rb
28
28
  - lib/hatchet/message.rb
29
+ - lib/hatchet/middleware.rb
30
+ - lib/hatchet/nested_diagnostic_context.rb
29
31
  - lib/hatchet/plain_formatter.rb
30
32
  - lib/hatchet/railtie.rb
31
33
  - lib/hatchet/simple_formatter.rb
@@ -44,6 +46,7 @@ files:
44
46
  - spec/logger_appender_spec.rb
45
47
  - spec/logger_spec.rb
46
48
  - spec/message_spec.rb
49
+ - spec/middleware_spec.rb
47
50
  - spec/plain_formatter_spec.rb
48
51
  - spec/simple_formatter_spec.rb
49
52
  - spec/spec_helper.rb
@@ -87,6 +90,7 @@ test_files:
87
90
  - spec/logger_appender_spec.rb
88
91
  - spec/logger_spec.rb
89
92
  - spec/message_spec.rb
93
+ - spec/middleware_spec.rb
90
94
  - spec/plain_formatter_spec.rb
91
95
  - spec/simple_formatter_spec.rb
92
96
  - spec/spec_helper.rb