semantic_logger 2.12.0 → 2.13.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1a76d0de5e08c9768042187ab19b2546d5c91b3a
4
- data.tar.gz: b04d51de5d531ec57ce382e77ddfd21bd69a420a
3
+ metadata.gz: 0e66e26770a5132bf299fe3b539af221ca75b0ae
4
+ data.tar.gz: 3f116e726cb8a76dda143f0b960cc9cc879be953
5
5
  SHA512:
6
- metadata.gz: 7fc60fcfef8e8c255720de4a4972ae2f0b919dd022eccc68afef004ad1f3fd0870f6c4adc54d190d0ff109a6671be910dbfafdf63f9ade57e9c8caedc66bead1
7
- data.tar.gz: 2c73e2cf3ac75e19097a3acb6b0437df745c4d60e7c8c3a5a02ef846a9b1ba1b16e37b49e07bbde4851c4ba77e63c1d22e027bf65ea3882150c1608f98db0f93
6
+ metadata.gz: 04f53db9e8ed15857bc9d0c2ce127ff1b0cc343fff8c5f43ca7bf0b7759e0ca69dd3415c3688fd807922f85e4d838bad3ecf1de499ee8dcd44c656bd9015c494
7
+ data.tar.gz: 9654f21ce94245806887850ec16ce506698262c6e70c31fc237ec090f054a76c23db743caca0927161e03ea528b5448a070d2fabe257e956ad45d164d6181cc6
data/lib/LogGC.java ADDED
@@ -0,0 +1,26 @@
1
+ //get all the info and pretty print it
2
+ duration =
3
+ //System.out.println("GcInfo CompositeType: " + info.getGcInfo().getCompositeType());
4
+ //System.out.println("GcInfo MemoryUsageAfterGc: " + info.getGcInfo().getMemoryUsageAfterGc());
5
+ //System.out.println("GcInfo MemoryUsageBeforeGc: " + info.getGcInfo().getMemoryUsageBeforeGc());
6
+
7
+ //Get the information about each memory space, and pretty print it
8
+ Map<String, MemoryUsage> membefore = info.getGcInfo().getMemoryUsageBeforeGc();
9
+ Map<String, MemoryUsage> mem = info.getGcInfo().getMemoryUsageAfterGc();
10
+ for (Entry<String, MemoryUsage> entry : mem.entrySet()) {
11
+ String name = entry.getKey();
12
+ MemoryUsage memdetail = entry.getValue();
13
+ long memInit = memdetail.getInit();
14
+ long memCommitted = memdetail.getCommitted();
15
+ long memMax = memdetail.getMax();
16
+ long memUsed = memdetail.getUsed();
17
+ MemoryUsage before = membefore.get(name);
18
+ long beforepercent = ((before.getUsed() * 1000L) / before.getCommitted());
19
+ long percent = ((memUsed * 1000L) / before.getCommitted()); //>100% when it gets expanded
20
+
21
+ System.out.print(name + (memCommitted == memMax ? "(fully expanded)" : "(still expandable)") + "used: " + (beforepercent / 10) + "." + (beforepercent % 10) + "%->" + (percent / 10) + "." + (percent % 10) + "%(" + ((memUsed / 1048576) + 1) + "MB) / ");
22
+ }
23
+ System.out.println();
24
+ totalGcDuration += info.getGcInfo().getDuration();
25
+ long percent = totalGcDuration * 1000L / info.getGcInfo().getEndTime();
26
+ System.out.println("GC cumulated overhead " + (percent / 10) + "." + (percent % 10) + "%");
data/lib/LogGC_1.java ADDED
@@ -0,0 +1,68 @@
1
+ //
2
+ // http://docs.oracle.com/javase/7/docs/jre/api/management/extension/com/sun/management/GarbageCollectionNotificationInfo.html
3
+ public class LogGC {
4
+
5
+ public static void installGCMonitoring() {
6
+ //get all the GarbageCollectorMXBeans - there's one for each heap generation
7
+ //so probably two - the old generation and young generation
8
+ List<GarbageCollectorMXBean> gcbeans = java.lang.management.ManagementFactory.getGarbageCollectorMXBeans();
9
+ //Install a notifcation handler for each bean
10
+ for (GarbageCollectorMXBean gcbean : gcbeans) {
11
+ System.out.println(gcbean);
12
+ NotificationEmitter emitter = (NotificationEmitter) gcbean;
13
+ //use an anonymously generated listener for this example
14
+ // - proper code should really use a named class
15
+ NotificationListener listener = new NotificationListener() {
16
+ //keep a count of the total time spent in GCs
17
+ long totalGcDuration = 0;
18
+
19
+ //implement the notifier callback handler
20
+ @Override
21
+ public void handleNotification(Notification notification, Object handback) {
22
+ //we only handle GARBAGE_COLLECTION_NOTIFICATION notifications here
23
+ if (notification.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) {
24
+ //get the information associated with this notification
25
+ GarbageCollectionNotificationInfo info = GarbageCollectionNotificationInfo.from((CompositeData) notification.getUserData());
26
+ //get all the info and pretty print it
27
+ long duration = info.getGcInfo().getDuration();
28
+ String gctype = info.getGcAction();
29
+ if ("end of minor GC".equals(gctype)) {
30
+ gctype = "Young Gen GC";
31
+ } else if ("end of major GC".equals(gctype)) {
32
+ gctype = "Old Gen GC";
33
+ }
34
+ System.out.println();
35
+ System.out.println(gctype + ": - " + info.getGcInfo().getId() + " " + info.getGcName() + " (from " + info.getGcCause() + ") " + duration + " microseconds; start-end times " + info.getGcInfo().getStartTime() + "-" + info.getGcInfo().getEndTime());
36
+ //System.out.println("GcInfo CompositeType: " + info.getGcInfo().getCompositeType());
37
+ //System.out.println("GcInfo MemoryUsageAfterGc: " + info.getGcInfo().getMemoryUsageAfterGc());
38
+ //System.out.println("GcInfo MemoryUsageBeforeGc: " + info.getGcInfo().getMemoryUsageBeforeGc());
39
+
40
+ //Get the information about each memory space, and pretty print it
41
+ Map<String, MemoryUsage> membefore = info.getGcInfo().getMemoryUsageBeforeGc();
42
+ Map<String, MemoryUsage> mem = info.getGcInfo().getMemoryUsageAfterGc();
43
+ for (Entry<String, MemoryUsage> entry : mem.entrySet()) {
44
+ String name = entry.getKey();
45
+ MemoryUsage memdetail = entry.getValue();
46
+ long memInit = memdetail.getInit();
47
+ long memCommitted = memdetail.getCommitted();
48
+ long memMax = memdetail.getMax();
49
+ long memUsed = memdetail.getUsed();
50
+ MemoryUsage before = membefore.get(name);
51
+ long beforepercent = ((before.getUsed() * 1000L) / before.getCommitted());
52
+ long percent = ((memUsed * 1000L) / before.getCommitted()); //>100% when it gets expanded
53
+
54
+ System.out.print(name + (memCommitted == memMax ? "(fully expanded)" : "(still expandable)") + "used: " + (beforepercent / 10) + "." + (beforepercent % 10) + "%->" + (percent / 10) + "." + (percent % 10) + "%(" + ((memUsed / 1048576) + 1) + "MB) / ");
55
+ }
56
+ System.out.println();
57
+ totalGcDuration += info.getGcInfo().getDuration();
58
+ long percent = totalGcDuration * 1000L / info.getGcInfo().getEndTime();
59
+ System.out.println("GC cumulated overhead " + (percent / 10) + "." + (percent % 10) + "%");
60
+ }
61
+ }
62
+ };
63
+
64
+ //Add the listener
65
+ emitter.addNotificationListener(listener, null, null);
66
+ }
67
+ }
68
+ }
@@ -17,6 +17,12 @@ module SemanticLogger
17
17
  autoload :NewRelic, 'semantic_logger/appender/new_relic'
