semantic_logger 0.2.0 → 0.3.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.
data/FUTURE.rb CHANGED
@@ -1,9 +1,4 @@
1
1
 
2
- # Return the logger for a specific class, supports class specific log levels
3
- # Clarity::Logger.logger(MyClass)
4
- # # OR
5
- # Clarity::Logger.logger('MyClass')
6
- #
7
2
  # # Switch to slf4j as the underlying implementation
8
3
  # Clarity::Logger.impl = slf4j
9
4
  #
@@ -14,13 +9,6 @@
14
9
  #
15
10
  #
16
11
  #
17
- # # Thread specific context information to be logged with every log entry
18
- # #
19
- # # Add metadata information within a block to all log calls on This Thread
20
- # logger.with_metadata(:tracking_number=>12345) do
21
- # # Any log entries within this block will have this metadata added to it
22
- # logger.debug('Hello World', :result => 'blah')
23
- # end
24
12
  #
25
13
  # # If a block cannot be used to set the scope of context
26
14
  # # Set global metadata for every log entry on this machine
@@ -41,6 +41,8 @@ module SemanticLogger
41
41
  def default_formatter
42
42
  Proc.new do |log|
43
43
  message = log.message.to_s
44
+ tags = log.tags.collect { |tag| "[#{tag}]" }.join(" ") + " " if log.tags && (log.tags.size > 0)
45
+
44
46
  if log.payload
45
47
  if log.payload.is_a?(Exception)
46
48
  exception = log.payload
@@ -50,8 +52,9 @@ module SemanticLogger
50
52
  end
51
53
  end
52
54
 
53
- str = "#{log.time.strftime("%Y-%m-%d %H:%M:%S")}.#{"%03d" % (log.time.usec/1000)} #{log.level.to_s[0..0].upcase} [#{$$}:#{log.thread_name}] #{log.name} -- #{message}\n"
55
+ str = "#{log.time.strftime("%Y-%m-%d %H:%M:%S")}.#{"%03d" % (log.time.usec/1000)} #{log.level.to_s[0..0].upcase} [#{$$}:#{log.thread_name}] #{tags}#{log.name} -- #{message}"
54
56
  str << " (#{'%.1f' % log.duration}ms)" if log.duration
57
+ str << "\n"
55
58
  str
56
59
  end
57
60
  end
@@ -12,8 +12,8 @@ module SemanticLogger
12
12
  # level : 'trace|debug|warn|info|error',
13
13
  # message : "blah blah",
14
14
  # duration : ms, # Set by Logger#benchmark
15
- # tracking_number : "Some tracking id"
16
- # metadata : {
15
+ # tags : "Some tracking id" | ["id1", "id2"]
16
+ # payload : {
17
17
  # Optional. Any user supplied data, including any thread specific context variables
18
18
  # values supplied on a per log entry will override any thread context values
19
19
  # }
@@ -53,7 +53,13 @@ module SemanticLogger
53
53
 
54
54
  @@default_level = :info
55
55
 
56
- # Create a Logger instance
56
+ # Returns a Logger instance
57
+ #
58
+ # Return the logger for a specific class, supports class specific log levels
59
+ # logger = SemanticLogger::Logger.new(self)
60
+ # OR
61
+ # logger = SemanticLogger::Logger.new('MyClass')
62
+ #
57
63
  # Parameters:
58
64
  # application: A class, module or a string with the application/class name
59
65
  # to be used in the logger
@@ -94,10 +100,14 @@ module SemanticLogger
94
100
  if result.is_a?(String)
95
101
  message = message.nil? ? result : "\#{message} -- \#{result.to_s}"
96
102
  else
97
- payload = payload.nil? ? sresult : payload.merge(result)
103
+ payload = payload.nil? ? result : payload.merge(result)
98
104
  end
99
105
  end
