semantic_logger 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,14 +1,141 @@
1
1
  semantic_logger
2
2
  ===============
3
3
 
4
- Ruby and Rails Logger enhanced with semantic capabilities, high performance, standardized
5
- logging with multiple appenders
4
+ Improved logging for Ruby
6
5
 
7
6
  * http://github.com/ClarityServices/semantic_logger
8
7
 
8
+ ### Overview
9
+
10
+ Semantic Logger takes logging in Ruby to a new level by adding several new
11
+ capabilities to the commonly used Logging API:
12
+
13
+ Dynamic
14
+
15
+ * Increase the log level at runtime for just one class
16
+ * For example enable debug level logging for a single class (logging instance)
17
+ while the program is running to get more detailed logging in production for just that class
18
+
19
+ Tagged Logging
20
+
21
+ * Supply custom data to be added to every log entry within a block of code,
22
+ including libraries and existing Gems
23
+
24
+ High Performance
25
+
26
+ * Logging is performed in a separate thread so as not to impact performance of
27
+ running code
28
+
29
+ Customizable
30
+
31
+ * Custom formatting by destination
32
+ * Easy to "roll your own" destination (Appender).
33
+ For example to log to Hadoop, Redis, etc..
34
+
35
+ Payload support
36
+
37
+ * Aside from the regular log message, a hash payload can also be supplied with
38
+ every log entry
39
+ * Very powerful when logging to NOSQL destinations that allow queries against
40
+ any data in the payload
41
+
42
+ Exceptions
43
+
44
+ * Directly log exceptions
45
+ * Semantic Logger standardizes the logging of exceptions with their backtraces
46
+ to text destinations and writes the exception elements as a hash to NOSQL
47
+ destinations
48
+
49
+ Drop-in Replacement
50
+
51
+ * Simple drop-in replacement for the Ruby, or the Rails loggers
52
+ * Supports current common logging interface
53
+ * No changes to existing to code to use new logger ( other than replacing the logger )
54
+
55
+ Rails 2 & 3 Support
56
+
57
+ * Just include the semantic_logger gem into Rails and it will immediately
58
+ replace the existing loggers to improve performance and information
59
+ in the log files
60
+
61
+ Thread Aware
62
+
63
+ * Includes the process and thread id information in every log entry
64
+
65
+ Trace Level
66
+
67
+ * :trace is a new level common in other languages and is commonly used for
68
+ logging trace level detail. It is intended for logging data at level below
69
+ :debug.
70
+ * :trace can be used for logging the actual data sent or received over the network
71
+ that is rarely needed but is critical when things are not working as expected.
72
+ * Since :trace can be enabled on a per class basis it can even be turned on
73
+ in production to resolve what was actually sent to an external vendor
74
+
75
+ Multiple Destinations
76
+
77
+ * Log to multiple destinations at the same time ( File and MongoDB, etc.. )
78
+ * Each destination can also have its own log level.
79
+ For example only write :info and above to MongoDB
80
+ Or have a second log file for :warn and above log entries
81
+
82
+ Benchmarking
83
+
84
+ * The performance of any block of code can be measured and logged at the same time
85
+ depending on the active log level
86
+
87
+ Semantic Capabilities
88
+
89
+ * With Semantic Logger it is simple to mix-in additional semantic information with
90
+ every log entry
91
+ * The application or class name is automatically included for every log entry under
92
+ a specific logging instance
93
+ * Includes the duration of blocks of code
94
+ * any Hash containing context specific information such as user_id or location information
95
+
96
+ Beyond Tagged Logging
97
+
98
+ * Supply entire hash of custom data to be added to the payload of every log entry
99
+ within a block of code, including libraries and existing Gems
100
+
101
+ NOSQL Destinations
102
+
103
+ * Every log entry is broken down into elements that NOSQL data stores can understand:
104
+
105
+ ```json
106
+ {
107
+ "_id" : ObjectId("5034fa48e3f3fea945e83ef2"),
108
+ "time" : ISODate("2012-08-22T15:27:04.409Z"),
109
+ "host_name" : "release",
110
+ "pid" : 16112,
111
+ "thread_name" : "main",
112
+ "name" : "UserLocator",
113
+ "level" : "debug",
114
+ "message" : "Fetch user information",
115
+ "duration" : 12,
116
+ "payload" : {
117
+ "user" : "Jack",
118
+ "zip_code" : 12345,
119
+ "location" : "US"
120
+ }
121
+ }
122
+ ```
123
+
124
+ Thread Safe
125
+
126
+ * Semantic Logger is completely thread safe and all methods can be called
127
+ concurrently from any thread
128
+ * Tagged logging keeps any tagging data on a per-thread basis to ensure that
129
+ tags from different threads are not inter-mingled
130
+
9
131
  ### Introduction
10
132
 