18
18
  autoload :Splunk, 'semantic_logger/appender/splunk'
19
19
  end
20
+
21
+ if defined?(JRuby)
22
+ module JRuby
23
+ autoload :GarbageCollectionLogger, 'semantic_logger/jruby/garbage_collection_logger'
24
+ end
25
+ end
20
26
  end
21
27
 
22
28
  # Flush all appenders at exit, waiting for outstanding messages on the queue
@@ -181,6 +181,50 @@ module SemanticLogger
181
181
  alias :unknown :error
182
182
  alias :unknown? :error?
183
183
 
184
+ # Silence noisy log levels by changing the default_level within the block
185
+ #
186
+ # This setting is thread-safe and only applies to the current thread
187
+ #
188
+ # Any threads spawned within the block will not be affected by this setting
189
+ #
190
+ # #silence can be used to both raise and lower the log level within
191
+ # the supplied block.
192
+ #
193
+ # Example:
194
+ #
195
+ # # Perform trace level logging within the block when the default is higher
196
+ # SemanticLogger.default_level = :info
197
+ #
198
+ # logger.debug 'this will _not_ be logged'
199
+ #
200
+ # logger.silence(:trace) do
201
+ # logger.debug "this will be logged"
202
+ # end
203
+ #
204
+ # Parameters
205
+ # new_level
206
+ # The new log level to apply within the block
207
+ # Default: :error
208
+ #
209
+ # Example:
210
+ # # Silence all logging below :error level
211
+ # logger.silence do
212
+ # logger.info "this will _not_ be logged"
213
+ # logger.warn "this neither"
214
+ # logger.error "but errors will be logged"
215
+ # end
216
+ #
217
+ # Note:
218
+ # #silence does not affect any loggers which have had their log level set
219
+ # explicitly. I.e. That do not rely on the global default level
220
+ def silence(new_level = :error)
221
+ current_index = Thread.current[:semantic_logger_silence]
222
+ Thread.current[:semantic_logger_silence] = SemanticLogger.level_to_index(new_level)
223
+ yield
224
+ ensure
225
+ Thread.current[:semantic_logger_silence] = current_index
226
+ end
227
+
184
228
  # DEPRECATED See SemanticLogger.default_level=