100
- self.class.queue << Log.new(:#{level}, self.class.thread_name, name, message, payload, Time.now)
106
+ # Add scoped payload
107
+ if self.payload
108
+ payload = payload.nil? ? self.payload : self.payload.merge(payload)
109
+ end
110
+ self.class.queue << Log.new(:#{level}, self.class.thread_name, name, message, payload, Time.now, nil, tags)
101
111
  true
102
112
  else
103
113
  false
@@ -117,10 +127,15 @@ module SemanticLogger
117
127
  start = Time.now
118
128
  begin
119
129
  result = yield
120
- self.class.queue << Log.new(:#{level}, self.class.thread_name, name, message, payload, start, Time.now - start)
130
+ # Add scoped payload
131
+ if self.payload
132
+ payload = payload.nil? ? self.payload : self.payload.merge(payload)
133
+ end
134
+ self.class.queue << Log.new(:#{level}, self.class.thread_name, name, message, payload, start, Time.now - start, tags)
121
135
  result
122
136
  rescue Exception => exc
123
- self.class.queue << Log.new(:#{level}, self.class.thread_name, name, message, exc, start, Time.now - start)
137
+ # TODO Need to be able to have both an exception and a Payload
138
+ self.class.queue << Log.new(:#{level}, self.class.thread_name, name, message, exc, start, Time.now - start, tags)
124
139
  raise exc
125
140
  end
126
141
  else
@@ -130,6 +145,55 @@ module SemanticLogger
130
145
  EOT
131
146
  end
132
147
 
148
+ # Add the supplied tags to the list of tags to log for this thread whilst
149
+ # the supplied block is active
150
+ # Returns nil if no tags are currently set
151
+ def with_tags(*tags)
152
+ current_tags = self.tags
153
+ # Check for nil tags
154
+ if tags
155
+ Thread.current[:semantic_logger_tags] = current_tags ? current_tags + tags : tags
156
+ end
157
+ yield
158
+ ensure
159
+ Thread.current[:semantic_logger_tags] = current_tags
160
+ end
161
+
162
+ # Returns [Array] of [String] tags currently active for this thread
163
+ # Returns nil if no tags are set
164
+ def tags
165
+ Thread.current[:semantic_logger_tags]
166
+ end
167
+
168
+ # Thread specific context information to be logged with every log entry
169
+ #
170
+ # Add a payload to all log calls on This Thread within the supplied block
171
+ #
172
+ # logger.with_payload(:tracking_number=>12345) do
173
+ # logger.debug('Hello World')
174
+ # end
175
+ #
176
+ # If a log call already includes a pyload, this payload will be merged with
177
+ # the supplied payload, with the supplied payload taking precedence
178
+ #
179
+ # logger.with_payload(:tracking_number=>12345) do
180
+ # logger.debug('Hello World', :result => 'blah')
181
+ # end
182
+ def with_payload(payload)
183
+ current_payload = self.payload
184
+ Thread.current[:semantic_logger_payload] = current_payload ? current_payload.merge(payload) : payload
185
+ yield
186
+ ensure
187
+ Thread.current[:semantic_logger_payload] = current_payload
188
+ end
189
+
190
+ # Returns [Hash] payload to be added to every log entry in the current scope
191
+ # on this thread.
192
+ # Returns nil if no payload is currently set
193
+ def payload
194
+ Thread.current[:semantic_logger_payload]
195
+ end
196
+
133
197
  # Semantic Logging does not support :unknown level since these
134
198
  # are not understood by the majority of the logging providers
135
199
  # Map it to :error
@@ -187,7 +251,7 @@ module SemanticLogger
187
251
  Queue.new
188
252
  end
189
253
 
190
- Log = Struct.new(:level, :thread_name, :name, :message, :payload, :time, :duration)
254
+ Log = Struct.new(:level, :thread_name, :name, :message, :payload, :time, :duration, :tags)
191
255
 
192
256
  # For JRuby include the Thread name rather than its id
193
257
  if defined? Java
@@ -23,15 +23,31 @@ module SemanticLogger #:nodoc:
23
23
  #
24
24
  # Loaded after Rails logging is initialized since SemanticLogger will continue
25
25
  # to forward logging to the Rails Logger
26
- initializer :initialize_semantic_logger, :after => :initialize_logger do
26
+ initializer :initialize_semantic_logger, :before => :initialize_logger do
27
27
  config = Rails.application.config
28
28
 
29
- # First set the internal logger to the one used by Rails in case something goes wrong
29
+ logger = Rails.logger || config.logger || begin
30
+ path = config.paths.log.to_a.first
31
+ logger = ActiveSupport::BufferedLogger.new(path)
32
+ logger.level = ActiveSupport::BufferedLogger.const_get(config.log_level.to_s.upcase)
33
+ logger.auto_flushing = false if Rails.env.production?
34
+ logger
35
+ rescue StandardError => e
36
+ logger = ActiveSupport::BufferedLogger.new(STDERR)
37
+ logger.level = ActiveSupport::BufferedLogger::WARN
38
+ logger.warn(
39
+ "Rails Error: Unable to access log file. Please ensure that #{path} exists and is chmod 0666. " +
40
+ "The log level has been raised to WARN and the output directed to STDERR until the problem is fixed."
41
+ )
42
+ logger
43
+ end
44
+
45
+ # First set the internal logger to the default file one used by Rails in case something goes wrong
30
46
  # with an appender
31
- SemanticLogger::Logger.logger = Rails.logger
47
+ SemanticLogger::Logger.logger = logger
32
48
 
33
49
  # Add the Rails Logger to the list of appenders
34
- SemanticLogger::Logger.appenders << SemanticLogger::Appender::Logger.new(Rails.logger)
50
+ SemanticLogger::Logger.appenders << SemanticLogger::Appender::Logger.new(logger)
35
51
 
36
52
  # Set the default log level based on the Rails config
37
53
  SemanticLogger::Logger.default_level = Rails.configuration.log_level
@@ -41,6 +57,10 @@ module SemanticLogger #:nodoc:
41
57
  if defined?(ActiveRecord)
42
58
  ActiveRecord::Base.logger = SemanticLogger::Logger.new(ActiveRecord)
43
59
  end
60
+ if defined?(ActionController)
61
+ ActionController::Base.logger = SemanticLogger::Logger.new(ActionController)
62
+ end
63
+ SemanticLogger::Logger.logger.info "SemanticLogger initialized"
44
64
  end
45
65
 
46
66
  end
@@ -1,3 +1,3 @@
1
1
  module SemanticLogger #:nodoc
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/test/logger_test.rb CHANGED
@@ -9,7 +9,6 @@ require 'semantic_logger'
9
9
  require 'test/mock_logger'
10
10
 
11
11
  # Unit Test for SemanticLogger::Logger
12
- #
13
12
  class LoggerTest < Test::Unit::TestCase
14
13
  context SemanticLogger::Logger do
15
14
 
@@ -39,6 +38,36 @@ class LoggerTest < Test::Unit::TestCase
39
38
  end
40
39
  end
41
40
 
41
+ context "with_tags logging" do
42
+ should "add tags to log entries" do
43
+ @logger.with_tags('12345', 'DJHSFK') do
44
+ @logger.info('Hello world')
45
+ @logger.flush
46
+ assert_match /\d+-\d+-\d+ \d+:\d+:\d+.\d+ \w \[\d+:.+\] \[12345\] \[DJHSFK\] LoggerTest -- Hello world\n/, @mock_logger.message
47
+ end
48
+ end
49
+
50
+ should "add embedded tags to log entries" do
51
+ @logger.with_tags('First Level', 'tags') do
52
+ @logger.with_tags('Second Level') do
53
+ @logger.info('Hello world')
54
+ @logger.flush
55
+ assert_match /\d+-\d+-\d+ \d+:\d+:\d+.\d+ \w \[\d+:.+\] \[First Level\] \[tags\] \[Second Level\] LoggerTest -- Hello world\n/, @mock_logger.message
56
+ end
57
+ end
58
+ end
59
+
60
+ should "add payload to log entries" do
61
+ @logger.with_payload(:tracking_number => '123456') do
62
+ @logger.with_payload(:more => 'data', :even => 2) do
63
+ @logger.info('Hello world')
64
+ @logger.flush
65
+ assert_match /\d+-\d+-\d+ \d+:\d+:\d+.\d+ \w \[\d+:.+\] LoggerTest -- Hello world -- \{:more=>\"data\", :even=>2, :tracking_number=>\"123456\"\}\n/, @mock_logger.message
66
+ end
67
+ end
68
+ end
69
+
70
+ end
42
71
  end
43
72
 
44
73
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 2
7
+ - 3
8
8
  - 0
9
- version: 0.2.0
9
+ version: 0.3.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Reid Morrison
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2012-08-20 00:00:00 -04:00
17
+ date: 2012-08-21 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency