logging 1.6.2 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/.travis.yml +13 -0
  2. data/History.txt +10 -0
  3. data/README.rdoc +24 -3
  4. data/Rakefile +2 -2
  5. data/lib/logging.rb +23 -23
  6. data/lib/logging/appender.rb +9 -6
  7. data/lib/logging/appenders.rb +12 -84
  8. data/lib/logging/appenders/buffering.rb +2 -2
  9. data/lib/logging/appenders/console.rb +22 -4
  10. data/lib/logging/appenders/email.rb +166 -61
  11. data/lib/logging/appenders/file.rb +9 -2
  12. data/lib/logging/appenders/growl.rb +12 -8
  13. data/lib/logging/appenders/io.rb +9 -2
  14. data/lib/logging/appenders/rolling_file.rb +9 -2
  15. data/lib/logging/appenders/string_io.rb +9 -2
  16. data/lib/logging/appenders/syslog.rb +9 -3
  17. data/lib/logging/layouts.rb +5 -42
  18. data/lib/logging/layouts/basic.rb +7 -0
  19. data/lib/logging/layouts/parseable.rb +18 -0
  20. data/lib/logging/layouts/pattern.rb +7 -0
  21. data/lib/logging/proxy.rb +2 -0
  22. data/lib/logging/utils.rb +3 -1
  23. data/test/appenders/test_buffered_io.rb +0 -1
  24. data/test/appenders/test_console.rb +0 -1
  25. data/test/appenders/test_email.rb +14 -14
  26. data/test/appenders/test_growl.rb +14 -3
  27. data/test/appenders/test_io.rb +0 -1
  28. data/test/appenders/test_periodic_flushing.rb +2 -1
  29. data/test/appenders/test_syslog.rb +0 -1
  30. data/test/benchmark.rb +0 -1
  31. data/test/config/test_configurator.rb +0 -1
  32. data/test/config/test_yaml_configurator.rb +0 -1
  33. data/test/layouts/test_basic.rb +0 -1
  34. data/test/layouts/test_json.rb +0 -1
  35. data/test/layouts/test_yaml.rb +0 -1
  36. data/test/test_appender.rb +0 -1
  37. data/test/test_consolidate.rb +0 -1
  38. data/test/test_layout.rb +0 -1
  39. data/test/test_log_event.rb +0 -1
  40. data/test/test_logger.rb +0 -1
  41. data/test/test_logging.rb +1 -2
  42. data/test/test_proxy.rb +6 -0
  43. data/test/test_repository.rb +0 -1
  44. data/test/test_root_logger.rb +0 -1
  45. data/test/test_stats.rb +0 -1
  46. data/test/test_utils.rb +1 -2
  47. data/version.txt +1 -1
  48. metadata +11 -21
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+
3
+ before_install: "gem install bones"
4
+ install: "rake gem:install_dependencies"
5
+
6
+ script: "rake"
7
+
8
+ rvm:
9
+ - 1.8.7
10
+ - 1.9.2
11
+ - 1.9.3
12
+ - jruby
13
+
data/History.txt CHANGED
@@ -1,3 +1,13 @@
1
+ == 1.7.0 / 2012-02-18
2
+
3
+ Enhancements
4
+ - Move appender factories [issue #28]
5
+ - ActionMail compatible options in the email appender [issue #27]
6
+ - Add TLS support to the email appender [issue #25]
7
+ - Refactoring appender shutdown [issue #20]
8
+ Bug Fixes
9
+ - File locking fails on windows using JRuby [issue #22]
10
+
1
11
  == 1.6.2 / 2012-01-05
2
12
 
3
13
  Bug Fixes
data/README.rdoc CHANGED
@@ -1,5 +1,5 @@
1
- Logging
2
- by Tim Pease
1
+ = Logging
2
+ by Tim Pease {<img src="https://secure.travis-ci.org/TwP/logging.png">}[http://travis-ci.org/TwP/logging]
3
3
 
4
4
  * {Homepage}[http://rubygems.org/gems/logging]
5
5
  * {Github Project}[http://github.com/TwP/logging]
@@ -116,4 +116,25 @@ Always remember that "rake -T" is your friend!
116
116
 
117
117
  == LICENSE
118
118
 
119
- Ruby
119
+ The MIT License
120
+
121
+ Copyright (c) 2012 Tim Pease
122
+
123
+ Permission is hereby granted, free of charge, to any person obtaining
124
+ a copy of this software and associated documentation files (the
125
+ 'Software'), to deal in the Software without restriction, including
126
+ without limitation the rights to use, copy, modify, merge, publish,
127
+ distribute, sublicense, and/or sell copies of the Software, and to
128
+ permit persons to whom the Software is furnished to do so, subject to
129
+ the following conditions:
130
+
131
+ The above copyright notice and this permission notice shall be
132
+ included in all copies or substantial portions of the Software.
133
+
134
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
135
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
136
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
137
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
138
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
139
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
140
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -17,7 +17,7 @@ Bones {
17
17
 
18
18
  rdoc.exclude << '^data'
19
19
  rdoc.include << '^examples/.*\.rb'
20
- rcov.opts << '-x' << '~/.rvm/'
20
+ #rcov.opts << '-x' << '~/.rvm/'
21
21
 
22
22
  use_gmail
23
23
 
@@ -25,6 +25,6 @@ Bones {
25
25
 
26
26
  depend_on 'flexmock', :development => true
27
27
  depend_on 'bones-git', :development => true
28
- depend_on 'bones-rcov', :development => true
28
+ #depend_on 'bones-rcov', :development => true
29
29
  }
30
30
 
data/lib/logging.rb CHANGED
@@ -493,7 +493,7 @@ module Logging
493
493
  end
494
494
 
495
495
  # Close all appenders
496
- def shutdown
496
+ def shutdown( *args )
497
497
  log_internal {'shutdown called - closing all appenders'}
498
498
  ::Logging::Appenders.each {|appender| appender.close}
499
499
  end
@@ -511,34 +511,34 @@ module Logging
511
511
  end
512
512
  # :startdoc:
513
513
  end
514
- end # module Logging
515
-
516
-
517
- Logging.libpath {
518
- require 'logging/appender'
519
- require 'logging/layout'
520
- require 'logging/log_event'
521
- require 'logging/logger'
522
- require 'logging/repository'
523
- require 'logging/root_logger'
524
- require 'logging/stats'
525
- require 'logging/color_scheme'
526
- require 'logging/appenders'
527
- require 'logging/layouts'
528
- require 'logging/proxy'
529
514
 
530
- require 'logging/config/configurator'
531
- require 'logging/config/yaml_configurator'
532
-
533
- require 'logging/rails_compat'
534
- }
515
+ require libpath('logging/appender')
516
+ require libpath('logging/layout')
517
+ require libpath('logging/log_event')
518
+ require libpath('logging/logger')
519
+ require libpath('logging/repository')
520
+ require libpath('logging/root_logger')
521
+ require libpath('logging/stats')
522
+ require libpath('logging/color_scheme')
523
+ require libpath('logging/appenders')
524
+ require libpath('logging/layouts')
525
+ require libpath('logging/proxy')
526
+
527
+ require libpath('logging/config/configurator')
528
+ require libpath('logging/config/yaml_configurator')
529
+
530
+ require libpath('logging/rails_compat')
531
+ end # module Logging
535
532
 
536
533
 
537
- # This exit handler will close all the appenders that exist in the system.
534
+ # This finalizer will close all the appenders that exist in the system.
538
535
  # This is needed for closing IO streams and connections to the syslog server
539
536
  # or e-mail servers, etc.
540
537
  #
541
- at_exit { Logging.shutdown }
538
+ # You can prevent the finalizer from running by calling `exit!` from your
539
+ # application. This is required when daemonizing.
540
+ #
541
+ ObjectSpace.define_finalizer self, Logging.method(:shutdown)
542
542
 
543
543
  end # unless defined?
544
544
 
@@ -42,13 +42,16 @@ class Appender
42
42
  self.level = opts.getopt(:level)
43
43
 
44
44
  @mutex = ReentrantMutex.new
45
- header = @layout.header
46
45
 
47
- unless header.nil? || header.empty?
48
- begin
49
- write(header)
50
- rescue StandardError => err
51
- ::Logging.log_internal(-2) {err}
46
+ if opts.getopt(:header, true)
47
+ header = @layout.header
48
+
49
+ unless header.nil? || header.empty?
50
+ begin
51
+ write(header)
52
+ rescue StandardError => err
53
+ ::Logging.log_internal(-2) {err}
54
+ end
52
55
  end
53
56
  end
54
57
 
@@ -2,75 +2,6 @@
2
2
  module Logging
3
3
  module Appenders
4
4
 
5
- # Accessor / Factory for the Email appender.
6
- #
7
- def email( *args )
8
- return ::Logging::Appenders::Email if args.empty?
9
- ::Logging::Appenders::Email.new(*args)
10
- end
11
-
12
- # Accessor / Factory for the File appender.
13
- #
14
- def file( *args )
15
- return ::Logging::Appenders::File if args.empty?
16
- ::Logging::Appenders::File.new(*args)
17
- end
18
-
19
- # Accessor / Factory for the Growl appender.
20
- #
21
- def growl( *args )
22
- return ::Logging::Appenders::Growl if args.empty?
23
- ::Logging::Appenders::Growl.new(*args)
24
- end
25
-
26
- # Accessor / Factory for the IO appender.
27
- #
28
- def io( *args )
29
- return ::Logging::Appenders::IO if args.empty?
30
- ::Logging::Appenders::IO.new(*args)
31
- end
32
-
33
- # Accessor / Factory for the RollingFile appender.
34
- #
35
- def rolling_file( *args )
36
- return ::Logging::Appenders::RollingFile if args.empty?
37
- ::Logging::Appenders::RollingFile.new(*args)
38
- end
39
-
40
- # Accessor / Factory for the Stderr appender.
41
- #
42
- def stderr( *args )
43
- if args.empty?
44
- return self['stderr'] || ::Logging::Appenders::Stderr.new
45
- end
46
- ::Logging::Appenders::Stderr.new(*args)
47
- end
48
-
49
- # Accessor / Factory for the Stdout appender.
50
- #
51
- def stdout( *args )
52
- if args.empty?
53
- return self['stdout'] || ::Logging::Appenders::Stdout.new
54
- end
55
- ::Logging::Appenders::Stdout.new(*args)
56
- end
57
-
58
- # Accessor / Factory for the StringIo appender.
59
- #
60
- def string_io( *args )
61
- return ::Logging::Appenders::StringIo if args.empty?
62
- ::Logging::Appenders::StringIo.new(*args)
63
- end
64
-
65
- if HAVE_SYSLOG
66
- # Accessor / Factory for the Syslog appender.
67
- #
68
- def syslog( *args )
69
- return ::Logging::Appenders::Syslog if args.empty?
70
- ::Logging::Appenders::Syslog.new(*args)
71
- end
72
- end
73
-
74
5
  # call-seq:
75
6
  # Appenders[name]
76
7
  #
@@ -118,19 +49,16 @@ module Logging
118
49
 
119
50
  extend self
120
51
  @appenders = Hash.new
121
-
122
- end # module Appenders
123
- end # module Logging
124
-
125
- Logging.libpath {
126
- require 'logging/appenders/buffering'
127
- require 'logging/appenders/io'
128
- require 'logging/appenders/console'
129
- require 'logging/appenders/email'
130
- require 'logging/appenders/file'
131
- require 'logging/appenders/growl'
132
- require 'logging/appenders/rolling_file'
133
- require 'logging/appenders/string_io'
134
- require 'logging/appenders/syslog'
135
- }
52
+ end # Appenders
53
+
54
+ require libpath('logging/appenders/buffering')
55
+ require libpath('logging/appenders/io')
56
+ require libpath('logging/appenders/console')
57
+ require libpath('logging/appenders/email')
58
+ require libpath('logging/appenders/file')
59
+ require libpath('logging/appenders/growl')
60
+ require libpath('logging/appenders/rolling_file')
61
+ require libpath('logging/appenders/string_io')
62
+ require libpath('logging/appenders/syslog')
63
+ end # Logging
136
64
 
@@ -390,6 +390,6 @@ module Logging::Appenders
390
390
  end # class PeriodicFlusher
391
391
  # :startdoc:
392
392
 
393
- end # module Buffering
394
- end # module Logging::Appenders
393
+ end # Buffering
394
+ end # Logging::Appenders
395
395
 
@@ -1,6 +1,15 @@
1
1
 
2
2
  module Logging::Appenders
3
3
 
4
+ # Accessor / Factory for the Stdout appender.
5
+ #
6
+ def self.stdout( *args )
7
+ if args.empty?
8
+ return self['stdout'] || ::Logging::Appenders::Stdout.new
9
+ end
10
+ ::Logging::Appenders::Stdout.new(*args)
11
+ end
12
+
4
13
  # This class provides an Appender that can write to STDOUT.
5
14
  #
6
15
  class Stdout < ::Logging::Appenders::IO
@@ -26,7 +35,17 @@ module Logging::Appenders
26
35
 
27
36
  super(name, STDOUT, opts)
28
37
  end
29
- end # class Stdout
38
+ end # Stdout
39
+
40
+
41
+ # Accessor / Factory for the Stderr appender.
42
+ #
43
+ def self.stderr( *args )
44
+ if args.empty?
45
+ return self['stderr'] || ::Logging::Appenders::Stderr.new
46
+ end
47
+ ::Logging::Appenders::Stderr.new(*args)
48
+ end
30
49
 
31
50
  # This class provides an Appender that can write to STDERR.
32
51
  #
@@ -53,7 +72,6 @@ module Logging::Appenders
53
72
 
54
73
  super(name, STDERR, opts)
55
74
  end
56
- end # class Stderr
57
-
58
- end # module Logging::Appenders
75
+ end # Stderr
76
+ end # Logging::Appenders
59
77
 
@@ -2,70 +2,175 @@
2
2
  require 'net/smtp'
3
3
  require 'time' # get rfc822 time format
4
4
 
5
- # a replacement EmailOutputter. This is essentially the default EmailOutputter from Log4r but with the following
6
- # changes:
7
- # 1) if there is data to send in an email, then do not send anything
8
- # 2) connect to the smtp server at the last minute, do not connect at startup and then send later on.
9
- # 3) Fix the To: field so that it looks alright.
10
5
  module Logging::Appenders
11
6
 
12
- class Email < ::Logging::Appender
13
- include Buffering
14
-
15
- attr_reader :server, :port, :domain, :acct, :authtype, :subject
16
-
17
- # TODO: make the from/to fields modifiable
18
- # possibly the subject, too
19
-
20
- def initialize( name, opts = {} )
21
- super(name, opts)
22
-
23
- af = opts.getopt(:buffsize) ||
24
- opts.getopt(:buffer_size) ||
25
- 100
26
- configure_buffering({:auto_flushing => af}.merge(opts))
27
-
28
- # get the SMTP parameters
29
- @from = opts.getopt(:from)
30
- raise ArgumentError, 'Must specify from address' if @from.nil?
31
-
32
- @to = opts.getopt(:to, '').split(',')
33
- raise ArgumentError, 'Must specify recipients' if @to.empty?
34
-
35
- @server = opts.getopt :server, 'localhost'
36
- @port = opts.getopt :port, 25, :as => Integer
37
- @domain = opts.getopt(:domain, ENV['HOSTNAME']) || 'localhost.localdomain'
38
- @acct = opts.getopt :acct
39
- @passwd = opts.getopt :passwd
40
- @authtype = opts.getopt :authtype, :cram_md5, :as => Symbol
41
- @subject = opts.getopt :subject, "Message of #{$0}"
42
- @params = [@server, @port, @domain, @acct, @passwd, @authtype]
43
- end
44
-
45
-
46
- private
47
-
48
- # This method is called by the buffering code when messages need to be
49
- # sent out as an email.
7
+ # Accessor / Factory for the Email appender.
50
8
  #
51
- def canonical_write( str )
52
- ### build a mail header for RFC 822
53
- rfc822msg = "From: #{@from}\n"
54
- rfc822msg << "To: #{@to.join(",")}\n"
55
- rfc822msg << "Subject: #{@subject}\n"
56
- rfc822msg << "Date: #{Time.new.rfc822}\n"
57
- rfc822msg << "Message-Id: <#{"%.8f" % Time.now.to_f}@#{@domain}>\n\n"
58
- rfc822msg << str
59
-
60
- ### send email
61
- Net::SMTP.start(*@params) {|smtp| smtp.sendmail(rfc822msg, @from, @to)}
62
- self
63
- rescue StandardError, TimeoutError => err
64
- self.level = :off
65
- ::Logging.log_internal {'e-mail notifications have been disabled'}
66
- ::Logging.log_internal(-2) {err}
9
+ def self.email( *args )
10
+ return ::Logging::Appenders::Email if args.empty?
11
+ ::Logging::Appenders::Email.new(*args)
67
12
  end
68
13
 
69
- end # class Email
70
- end # module Logging::Appenders
14
+ # Provides an appender that can send log messages via email to a list of
15
+ # recipients.
16
+ #
17
+ class Email < ::Logging::Appender
18
+ include Buffering
19
+
20
+ attr_reader :authentication, :to, :port
21
+ attr_accessor :address, :domain, :from, :subject
22
+ attr_accessor :user_name, :password, :enable_starttls_auto
23
+
24
+ # call-seq:
25
+ # Email.new( name, :from => 'me@example.com', :to => 'you@example.com', :subject => 'Whoops!' )
26
+ #
27
+ # Create a new email appender that will buffer messages and then send them
28
+ # out in batches to the listed recipients. See the options below to
29
+ # configure how emails are sent through you mail server of choice. All the
30
+ # buffering options apply to the email appender.
31
+ #
32
+ # The following options are required:
33
+ #
34
+ # :from - The base filename to use when constructing new log
35
+ # filenames.
36
+ # :to - The list of email recipients either as an Array or a comma
37
+ # separated list.
38
+ #
39
+ # The following options are optional:
40
+ #
41
+ # :subject - The subject line for the email.
42
+ # :address - Allows you to use a remote mail server. Just change it
43
+ # from its default "localhost" setting.
44
+ # :port - On the off chance that your mail server doesn't run on
45
+ # port 25, you can change it.
46
+ # :domain - If you need to specify a HELO domain, you can do it here.
47
+ # :user_name - If your mail server requires authentication, set the user
48
+ # name in this setting.
49
+ # :password - If your mail server requires authentication, set the
50
+ # password in this setting.
51
+ # :authentication - If your mail server requires authentication, you need
52
+ # to specify the authentication type here. This is a
53
+ # symbol and one of :plain (will send the password in
54
+ # the clear), :login (will send password Base64
55
+ # encoded) or :cram_md5 (combines a Challenge/Response
56
+ # mechanism to exchange information and a cryptographic
57
+ # Message Digest 5 algorithm to hash important
58
+ # information)
59
+ # :enable_starttls_auto - When set to true, detects if STARTTLS is
60
+ # enabled in your SMTP server and starts to use it.
61
+ #
62
+ # Example:
63
+ #
64
+ # Setup an email appender that will buffer messages for up to 1 minute,
65
+ # and only send messages for ERROR and FATAL messages. This example uses
66
+ # Google's SMTP server with authentication to send out messages.
67
+ #
68
+ # Logger.appenders.email( 'email',
69
+ # :from => "server@example.com",
70
+ # :to => "developers@example.com",
71
+ # :subject => "Application Error [#{%x(uname -n).strip}]",
72
+ #
73
+ # :address => "smtp.google.com",
74
+ # :port => 443,
75
+ # :domain => "google.com",
76
+ # :user_name => "example",
77
+ # :password => "12345",
78
+ # :authentication => :plain,
79
+ # :enable_starttls_auto => true,
80
+ #
81
+ # :auto_flushing => 200, # send an email after 200 messages have been buffered
82
+ # :flush_period => 60, # send an email after one minute
83
+ # :level => :error # only process log events that are "error" or "fatal"
84
+ # )
85
+ #
86
+ def initialize( name, opts = {} )
87
+ opts[:header] = false
88
+ super(name, opts)
89
+
90
+ af = opts.getopt(:buffsize) ||
91
+ opts.getopt(:buffer_size) ||
92
+ 100
93
+ configure_buffering({:auto_flushing => af}.merge(opts))
94
+
95
+ # get the SMTP parameters
96
+ self.from = opts.getopt :from
97
+ raise ArgumentError, 'Must specify from address' if @from.nil?
98
+
99
+ self.to = opts.getopt :to
100
+ raise ArgumentError, 'Must specify recipients' if @to.empty?
101
+
102
+ self.subject = opts.getopt :subject, "Message from #{$0}"
103
+ self.address = opts.getopt(:server) || opts.getopt(:address) || 'localhost'
104
+ self.port = opts.getopt(:port, 25)
105
+ self.domain = opts.getopt(:domain, ENV['HOSTNAME']) || 'localhost.localdomain'
106
+ self.user_name = opts.getopt(:acct) || opts.getopt(:user_name)
107
+ self.password = opts.getopt(:passwd) || opts.getopt(:password)
108
+ self.enable_starttls_auto = opts.getopt(:enable_starttls_auto, false)
109
+ self.authentication = opts.getopt(:authtype) || opts.getopt(:authentication) || :plain
110
+ end
111
+
112
+ # Close the email appender. If the layout contains a foot, it will not be
113
+ # sent as an email.
114
+ #
115
+ def close( *args )
116
+ super(false)
117
+ end
118
+
119
+ # If your mail server requires authentication, you need to specify the
120
+ # authentication type here. This is a symbol and one of :plain (will send
121
+ # the password in the clear), :login (will send password Base64 encoded)
122
+ # or :cram_md5 (combines a Challenge/Response mechanism to exchange
123
+ # information and a cryptographic Message Digest 5 algorithm to hash
124
+ # important information)
125
+ #
126
+ def authentication=( val )
127
+ @authentication = val.to_s.to_sym
128
+ end
129
+
130
+ # On the off chance that your mail server doesn't run on port 25, you can
131
+ # change it.
132
+ #
133
+ def port=( val )
134
+ @port = Integer(val)
135
+ end
136
+
137
+ # The list of email recipients. This can either be an Array of recipients
138
+ # or a comma separated list. A single recipient is also valid.
139
+ #
140
+ # email.to = ['mike@example.com', 'tony@example.com']
141
+ # email.to = 'alicia@example.com'
142
+ # email.to = 'bob@example.com, andy@example.com, john@example.com'
143
+ #
144
+ def to=( val )
145
+ @to = val.respond_to?(:split) ? val.split(',') : Array(val)
146
+ end
147
+
148
+
149
+ private
150
+
151
+ # This method is called by the buffering code when messages need to be
152
+ # sent out as an email.
153
+ #
154
+ def canonical_write( str )
155
+ ### build a mail header for RFC 822
156
+ rfc822msg = "From: #{@from}\n"
157
+ rfc822msg << "To: #{@to.join(",")}\n"
158
+ rfc822msg << "Subject: #{@subject}\n"
159
+ rfc822msg << "Date: #{Time.new.rfc822}\n"
160
+ rfc822msg << "Message-Id: <#{"%.8f" % Time.now.to_f}@#{@domain}>\n\n"
161
+ rfc822msg << str
162
+
163
+ ### send email
164
+ smtp = Net::SMTP.new(@address, @port)
165
+ smtp.enable_starttls_auto if @enable_starttls_auto and smtp.respond_to? :enable_starttls_auto
166
+ smtp.start(@domain, @user_name, @password, @authentication) { |s| s.sendmail(rfc822msg, @from, @to) }
167
+ self
168
+ rescue StandardError, TimeoutError => err
169
+ self.level = :off
170
+ ::Logging.log_internal {'e-mail notifications have been disabled'}
171
+ ::Logging.log_internal(-2) {err}
172
+ end
173
+
174
+ end # Email
175
+ end # Logging::Appenders
71
176