185
229
  def self.default_level=(level)
186
230
  warn "[DEPRECATION] `SemanticLogger::Logger.default_level=` is deprecated. Please use `SemanticLogger.default_level=` instead."
@@ -312,9 +356,17 @@ module SemanticLogger
312
356
  def benchmark_internal(level, index, message, params, &block)
313
357
  start = Time.now
314
358
  begin
315
- rc = block.call(params) if block
316
- exception = params[:exception]
317
- rc
359
+ if block
360
+ result = if silence_level = params[:silence]
361
+ # In case someone accidentally sets `silence: true` instead of `silence: :error`
362
+ silence_level = :error if silence_level == true
363
+ silence(silence_level) { block.call(params) }
364
+ else
365
+ block.call(params)
366
+ end
367
+ exception = params[:exception]
368
+ result
369
+ end
318
370
  rescue Exception => exc
319
371
  exception = exc
320
372
  ensure
@@ -0,0 +1,27 @@
1
+ module SemanticLogger
2
+ module JRuby
3
+ class GarbageCollectionLogger
4
+ include Java::JavaxManagement::NotificationListener
5
+
6
+ # Only log the garbage collection if the number of microseconds exceeds
7
+ # this value
8
+ def initialize(min_microseconds = 10000)
9
+ @min_microseconds = min_microseconds
10
+ end
11
+
12
+ # Must leave the method name as-is so that it can be found by Java
13
+ def handleNotification(notification, _)
14
+ # Only care about GARBAGE_COLLECTION_NOTIFICATION notifications
15
+ return unless notification.get_type == Java::ComSunManagement::GarbageCollectionNotificationInfo::GARBAGE_COLLECTION_NOTIFICATION
16
+
17
+ info = Java::ComSunManagement::GarbageCollectionNotificationInfo.from(notification.user_data)
18
+ gc_info = info.gc_info
19
+ duration = gc_info.duration
20
+ if duration >= @min_microseconds
21
+ SemanticLogger['GarbageCollector'].benchmark_warn "Garbage Collection completed: #{info.gc_name} ##{gc_info.id}", duration: duration.to_f / 1000
22
+ end
23
+ end
24
+ end
25
+
26
+ end
27
+ end
@@ -152,23 +152,65 @@ module SemanticLogger
152
152
  SemanticLogger::Logger.on_metric(&block)
153
153
  end
154
154
 
155
- # Add a signal handler so that the log level can be changed externally
156
- # without restarting the process
155
+ # Add signal handlers for Semantic Logger
157
156
  #
158
- # When the signal is raised on this process, the global default log level
159
- # rotates through the following log levels in the following order, starting
160
- # from the current global default level:
161
- # :warn, :info, :debug, :trace
157
+ # Two signal handlers will be registered by default:
162
158
  #
163
- # If the current level is :trace it wraps around back to :warn
164
- def self.add_signal_handler(signal='USR2')
165
- Signal.trap(signal) do
159
+ # 1. Changing the log_level:
160
+ #
161
+ # The log level can be changed without restarting the process by sending the
162
+ # log_level_signal, which by default is 'USR2'
163
+ #
164
+ # When the log_level_signal is raised on this process, the global default log level
165
+ # rotates through the following log levels in the following order, starting
166
+ # from the current global default level:
167
+ # :warn, :info, :debug, :trace
168
+ #
169
+ # If the current level is :trace it wraps around back to :warn
170
+ #
171
+ # 2. Logging a Ruby thread dump
172
+ #
173
+ # When the signal is raised on this process, Semantic Logger will write the list
174
+ # of threads to the log file, along with their back-traces when available
175
+ #
176
+ # For JRuby users this thread dump differs form the standard QUIT triggered
177
+ # Java thread dump which includes system threads and Java stack traces.
178
+ #
179
+ # It is recommended to name any threads you create in the application, by
180
+ # calling the following from within the thread itself:
181
+ # Thread.current.name = 'My Worker'
182
+ #
183
+ # Also adds JRuby Garbage collection logging so that any garbage collections
184
+ # that exceed the time threshold will be logged. Default: 10 ms
185
+ # Currently only supported when running JRuby
186
+ #
187
+ # Note:
188
+ # To only register one of the signal handlers, set the other to nil
189
+ # Set gc_log_microseconds to nil to not enable JRuby Garbage collections
190
+ def self.add_signal_handler(log_level_signal='USR2', thread_dump_signal='TTIN', gc_log_microseconds=10000)
191
+ Signal.trap(log_level_signal) do
166
192
  index = (default_level == :trace) ? LEVELS.find_index(:error) : LEVELS.find_index(default_level)
167
193
  new_level = LEVELS[index-1]
168
194
  self['SemanticLogger'].warn "Changed global default log level to #{new_level.inspect}"
169
195
  self.default_level = new_level
196
+ end if log_level_signal
197
+
198
+ Signal.trap(thread_dump_signal) do
199
+ logger = SemanticLogger['Ruby Thread Dump']
200
+ Thread.list.each do |thread|
201
+ backtrace = thread.backtrace ? thread.backtrace.join("\n") : ''
202
+ logger.warn "#{thread.name}\n#{backtrace}"
203
+ end
204
+ end if thread_dump_signal
205
+
206
+ if gc_log_microseconds && defined?(JRuby)
207
+ listener = SemanticLogger::JRuby::GarbageCollectionLogger.new(gc_log_microseconds)
208
+ Java::JavaLangManagement::ManagementFactory.getGarbageCollectorMXBeans.each do |gcbean|
209
+ gcbean.add_notification_listener(listener, nil, nil)
210
+ end
170
211
  end
171
- signal
212
+
213
+ true
172
214
  end
173
215
 
174
216
  ############################################################################
@@ -180,7 +222,7 @@ module SemanticLogger
180
222
  private
181
223
 
182
224
  def self.default_level_index
183
- @@default_level_index
225
+ Thread.current[:semantic_logger_silence] || @@default_level_index
184
226
  end
185
227
 
186
228
  # Returns the symbolic level for the supplied level index
@@ -1,3 +1,3 @@
1
1
  module SemanticLogger #:nodoc
2
- VERSION = "2.12.0"
2
+ VERSION = "2.13.0"
3
3
  end
data/test/logger_test.rb CHANGED
@@ -216,6 +216,29 @@ class LoggerTest < Minitest::Test
216
216
  SemanticLogger.flush
217
217
  assert_match /\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:.+\] \(\d+\.\dms\) LoggerTest -- hello world -- #{@hash_str}/, @mock_logger.message
218
218
  end
219
+
220
+ should 'not log at a level below the silence level' do
221
+ SemanticLogger.default_level = :info
222
+ @logger.benchmark_info('hello world', silence: :error) do
223
+ @logger.warn "don't log me"
224
+ end
225
+ SemanticLogger.flush
226
+ assert_match /\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:.+\] \(\d+\.\dms\) LoggerTest -- hello world/, @mock_logger.message
227
+ end
228
+
229
+ should 'log at a silence level below the default level' do
230
+ SemanticLogger.default_level = :info
231
+ first_message = nil
232
+ @logger.benchmark_info('hello world', silence: :trace) do
233
+ @logger.debug('hello world', @hash) { "Calculations" }
234
+ SemanticLogger.flush
235
+ first_message = @mock_logger.message
236
+ end
237
+ assert_match /\d+-\d+-\d+ \d+:\d+:\d+.\d+ D \[\d+:.+\] LoggerTest -- hello world -- Calculations -- #{@hash_str}/, first_message
238
+ SemanticLogger.flush
239
+ # Only the last log message is kept in mock logger
240
+ assert_match /\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:.+\] \(\d+\.\dms\) LoggerTest -- hello world/, @mock_logger.message
241
+ end
219
242
  end