11
133
  SemanticLogger is a Logger that supports logging of meta-data, along with text messages
134
+ to multiple appenders
135
+
136
+ An appender is a Logging destination such as a File, MongoDB collection, etc..
137
+ Multiple Appenders can be active at the same time. All log entries are written
138
+ to each appender.
12
139
 
13
140
  Machines can understand the logged data without having to use
14
141
  complex Regular Expressions or other text parsing techniques
@@ -205,7 +332,7 @@ as debug calls only if the log level is set to trace
205
332
 
206
333
  When Semantic Logger is included on a Rails project it automatically replaces the
207
334
  loggers for Rails, ActiveRecord::Base, ActionController::Base, and ActiveResource::Base
208
- with wrappers that set their Class name. For example in railtie.rb:
335
+ with wrappers that set their Class name. For example in semantic_logger/railtie.rb:
209
336
 
210
337
  ```ruby
211
338
  ActiveRecord::Base.logger = SemanticLogger::Logger.new(ActiveRecord)
@@ -246,8 +373,37 @@ This will result in the log output identifying the log entry as from the Externa
246
373
  [SyncAttr](https://github.com/ClarityServices/sync_attr) is a gem that supports
247
374
  lazy loading and thread-safe initialization of class attributes
248
375
 
376
+ Extract from a Rails log file after adding the semantic_logger gem:
377
+
378
+ ```
379
+ 2012-10-19 12:05:46.736 I [35940:JRubyWorker-10] Rails --
380
+
381
+ Started GET "/" for 127.0.0.1 at 2012-10-19 12:05:46 +0000
382
+ 2012-10-19 12:05:47.318 I [35940:JRubyWorker-10] ActionController -- Processing by AdminController#index as HTML
383
+ 2012-10-19 12:05:47.633 D [35940:JRubyWorker-10] ActiveRecord -- User Load (2.0ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
384
+ 2012-10-19 12:05:49.833 D [35940:JRubyWorker-10] ActiveRecord -- Role Load (2.0ms) SELECT `roles`.* FROM `roles`
385
+ 2012-10-19 12:05:49.868 D [35940:JRubyWorker-10] ActiveRecord -- Role Load (1.0ms) SELECT * FROM `roles` INNER JOIN `roles_users` ON `roles`.id = `roles_users`.role_id WHERE (`roles_users`.user_id = 1 )
386
+ 2012-10-19 12:05:49.885 I [35940:JRubyWorker-10] ActionController -- Rendered menus/_control_system.html.erb (98.0ms)
387
+ 2012-10-19 12:05:51.014 I [35940:JRubyWorker-10] ActionController -- Rendered layouts/_top_bar.html.erb (386.0ms)
388
+ 2012-10-19 12:05:51.071 D [35940:JRubyWorker-10] ActiveRecord -- Announcement Load (20.0ms) SELECT `announcements`.* FROM `announcements` WHERE `announcements`.`active` = 1 ORDER BY created_at desc
389
+ 2012-10-19 12:05:51.072 I [35940:JRubyWorker-10] ActionController -- Rendered layouts/_announcement.html.erb (26.0ms)
390
+ 2012-10-19 12:05:51.083 I [35940:JRubyWorker-10] ActionController -- Rendered layouts/_flash.html.erb (4.0ms)
391
+ 2012-10-19 12:05:51.109 I [35940:JRubyWorker-10] ActionController -- Rendered layouts/_footer.html.erb (16.0ms)
392
+ 2012-10-19 12:05:51.109 I [35940:JRubyWorker-10] ActionController -- Rendered admin/index.html.erb within layouts/base (1329.0ms)
393
+ 2012-10-19 12:05:51.113 I [35940:JRubyWorker-10] ActionController -- Completed 200 OK in 3795ms (Views: 1349.0ms | ActiveRecord: 88.0ms | Mongo: 0.0ms)
394
+ ```
395
+
249
396
  #### Tagged Logging
250
397
 
398
+ Semantic Logger allows any Ruby or Rails program to also include tagged logging.
399
+
400
+ This means that any logging performed within a block, including any called
401
+ libraries or gems to include the specified tag with every log entry.
402
+
403
+ Using Tagged logging is critical in any highly concurrent environment so that
404
+ one can quickly find all related log entries across all levels of code, and even
405
+ across threads
406
+
251
407
  ```ruby
252
408
  logger.tagged(tracking_number) do
253
409
  logger.debug("Hello World")
@@ -255,10 +411,17 @@ logger.tagged(tracking_number) do
255
411
  end
256
412
  ```
257
413
 
258
- #### Payload injected logging
414
+ #### Beyond Tagged Logging
415
+
416
+ Blocks of code can be tagged with not only values, but can be tagged with
417
+ entire hashes of data. The additional hash of data will be merged into
418
+ the payload of every log entry
419
+
420
+ For example every corresponding log entry could include a hash containing
421
+ a user_id, name, region, zip_code, tracking_number, etc...
259
422
 
260
423
  ```ruby
261
- logger.with_payload(:user => 'Jack') do
424
+ logger.with_payload(:user => 'Jack', :zip_code => 12345) do
262
425
  logger.debug("Hello World")
263
426
  # ...
264
427
  end
@@ -441,6 +604,52 @@ For example to replace the MongoDB formatter, in the environment configuration f
441
604
  end
442
605
  ```
443
606
 
607
+ ### SysLog and other standard loggers
608
+
609
+ To write log entries to a Syslog logger or any other logger of your choice,
610
+ that conforms the standard Ruby Logger API, Semantic Logger has an Appender to
611
+ use that logger.
612
+
613
+ For example to configure rails to also log to the Syslogger gem:
614
+ ```ruby
615
+ config.after_initialize do
616
+ # Besides logging to the local file also log to Syslogger
617
+ config.semantic_logger.appenders << SemanticLogger::Appender::Wrapper.new(Syslogger.new("yourappname"))
618
+ end
619
+ ```
620
+
621
+ ### Performance
622
+
623
+ The traditional logging implementations write their log information to file in the
624
+ same thread of execution as the program itself. This means that for every log entry
625
+ the program has to wait for the data to be written.
626
+
627
+ With Semantic Logger it uses a dedicated thread for logging so that writing to
628
+ the log file or other appenders does not hold up program execution.
629
+
630
+ Also, since the logging is in this separate thread there is no impact to program
631
+ execution if we decided to add another appender.
632
+ For example, log to both a file and a MongoDB collection.
633
+
634
+ ### Log Rotation
635
+
636
+ Since the log file is not re-opened with every call, when the log file needs
637
+ to be rotated, use a copy-truncate operation over deleting the file.
638
+
639
+ ### Why Semantic logging?
640
+
641
+ Just as there is the initiative to add Semantic information to data on the web
642
+ so that computers can directly understand the content without having to resort
643
+ to complex regular expressions or machine learning techniques, it is important
644
+ to be able to do the same with log files or data.
645
+
646
+ Semantic Logger allows every log entry to have not only a message, but a payload
647
+ that can be written to a file or a NOSQL destination.
648
+
649
+ Once the logging data is in the NOSQL data store it can be queried quickly and
650
+ efficiently. Some SQL data stores also allow complex data types that could be used
651
+ for storing and querying the logging data
652
+
444
653
  ### Architecture & Performance
445
654
 
446
655
  In order to ensure that logging does not hinder the performance of the application
@@ -449,7 +658,7 @@ for writing the log entries to each of the appenders.
449
658
 
450
659
  In this way formatting and disk or network write delays will not affect the
451
660
  performance of the application. Also adding more than one appender does not affect
452
- the runtime performance of the application
661
+ the runtime performance of the application.
453
662
 
454
663
  The additional thread is automatically started on initialization. When the program
455
664
  terminates it will complete writing out all log data and flush the appenders before
@@ -460,9 +669,102 @@ have been written and flushed to their respective appenders before returning.
460
669
  Since all logging is now from this thread calling flush is no longer thread
461
670
  specific.
462
671
 
672
+ ### Write your own Appender
673
+
674
+ To write your own appender it should meet the following requirements:
675
+
676
+ * Inherit from SemanticLogger::Base
677
+ * In the initializer connect to the resource being logged to
678
+ * Implement #log(log) which needs to write to the relevant resource
679
+ * Implement #flush if the resource can be flushed
680
+ * Write a test for the new appender
681
+
682
+ The #log method takes the log struct as a parameter which is defined as follows:
683
+ ```ruby
684
+ Log = Struct.new(:level, :thread_name, :name, :message, :payload, :time, :duration, :tags, :level_index)
685
+ ```
686
+ level
687
+
688
+ * Log level of the supplied log call
689
+ * :trace, :debug, :info, :warn, :error, :fatal
690
+
691
+ thread_name
692
+
693
+ * Name or id of the thread in which the logging call was called
694
+
695
+ name
696
+
697
+ * Class name supplied to the logging instance
698
+
699
+ message
700
+
701
+ * Text message to be logged
702
+
703
+ payload [Hash|Exception]
704
+
705
+ * Optional Hash or Ruby Exception object to be logged
706
+
707
+ time [Time]
708
+
709
+ * The time at which the log entry was created
710
+
711
+ duration [Float]
712
+
713
+ * The time taken in milli-seconds to complete a benchmark call
714
+
715
+ tags [Array<String>]
716
+
717
+ * Any tags active on the thread when the log call was made
718
+
719
+ level_index
720
+
721
+ * Internal use only. Index of the log level
722
+
723
+ Basic outline for an Appender:
724
+
725
+ ```ruby
726
+ require 'semantic_logger'
727
+
728
+ class SimpleAppender < SemanticLogger::Base
729
+ def initialize(level=nil, &block)
730
+ # Set the log level and formatter if supplied
731
+ super(level, &block)
732
+ end
733
+
734
+ # Just display the log struct
735
+ def log(log)
736
+ p log
737
+ end
738
+
739
+ # Optional
740
+ def flush
741
+ puts "Flush :)"
742
+ end
743
+ end
744
+ ```
745
+
746
+ Sample program calling the above appender:
747
+ ```ruby
748
+ SemanticLogger::Logger.default_level = :trace
749
+ # Log to file dev.log
750
+ SemanticLogger::Logger.appenders << SemanticLogger::Appender::File.new('dev.log')
751
+ # Also log the above sample appender
752
+ SemanticLogger::Logger.appenders << SimpleAppender.new
753
+
754
+ logger = SemanticLogger::Logger.new('Hello')
755
+ logger.info "Hello World"
756
+ ```
757
+
758
+ Look at the [existing appenders](https://github.com/ClarityServices/semantic_logger/tree/master/lib/semantic_logger/appender) for good examples
759
+
760
+ To have your appender included in the standard list of appenders follow the fork
761
+ instructions below.
762
+ Very Important: New appenders will not be accepted without complete working tests.
763
+ See the [MongoDB Appender Test](https://github.com/ClarityServices/semantic_logger/blob/master/test/appender_mongodb_test.rb) for an example.
764
+
463
765
  ### Dependencies
464
766
 
465
- - Ruby MRI 1.8.7 (or above) Or, JRuby 1.6.3 (or above)
767
+ - Ruby MRI 1.8.7, 1.9.3 (or above) Or, JRuby 1.6.3 (or above)
466
768
  - Optional: Rails 3.0.10 (or above)
467
769
  - Optional: To log to MongoDB, Mongo Ruby Driver 1.5.2 or above
468
770
 
@@ -476,7 +778,9 @@ To log to MongoDB
476
778
 
477
779
  ### Future
478
780
 
479
- - Web Interface to view and search log information stored in MongoDB
781
+ - Configuration file to support setting the log level for a specific class
782
+ - Configuration file to support adding appenders
783
+ - Based on demand add direct appenders for: Syslog, hadoop, redis
480
784
 
481
785
  Development
482
786
  -----------
@@ -487,7 +791,7 @@ First clone the repo and run the tests:
487
791
 
488
792
  git clone git://github.com/ClarityServices/semantic_logger.git
489
793
  cd semantic_logger
490
- ruby -S rake test
794
+ rake test
491
795
 
492
796
  Feel free to ping the mailing list with any issues and we'll try to resolve it.
493
797
 
@@ -135,7 +135,7 @@ module SemanticLogger
135
135
  end
136
136
 
137
137
  # Flush all pending logs to disk.
138
- # Waits for all sent documents to be writted to disk
138
+ # Waits for all sent documents to be written to disk
139
139
  def flush
140
140
  db.get_last_error
141
141
  end
@@ -49,6 +49,7 @@ module SemanticLogger
49
49
 
50
50
  # Initial default Level for all new instances of SemanticLogger::Logger
51
51
  @@default_level = :info
52
+ @@appender_thread = nil
52
53
 
53
54
  # Allow for setting the global default log level
54
55
  # This change only applies to _new_ loggers, existing logger levels
@@ -99,7 +100,7 @@ module SemanticLogger
99
100
  # Flush all queued log entries disk, database, etc.
100
101
  # All queued log messages are written and then each appender is flushed in turn
101
102
  def self.flush
102
- return false unless started?
103
+ return false unless started? && @@appender_thread && @@appender_thread.alive?
103
104
 
104
105
  reply_queue = Queue.new
105
106
  queue << { :command => :flush, :reply_queue => reply_queue }
@@ -172,7 +173,7 @@ module SemanticLogger
172
173
  #
173
174
  # Should any appender fail to log or flush, the exception is logged and
174
175
  # other appenders will still be called
175
- Thread.new do
176
+ @@appender_thread = Thread.new do
176
177
  logger.debug "SemanticLogger::Logger Appender thread started"
177
178
  begin
178
179
  count = 0
@@ -1,3 +1,3 @@
1
1
  module SemanticLogger #:nodoc
2
- VERSION = "0.8.0"
2
+ VERSION = "0.8.1"
3
3
  end
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: semantic_logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.1
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-10-18 00:00:00.000000000 Z
12
+ date: 2012-10-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sync_attr
@@ -111,7 +111,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
111
111
  version: '0'
112
112
  segments:
113
113
  - 0
114
- hash: 3275873948644639479
114
+ hash: -3615546680742578594
115
115
  required_rubygems_version: !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements: