logging 0.9.8 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/History.txt +13 -0
  2. data/README.rdoc +51 -39
  3. data/Rakefile +1 -0
  4. data/examples/appenders.rb +44 -0
  5. data/examples/classes.rb +39 -0
  6. data/examples/formatting.rb +49 -0
  7. data/examples/hierarchies.rb +71 -0
  8. data/examples/layouts.rb +45 -0
  9. data/examples/loggers.rb +26 -0
  10. data/examples/names.rb +40 -0
  11. data/examples/simple.rb +14 -0
  12. data/lib/logging.rb +50 -21
  13. data/lib/logging/appender.rb +4 -56
  14. data/lib/logging/appenders.rb +120 -0
  15. data/lib/logging/appenders/buffering.rb +2 -1
  16. data/lib/logging/appenders/console.rb +0 -2
  17. data/lib/logging/appenders/rolling_file.rb +0 -2
  18. data/lib/logging/appenders/string_io.rb +1 -3
  19. data/lib/logging/appenders/syslog.rb +0 -7
  20. data/lib/logging/config/configurator.rb +1 -1
  21. data/lib/logging/config/yaml_configurator.rb +3 -7
  22. data/lib/logging/layout.rb +2 -4
  23. data/lib/logging/layouts.rb +47 -0
  24. data/lib/logging/layouts/basic.rb +2 -4
  25. data/lib/logging/layouts/parseable.rb +211 -0
  26. data/lib/logging/layouts/pattern.rb +6 -8
  27. data/lib/logging/log_event.rb +1 -1
  28. data/lib/logging/logger.rb +4 -4
  29. data/lib/spec/logging_helper.rb +2 -2
  30. data/test/appenders/test_buffered_io.rb +26 -18
  31. data/test/appenders/test_console.rb +10 -10
  32. data/test/appenders/test_email.rb +18 -19
  33. data/test/appenders/test_file.rb +12 -12
  34. data/test/appenders/test_growl.rb +11 -12
  35. data/test/appenders/test_io.rb +14 -15
  36. data/test/appenders/test_rolling_file.rb +15 -24
  37. data/test/appenders/test_syslog.rb +10 -10
  38. data/test/layouts/test_basic.rb +4 -5
  39. data/test/layouts/test_json.rb +112 -0
  40. data/test/layouts/test_pattern.rb +9 -9
  41. data/test/layouts/test_yaml.rb +121 -0
  42. data/test/setup.rb +1 -1
  43. data/test/test_appender.rb +0 -14
  44. data/test/test_log_event.rb +1 -1
  45. data/test/test_logging.rb +3 -3
  46. metadata +17 -2
data/History.txt CHANGED
@@ -1,3 +1,16 @@
1
+ == 1.0.0 / 2009-04-17
2
+
3
+ 2 major enhancements
4
+ - Refactored access to the appenders
5
+ - Created a much cleaner way to initialize the logging framework
6
+ 3 minor enhancements
7
+ - Added a YAML layout option
8
+ - Added a JSON layout option
9
+ - Cration of an "examples" directory
10
+ 1 bug fix
11
+ - Logging initialization happens implicitly when a logger, layout, or
12
+ appender is created
13
+
1
14
  == 0.9.8 / 2009-04-11
2
15
 
3
16
  2 minor enhancements
data/README.rdoc CHANGED
@@ -14,7 +14,7 @@ formatting, and more.
14
14
 
15
15
  == INSTALL
16
16
 
17
- sudo gem install logging
17
+ sudo gem install logging
18
18
 
19
19
  == EXAMPLE
20
20
 
@@ -22,58 +22,70 @@ This example configures a logger to output messages in a format similar to the
22
22
  core ruby Logger class. Only log messages that are warnings or higher will be
23
23
  logged.
24
24
 
25
- require 'logging'
25
+ require 'logging'
26
26
 
27
- logger = Logging.logger(STDOUT)
28
- logger.level = :warn
27
+ logger = Logging.logger(STDOUT)
28
+ logger.level = :warn
29
29
 
30
- logger.debug "this debug message will not be output by the logger"
31
- logger.warn "this is your last warning"
30
+ logger.debug "this debug message will not be output by the logger"
31
+ logger.warn "this is your last warning"
32
32
 
33
33
  In this example, a single logger is crated that will append to STDOUT and to a
34
34
  file. Only log messages that are informational or higher will be logged.
35
35
 
36
- require 'logging'
36
+ require 'logging'
37
37
 
38
- logger = Logging::Logger['example_logger']
39
- logger.add_appenders(
40
- Logging::Appender.stdout,
41
- Logging::Appenders::File.new('example.log')
42
- )
43
- logger.level = :info
38
+ logger = Logging.logger['example_logger']
39
+ logger.add_appenders(
40
+ Logging.appenders.stdout,
41
+ Logging.appenders.file('example.log')
42
+ )
43
+ logger.level = :info
44
44
 
45
- logger.debug "this debug message will not be output by the logger"
46
- logger.info "just some friendly advice"
45
+ logger.debug "this debug message will not be output by the logger"
46
+ logger.info "just some friendly advice"
47
47
 
48
48
  The Logging library was created to allow each class in a program to have its
49
49
  own configurable logger. The logging level for a particular class can be
50
50
  changed independently of all other loggers in the system. This example shows
51
51
  the recommended way of accomplishing this.
52
52
 
53
- require 'logging'
54
-
55
- Logging::Logger['FirstClass'].level = :warn
56
- Logging::Logger['SecondClass'].level = :debug
57
-
58
- class FirstClass
59
- def initialize
60
- @log = Logging::Logger[self]
61
- end
62
-
63
- def some_method
64
- @log.debug "some method was called on #{self.inspect}"
65
- end
66
- end
67
-
68
- class SecondClass
69
- def initialize
70
- @log = Logging::Logger[self]
71
- end
72
-
73
- def another_method
74
- @log.debug "another method was called on #{self.inspect}"
75
- end
76
- end
53
+ require 'logging'
54
+
55
+ Logging.logger['FirstClass'].level = :warn
56
+ Logging.logger['SecondClass'].level = :debug
57
+
58
+ class FirstClass
59
+ def initialize
60
+ @log = Logging.logger[self]
61
+ end
62
+
63
+ def some_method
64
+ @log.debug "some method was called on #{self.inspect}"
65
+ end
66
+ end
67
+
68
+ class SecondClass
69
+ def initialize
70
+ @log = Logging.logger[self]
71
+ end
72
+
73
+ def another_method
74
+ @log.debug "another method was called on #{self.inspect}"
75
+ end
76
+ end
77
+
78
+ There are many more examples in the "examples" folder of the logging
79
+ package. The recommended reading order is the following:
80
+
81
+ simple.rb
82
+ loggers.rb
83
+ classes.rb
84
+ hierarchies.rb
85
+ names.rb
86
+ appenders.rb
87
+ layouts.rb
88
+ formatting.rb
77
89
 
78
90
  == NOTES
79
91
 
data/Rakefile CHANGED
@@ -27,6 +27,7 @@ PROJ.ignore_file = '.gitignore'
27
27
 
28
28
  PROJ.exclude << %w[^tags$ logging.gemspec]
29
29
  PROJ.rdoc.exclude << '^data'
30
+ PROJ.rdoc.include << '^examples/.*\.rb'
30
31
  #PROJ.rdoc.dir = 'doc/rdoc'
31
32
  #PROJ.rdoc.remote_dir = 'rdoc'
32
33
  PROJ.rdoc.dir = 'doc'