220
243
 
221
244
  context '.default_level' do
@@ -224,6 +247,7 @@ class LoggerTest < Minitest::Test
224
247
  end
225
248
 
226
249
  should 'not log at a level below the global default' do
250
+ assert_equal :debug, SemanticLogger.default_level
227
251
  assert_equal :debug, @logger.level
228
252
  @logger.trace('hello world', @hash) { "Calculations" }
229
253
  SemanticLogger.flush
@@ -231,6 +255,7 @@ class LoggerTest < Minitest::Test
231
255
  end
232
256
 
233
257
  should 'log at the instance level' do
258
+ assert_equal :debug, SemanticLogger.default_level
234
259
  @logger.level = :trace
235
260
  assert_equal :trace, @logger.level
236
261
  @logger.trace('hello world', @hash) { "Calculations" }
@@ -239,6 +264,7 @@ class LoggerTest < Minitest::Test
239
264
  end
240
265
 
241
266
  should 'not log at a level below the instance level' do
267
+ assert_equal :debug, SemanticLogger.default_level
242
268
  @logger.level = :warn
243
269
  assert_equal :warn, @logger.level
244
270
  @logger.debug('hello world', @hash) { "Calculations" }
@@ -247,6 +273,45 @@ class LoggerTest < Minitest::Test
247
273
  end
248
274
  end
249
275
 
276
+ context '.silence' do
277
+ setup do
278
+ SemanticLogger.default_level = :info
279
+ end
280
+
281
+ should 'not log at a level below the silence level' do
282
+ assert_equal :info, SemanticLogger.default_level
283
+ assert_equal :info, @logger.level
284
+ @logger.silence do
285
+ @logger.warn('hello world', @hash) { "Calculations" }
286
+ @logger.info('hello world', @hash) { "Calculations" }
287
+ @logger.debug('hello world', @hash) { "Calculations" }
288
+ @logger.trace('hello world', @hash) { "Calculations" }
289
+ end
290
+ SemanticLogger.flush
291
+ assert_nil @mock_logger.message
292
+ end
293
+
294
+ should 'log at the instance level even with the silencer at a higher level' do
295
+ @logger.level = :trace
296
+ assert_equal :trace, @logger.level
297
+ @logger.silence do
298
+ @logger.trace('hello world', @hash) { "Calculations" }
299
+ end
300
+ SemanticLogger.flush
301
+ assert_match /\d+-\d+-\d+ \d+:\d+:\d+.\d+ T \[\d+:.+\] LoggerTest -- hello world -- Calculations -- #{@hash_str}/, @mock_logger.message
302
+ end
303
+
304
+ should 'log at a silence level below the default level' do
305
+ assert_equal :info, SemanticLogger.default_level
306
+ assert_equal :info, @logger.level
307
+ @logger.silence(:debug) do
308
+ @logger.debug('hello world', @hash) { "Calculations" }
309
+ end
310
+ SemanticLogger.flush
311
+ assert_match /\d+-\d+-\d+ \d+:\d+:\d+.\d+ D \[\d+:.+\] LoggerTest -- hello world -- Calculations -- #{@hash_str}/, @mock_logger.message
312
+ end
313
+ end
314
+
250
315
  context '.level?' do
251
316
  should 'return true for debug? with :trace level' do
252
317
  SemanticLogger.default_level = :trace
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: semantic_logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.12.0
4
+ version: 2.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-22 00:00:00.000000000 Z
11
+ date: 2015-02-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sync_attr
@@ -49,6 +49,8 @@ files:
49
49
  - LICENSE.txt
50
50
  - README.md
51
51
  - Rakefile
52
+ - lib/LogGC.java
53
+ - lib/LogGC_1.java
52
54
  - lib/semantic_logger.rb
53
55
  - lib/semantic_logger/appender/base.rb
54
56
  - lib/semantic_logger/appender/file.rb
@@ -60,6 +62,7 @@ files:
60
62
  - lib/semantic_logger/base.rb
61
63
  - lib/semantic_logger/core_ext/thread.rb
62
64
  - lib/semantic_logger/debug_as_trace_logger.rb
65
+ - lib/semantic_logger/jruby/garbage_collection_logger.rb
63
66
  - lib/semantic_logger/loggable.rb
64
67
  - lib/semantic_logger/logger.rb
65
68
  - lib/semantic_logger/semantic_logger.rb