semantic_logger 2.12.0 → 2.13.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.
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