@@ -0,0 +1,44 @@
1
+ #
2
+ # Appenders are used to output log events to some logging destination. The
3
+ # same log event can be sent to multiple desitnations by associating
4
+ # multiple appenders with the logger.
5
+ #
6
+ # The following is a list of all the available appenders and a brief
7
+ # description of each. Please refer to the documentation for specific
8
+ # configuration options available for each.
9
+ #
10
+ # Email generates e-mail messages
11
+ # File writes to a regular file
12
+ # Growl outputs growl notifications (Mac OS X only)
13
+ # IO generic IO appender
14
+ # RollingFile writes to a file and rolls based on size or age
15
+ # Stdout appends to STDOUT
16
+ # Stderr appends to STDERR
17
+ # StringIo writes to a StringIO instance (useful for testing)
18
+ # Syslog outputs to syslogd (not available on all systems)
19
+ #
20
+ # And you can access these appenders:
21
+ #
22
+ # Logging.appenders.email
23
+ # Logging.appenders.file
24
+ # Logging.appenders.growl
25
+ # Logging.appenders.io
26
+ # Logging.appenders.rolling_file
27
+ # Logging.appenders.stdout
28
+ # Logging.appenders.stderr
29
+ # Logging.appenders.string_io
30
+ # Logging.appenders.syslog
31
+ #
32
+
33
+ require 'logging'
34
+
35
+ log = Logging.logger['example']
36
+ log.add_appenders(
37
+ Logging.appenders.stdout,
38
+ Logging.appenders.file('development.log')
39
+ )
40
+ log.level = :debug
41
+
42
+ # These messages will be logged to both the log file and to STDOUT
43
+ log.debug "a very nice little debug message"
44
+ log.warn "this is your last warning"
@@ -0,0 +1,39 @@
1
+ #
2
+ # The Logging framework is very good about figuring out predictable names
3
+ # for loggers regardless of what object is used to create them. The name is
4
+ # the class name or module name of whatever is passed to the logger bracket
5
+ # method. The following lines all return the exact same logger instance:
6
+ #
7
+ # ary = Array.new
8
+ # Logging.logger[ary]
9
+ # Logging.logger[Array]
10
+ # Logging.logger['Array']
11
+ # Logging.logger[:Array]
12
+ #
13
+ # So, if you want each class to have it's own logger this is very easy to
14
+ # do.
15
+ #
16
+
17
+ require 'logging'
18
+
19
+ Logging.logger.root.appenders = Logging.appenders.stdout
20
+ Logging.logger.root.level = :info
21
+
22
+ class Foo
23
+ attr_reader :log
24
+ def initialize() @log = Logging.logger[self]; end
25
+ end
26
+
27
+ class Foo::Bar
28
+ attr_reader :log
29
+ def initialize() @log = Logging.logger[self]; end
30
+ end
31
+
32
+ foo = Foo.new.log
33
+ bar = Foo::Bar.new.log
34
+
35
+ # you'll notice in these log messages that the logger names were taken
36
+ # from the class names of the Foo and Foo::Bar instances
37
+ foo.info 'this message came from Foo'
38
+ bar.warn 'this is a warning from Foo::Bar'
39
+
@@ -0,0 +1,49 @@
1
+ #
2
+ # Any Ruby object can be passed to the log methods of a logger. How these
3
+ # objects are formatted by the Logging framework is controlled by a global
4
+ # "format_as" option and a global "backtrace" option.
5
+ #
6
+ # The format_as option allows objects to be converted to a string using the
7
+ # standard "to_s" method, the "inspect" method, or the "to_yaml" method
8
+ # (this is independent of the YAML layout). The format_as option can be
9
+ # overridden by each layout as desired.
10
+ #
11
+ # Logging.format_as :string # or :inspect or :yaml
12
+ #
13
+ # Exceptions are treated differently by the logging framework. The Exception
14
+ # class is printed along with the message. Optionally, exception backtraces
15
+ # can be included in the logging output; this option is enabled by default.
16
+ #
17
+ # Logging.backtrace false
18
+ #
19
+ # The backtrace can be enabled or disabled for each layout as needed.
20
+ #
21
+
22
+ require 'logging'
23
+
24
+ Logging.format_as :inspect
25
+ Logging.backtrace false
26
+
27
+ Logging.appenders.stdout(
28
+ :layout => Logging.layouts.basic(:format_as => :yaml)
29
+ )
30
+
31
+ Logging.appenders.stderr(
32
+ :layout => Logging.layouts.basic(:backtrace => true)
33
+ )
34
+
35
+ log = Logging.logger['foo']
36
+ log.appenders = %w[stdout stderr]
37
+
38
+ # these log messages will all appear twice because of the two appenders -
39
+ # STDOUT and STDERR - but the interesting thing is the difference in the
40
+ # output
41
+ log.info %w[An Array Of Strings]
42
+ log.info({"one"=>1, "two"=>2})
43
+
44
+ begin
45
+ 1 / 0
46
+ rescue => err
47
+ log.error err
48
+ end
49
+
@@ -0,0 +1,71 @@
1
+ #
2
+ # Loggers exist in a hierarchical relationship defined by their names. Each
3
+ # logger has a parent (except for the root logger). A logger can zero or
4
+ # more children. This parent/child relationship is determined by the Ruby
5
+ # namespace separator '::'.
6
+ #
7
+ # root
8
+ # |-- Foo
9
+ # | |-- Foo::Bar
10
+ # | `-- Foo::Baz
11
+ # |-- ActiveRecord
12
+ # | `-- ActiveRecord::Base
13
+ # |-- ActiveSupport
14
+ # | `-- ActiveSupport::Base
15
+ # `-- Rails
16
+ #
17
+ # A logger inherits its log level from its parent. This level can be set for
18
+ # each logger in the system. Setting the level on a logger affects all it's
19
+ # children and grandchildren, etc. unless the child has it's own level set.
20
+ #
21
+ # Loggers also have a property called "additivity", and by default it is set
22
+ # to true for all loggers. This property enables a logger to pass log events
23
+ # up to its parent.
24
+ #
25
+ # If a logger does not have an appender and its additivity is true, it will
26
+ # pass all log events up to its parent who will then try to send the log
27
+ # event to its appenders. The parent will do the same thing, passing the log
28
+ # event up the chain till the root logger is reached or some parent logger
29
+ # has its additivity set to false.
30
+ #
31
+ # So, if the root logger is the only one with an appender, all loggers can
32
+ # still output log events to the appender because of additivity. A logger
33
+ # will ALWAYS send log events to its own appenders regardless of its
34
+ # additivity.
35
+ #
36
+ # The show_configuration method can be used to dump the logging hierarchy.
37
+ #
38
+
39
+ require 'logging'
40
+
41
+ Logging.logger.root.level = :debug
42
+
43
+ foo = Logging.logger['Foo']
44
+ bar = Logging.logger['Foo::Bar']
45
+ baz = Logging.logger['Foo::Baz']
46
+
47
+ # configure the Foo logger
48
+ foo.level = 'warn'
49
+ foo.appenders = Logging.appenders.stdout
50
+
51
+ # since Foo is the parent of Foo::Bar and Foo::Baz, these loggers all have
52
+ # their level set to warn
53
+
54
+ foo.warn 'this is a warning, not a ticket'
55
+ bar.info 'this message will not be logged'
56
+ baz.info 'nor will this message'
57
+ bar.error 'but this error message will be logged'
58
+
59
+ # let's demonstrate additivity of loggers
60
+
61
+ Logging.logger.root.appenders = Logging.appenders.stdout
62
+
63
+ baz.warn 'this message will be logged twice - once by Foo and once by root'
64
+
65
+ foo.additive = false
66
+ bar.warn "foo is no longer passing log events up to it's parent"
67
+
68
+ # let's look at the logger hierarchy
69
+ puts '='*76
70
+ Logging.show_configuration
71
+
@@ -0,0 +1,45 @@
1
+ #
2
+ # The formatting of log messages is controlled by the layout given to the
3
+ # appender. By default all appenders use the Basic layout. It's pretty
4
+ # basic. However, a more sophisticated Pattern layout can be used or one of
5
+ # the Parseable layouts -- JSON or YAML.
6
+ #
7
+ # The available layouts are:
8
+ #
9
+ # Logging.layouts.basic
10
+ # Logging.layouts.pattern
11
+ # Logging.layouts.json
12
+ # Logging.layouts.yaml
13
+ #
14
+ # In this example we'll demonstrate use of different layouts and setting log
15
+ # levels in the appenders to filter out events.
16
+ #
17
+
18
+ require 'logging'
19
+
20
+ # only show "info" or higher messages on STDOUT using the Basic layout
21
+ Logging.appenders.stdout(:level => :info)
22
+
23
+ # send all log events to the development log (including debug) as JSON
24
+ Logging.appenders.rolling_file(
25
+ 'development.log',
26
+ :age => 'daily',
27
+ :layout => Logging.layouts.json
28
+ )
29
+
30
+ # send growl notifications for errors and fatals using a nice pattern
31
+ Logging.appenders.growl(
32
+ 'growl',
33
+ :level => :error,
34
+ :layout => Logging.layouts.pattern(:pattern => '[%d] %-5l: %m\n')
35
+ )
36
+
37
+ log = Logging.logger['Foo::Bar']
38
+ log.add_appenders 'stdout', 'development.log', 'growl'
39
+ log.level = :debug
40
+
41
+ log.debug "a very nice little debug message"
42
+ log.info "things are operating nominally"
43
+ log.warn "this is your last warning"
44
+ log.error StandardError.new("something went horribly wrong")
45
+ log.fatal "I Die!"
@@ -0,0 +1,26 @@
1
+ #
2
+ # Multiple loggers can be created and each can be configured with it's own
3
+ # log level and appenders. So one logger can be configured to output debug
4
+ # messages, and all the others can be left at the info or warn level. This
5
+ # makes it easier to debug specific portions of your code.
6
+ #
7
+
8
+ require 'logging'
9
+
10
+ # all loggers inherit the log level of the "root" logger
11
+ # but specific loggers can be given their own level
12
+ Logging.logger.root.level = :warn
13
+
14
+ # similarly, the root appender will be used by all loggers
15
+ Logging.logger.root.appenders = Logging.appenders.file('output.log')
16
+
17
+ log1 = Logging.logger['Log1']
18
+ log2 = Logging.logger['Log2']
19
+ log3 = Logging.logger['Log3']
20
+
21
+ # you can use strings or symbols to set the log level
22
+ log3.level = 'debug'
23
+
24
+ log1.info "this message will not get logged"
25
+ log2.info "nor will this message"
26
+ log3.info "but this message will get logged"
data/examples/names.rb ADDED
@@ -0,0 +1,40 @@
1
+ #
2
+ # Loggers and appenders can be looked up by name. The bracket notation is
3
+ # used to find these objects:
4
+ #
5
+ # Logging.logger['foo']
6
+ # Logging.appenders['bar']
7
+ #
8
+ # A logger will be created if a new name is used. Appenders are different;
9
+ # nil is returned when an unknown appender name is used. The reason for this
10
+ # is that appenders come in many different flavors (so it is unclear which
11
+ # type should be created), but there is only one type of logger.
12
+ #
13
+ # So it is useful to be able to create an appender and then reference it by
14
+ # name to add it to multiple loggers. When the same name is used, the same
15
+ # object will be returned by the bracket methods.
16
+ #
17
+ # Layouts do not have names. Some are stateful, and none are threadsafe. So
18
+ # each appender is configured with it's own layout.
19
+ #
20
+
21
+ require 'logging'
22
+
23
+ Logging.appenders.file('Debug File', :filename => 'debug.log')
24
+ Logging.appenders.growl('Growl Notifier', :level => :error)
25
+
26
+ # configure the root logger
27
+ Logging.logger.root.appenders = 'Debug File'
28
+ Logging.logger.root.level = :debug
29
+
30
+ # add the growl notifier to the Critical logger (it will use it's own
31
+ # appender and the root logger's appender, too)
32
+ Logging.logger['Critical'].appenders = 'Growl Notifier'
33
+
34
+ # if you'll notice above, assigning appenders using just the name is valid
35
+ # the logger is smart enough to figure out it was given a string and then
36
+ # go lookup the appender by name
37
+
38
+ # and now log some messages
39
+ Logging.logger['Critical'].info 'just keeping you informed'
40
+ Logging.logger['Critical'].fatal 'WTF!!'