yell 0.1.0 → 0.2.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.
data/Gemfile CHANGED
@@ -7,6 +7,6 @@ gemspec
7
7
  group :development do
8
8
  gem "rake"
9
9
 
10
- gem "rspec", "~> 2"
10
+ gem "rspec"
11
11
  gem "timecop"
12
- end
12
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2011-2012 Rudolf Schmidt
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ Yell - Your Extensible Logging Library
2
+
3
+ ## Installation
4
+
5
+ System wide:
6
+
7
+ ```console
8
+ gem install yell
9
+ ```
10
+
11
+ Or in your Gemfile:
12
+
13
+ ```ruby
14
+ gem 'yell'
15
+ ```
16
+
17
+ ## Usage
18
+ On the basics, Yell works just like any other logging library. However, it
19
+ tries to make your log mesages more readable. By default, it will format the given
20
+ message as follows:
21
+
22
+ ```ruby
23
+ logger = Yell.new STDOUT
24
+
25
+ logger.info "Hello World"
26
+ "2012-02-29T09:30:00+01:00 [ INFO] 65784 : Hello World"
27
+ #^ ^ ^ ^
28
+ #ISO8601 Timestamp Level Pid message
29
+ ```
30
+
31
+ You can alternate the formatting, or completely disable it altogether. See the
32
+ next examples for reference:
33
+
34
+ ```ruby
35
+ # No formatting
36
+ logger = Yell.new STDOUT, :format => false
37
+ logger.info "No formatting"
38
+ "No formatting"
39
+
40
+ # Alternate formatting
41
+ logger = Yell.new STDOUT, :format => "'%m' at %d"
42
+ logger.info "Alternate formatting"
43
+ "'Alternate format' at 2012-02-29T09:30:00+01:00"
44
+ ```
45
+
46
+ As you can see, it basically is just string interpolation with a few reserved
47
+ captures. You can see the list at #Yell::Formatter.
48
+
49
+ When no arguments are given, Yell will check for `ENV['RACK_ENV']` and
50
+ determine the filename from that.
51
+
52
+ Alternatively, you may define `ENV['YELL_ENV']` to set the filename. If neither
53
+ `YELL_ENV` or `RACK_ENV` is defined, `'development'` will be the default. Also, if a
54
+ `log` directory exists, Yell will place the file there (only if you have not passed
55
+ a filename explicitly.
56
+
57
+ Naturally, if you pass a `:filename` to Yell:
58
+
59
+ ```ruby
60
+ logger = Yell.new 'custom.log'
61
+ ```
62
+
63
+ Copyright © 2011-2012 Rudolf Schmidt, released under the MIT license
64
+
data/lib/yell.rb CHANGED
@@ -1,19 +1,58 @@
1
- module Yell
1
+ # encoding: utf-8
2
2
 
3
- autoload :Config, File.dirname(__FILE__) + '/yell/config'
4
- autoload :Formatter, File.dirname(__FILE__) + '/yell/formatter'
5
- autoload :Logger, File.dirname(__FILE__) + '/yell/logger'
6
- autoload :Adapters, File.dirname(__FILE__) + '/yell/adapters'
3
+ # Copyright (c) 2011-2012 Rudolf Schmidt
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7
23
 
8
- class NoSuchAdapter < StandardError; end
24
+ require 'time'
9
25
 
26
+ $: << File.dirname(__FILE__)
10
27
 
11
- def self.new( *args, &block )
28
+ require 'yell/formatter'
29
+ require 'yell/adapters'
30
+ require 'yell/level'
31
+ require 'yell/logger'
32
+
33
+ module Yell #:nodoc:
34
+ # The possible log levels
35
+ Severities = [ 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL', 'UNKNOWN' ]
36
+
37
+ extend self
38
+
39
+ # Creates a new logger instance.
40
+ #
41
+ # Refer to #Yell::Loggger for usage.
42
+ #
43
+ # @returns [Yell::Logger] The logger instance
44
+ def new( *args, &block )
12
45
  Yell::Logger.new( *args, &block )
13
46
  end
14
-
15
- def self.config
16
- @@config ||= Yell::Config.new
47
+
48
+
49
+ def env #:nodoc:
50
+ ENV['YELL_ENV'] || ENV['RACK_ENV'] || 'development'
51
+ end
52
+
53
+ def level( val = nil ) #:nodoc:
54
+ Yell::Level.new( val )
17
55
  end
18
56
 
19
57
  end
58
+
data/lib/yell/adapters.rb CHANGED
@@ -1,21 +1,57 @@
1
- module Yell
1
+ # encoding: utf-8
2
+
3
+ require 'yell/adapters/base'
4
+ require 'yell/adapters/io'
5
+ require 'yell/adapters/file'
6
+ require 'yell/adapters/datefile'
7
+
8
+ module Yell #:nodoc:
9
+
10
+ # NoSuchAdapter is raised whenever you want to instantiate an
11
+ # adapter that does not exist.
12
+ class NoSuchAdapter < StandardError; end
13
+
14
+ # This module provides the interface to attaching adapters to
15
+ # the logger. You should not have to call the corresponding classes
16
+ # directly.
2
17
  module Adapters
18
+ extend self
3
19
 
4
- Dir[ ::File.dirname(__FILE__) + '/adapters/*.rb' ].each do |file|
5
- autoload ::File.basename(file, '.rb').capitalize, file
6
- end
20
+ # Returns an instance of the given processor type.
21
+ #
22
+ # @example A simple file adapter
23
+ # Yell::Adapters[ :file ]
24
+ def []( type, options = {}, &block )
25
+ # return type if type.instance_of?(Yell::Adapters::)
26
+
27
+ if type.instance_of?( ::IO )
28
+ # should apply to STDOUT, STDERR, File, etc
29
+ Yell::Adapters::Io.new( type, options, &block )
30
+ else
31
+ # any other type
32
+ adapter = case type
33
+ when String, Symbol then self.const_get( camelize(type.to_s) )
34
+ else type
35
+ end
7
36
 
8
- # returns an instance of the given processor type
9
- def self.new( type, options = {}, &block )
10
- klass = case type
11
- when String, Symbol then const_get( type.to_s.capitalize )
12
- else type
37
+ adapter.new( options, &block )
13
38
  end
14
-
15
- klass.new( options, &block )
16
- rescue NameError => e
17
- raise Yell::NoSuchAdapter, "no such adapter #{type.inspect}"
18
39
  end
19
-
40
+
41
+
42
+ private
43
+
44
+ # Simple camelcase converter.
45
+ #
46
+ # @example
47
+ # camelize("file")
48
+ # #=> "File"
49
+ #
50
+ # camelize("date_file")
51
+ # #=> "DateFile"
52
+ def camelize( str )
53
+ str.capitalize.gsub( /(_\w)/ ) { |match| match.reverse.chop.upcase }
54
+ end
55
+
20
56
  end
21
57
  end
Binary file
@@ -1,72 +1,55 @@
1
- module Yell::Adapters
2
- class Base
1
+ # encoding: utf-8
3
2
 
4
- attr_reader :name # name of the logger this adapter belongs to
3
+ module Yell #:nodoc:
4
+ module Adapters #:nodoc:
5
5
 
6
- # Initialize a new base adapter. Other adapters should inherit from it.
7
- def initialize ( options = {}, &block )
8
- @block = block
9
-
10
- @name = options[:name] || Yell.config.env
11
- @level, @data = '', '' # default
12
- end
13
-
14
- def call ( level, msg )
15
- reset!(true) if reset? # connect / get a file handle or whatever
16
-
17
- @level, @message = level, msg
18
-
19
- # self.instance_eval &@block if @block
20
- @block.call( self ) if @block
21
- end
22
-
23
- def message
24
- return @message if @message.is_a?( String )
25
-
26
- @message.inspect
27
- end
28
-
29
- # Convenience method for resetting the processor.
6
+ # This class provides the basic interface for all allowed
7
+ # operations on any adapter implementation.
30
8
  #
31
- # @param [true, false] now Perform the reset immediately? (default false)
32
- def reset!( now = false )
33
- close
34
- open if now
35
- end
36
-
37
- # Opens the logfile or connection (in case of a database adapter)
38
- def open
39
- open! unless opened?
40
- end
9
+ # Other adapters should include it for the base methods used
10
+ # by the {Yell::Logger}.
11
+ module Base
12
+
13
+ # The main method for calling the adapter.
14
+ #
15
+ # Adapter classes should provide their own implementation
16
+ # of this method.
17
+ def write( level, message )
18
+ nil
19
+ end
20
+
21
+ # Determine whether to write at the given severity.
22
+ #
23
+ # @example
24
+ # write? :error
25
+ #
26
+ # @param [String,Symbol,Integer] severity The severity to ask if to write or not.
27
+ #
28
+ # @return [Boolean] true or false
29
+ def write?( severity )
30
+ @level.nil? || @level.at?( severity )
31
+ end
32
+
33
+ # Close the adapter (stream, connection, etc).
34
+ #
35
+ # Adapter classes should provide their own implementation
36
+ # of this method.
37
+ def close
38
+ nil
39
+ end
40
+
41
+ # Set the log level.
42
+ #
43
+ # @example Set minimum level to :info
44
+ # level :info
45
+ #
46
+ # For more examples, refer to {Yell::Level}.
47
+ def level( severity = nil )
48
+ @level = Yell::Level.new( severity )
49
+ end
41
50
 
42
- # Closes the file handle or connection (in case of a database adapter)
43
- def close
44
- close! unless closed?
45
- end
46
-
47
-
48
- private
49
-
50
- def reset?; closed?; end
51
-
52
- # stub
53
- def open!
54
- raise "Not implemented"
55
- end
56
-
57
- def opened?; false; end
58
-
59
- # stub
60
- def close!
61
- raise "Not implemented"
62
- end
63
-
64
- def closed?; !opened?; end
65
-
66
- # stub
67
- def write
68
- raise 'Not implemented'
69
51
  end
70
52
 
71
53
  end
72
54
  end
55
+
@@ -1,38 +1,63 @@
1
- module Yell::Adapters
2
- class Datefile < Yell::Adapters::File
1
+ # encoding: utf-8
3
2
 
4
- DefaultDatePattern = "%Y%m%d"
3
+ module Yell #:nodoc:
4
+ module Adapters #:nodoc:
5
5
 
6
- def initialize ( options = {}, &block )
7
- @date_pattern = options[:date_pattern] || DefaultDatePattern
8
- @date = nil # default; do not override --R
6
+ # The +Datefile+ adapter is similar to the +File+ adapter. However, it
7
+ # rotates the file at midnight.
8
+ class Datefile < Yell::Adapters::File
9
9
 
10
- @file_basename = options[:filename] || default_filename
11
- options[:filename] = @file_basename
10
+ # The default date pattern, e.g. "19820114" (14 Jan 1982)
11
+ DefaultDatePattern = "%Y%m%d"
12
12
 
13
- super( options, &block )
14
- end
13
+ def initialize( options = {}, &block )
14
+ @date_pattern = options[:date_pattern] || DefaultDatePattern
15
15
 
16
- def reset!( now )
17
- @filename = new_filename
18
- super( now )
19
- end
16
+ @file_basename = options[:filename] || default_filename
17
+ options[:filename] = @file_basename
20
18
 
19
+ @date = nil # default; do not override --R
20
+
21
+ super( options, &block )
22
+ end
21
23
 
22
- private
24
+ def write( level, message )
25
+ close if close?
23
26
 
24
- def reset?
25
- _date = Time.now.strftime( @date_pattern )
26
- unless opened? && _date == @date
27
- @date = _date
28
- return true
27
+ super( level, message )
29
28
  end
30
29
 
31
- false
32
- end
30
+ # @override Reset the file handle
31
+ def close
32
+ @filename = new_filename
33
+
34
+ super
35
+ end
36
+
37
+
38
+ private
39
+
40
+ # Determines whether to close the file handle or not.
41
+ #
42
+ # It is based on the `:date_pattern` (can be passed as option upon initialize).
43
+ # If the current time hits the pattern, it closes the file stream.
44
+ #
45
+ # @return [Boolean] true or false
46
+ def close?
47
+ _date = Time.now.strftime( @date_pattern )
48
+ if !@stream or _date != @date
49
+ @date = _date
50
+ return true
51
+ end
52
+
53
+ false
54
+ end
55
+
56
+ # Sets the filename with the `:date_pattern` appended to it.
57
+ def new_filename
58
+ @file_basename.sub( /(\.\w+)?$/, ".#{@date}\\1" )
59
+ end
33
60
 
34
- def new_filename
35
- @file_basename.sub( /(\.\w+)?$/, ".#{@date}\\1" )
36
61
  end
37
62
 
38
63
  end
@@ -1,95 +1,32 @@
1
- module Yell::Adapters
2
- class File < Yell::Adapters::Base
1
+ # encoding: utf-8
3
2
 
4
- Colors = {
5
- 'DEBUG' => "\e[32;1m", # green;bold
6
- # 'INFO' => "\e[0m", # white
7
- 'WARN' => "\e[33;1m", # yello;bold
8
- 'ERROR' => "\e[31;1m", # red;bold
9
- 'FATAL' => "\e[35;1m", # magenta;bold
10
- 'UNKNOWN' => "\e[36m", # cyan
11
- 'DEFAULT' => "\e[0m" # NONE
12
- }
3
+ module Yell #:nodoc:
4
+ module Adapters #:nodoc:
13
5
 
14
- def initialize ( options = {}, &block )
15
- super
6
+ # The +File+ adapter is the most basic. As one would expect, it's used
7
+ # for logging into files.
8
+ class File < Yell::Adapters::Io
16
9
 
17
- @formatter = formatter_from( options )
10
+ def initialize( options = {}, &block )
11
+ super( nil, options, &block )
18
12
 
19
- @colorize = options[:colorize]
20
- @filename = options[:filename] || default_filename
21
-
22
- @file_prefix, @file_suffix = options[:file_prefix], options[:file_suffix]
23
-
24
- # validate the filename
25
- unless @filename.is_a?( String )
26
- raise( TypeError, "Argument :filename must be a string." )
13
+ @filename = options.fetch(:filename, default_filename)
27
14
  end
28
- end
29
-
30
- def call ( level, msg )
31
- super # Base call
32
-
33
- msg = @formatter.format( @level, message )
34
- msg = colorize( @level, msg ) if @colorize
35
- msg << "\n" unless msg[-1] == ?\n # add new line if there is none
36
15
 
37
- write( msg )
38
- end
39
-
40
-
41
- private
42
-
43
- def write ( msg )
44
- @file.print( msg )
45
- @file.flush
46
- rescue Exception => e
47
- close # make sure the file gets closed
48
- raise( e ) # re-raise the error
49
- end
50
-
51
- def close!
52
- @file.close
53
- @file = nil
54
- end
55
-
56
- def open!
57
- # create directory if not exists
58
- dirname = ::File.dirname( @filename )
59
- FileUtils.mkdir_p( dirname ) unless ::File.directory?( dirname )
16
+ # @override Lazily open the file handle
17
+ def stream
18
+ @stream ||= ::File.open( @filename, ::File::WRONLY|::File::APPEND|::File::CREAT )
19
+ end
60
20
 
61
- # open file for appending if exists, or create a new
62
- filename = [ dirname, "#{@file_prefix}#{::File.basename(@filename)}#{@file_suffix}" ].join( '/' )
63
- @file = ::File.open( filename, ::File::WRONLY|::File::APPEND|::File::CREAT )
64
- end
65
21
 
66
- def opened?; !@file.nil?; end
22
+ private
67
23
 
68
- # Returns the right formatter from the given options
69
- def formatter_from( options )
70
- if options.key?(:formatter)
71
- # this is done, so we can set :formatter => false to just output the given message
72
- options[:formatter] || Yell::Formatter.new( "%m" )
73
- elsif options[:formatter]
74
- # the options :formatter was given
75
- Yell::Formatter.new(
76
- options[:formatter][:pattern],
77
- options[:formatter][:date_pattern]
78
- )
79
- else
80
- # Standard formatter
81
- Yell::Formatter.new
24
+ def default_filename
25
+ ::File.directory?("log") ? "log/#{Yell.env}.log" : "#{Yell.env}.log"
82
26
  end
83
- end
84
-
85
- def colorize( level, msg )
86
- return msg unless color = Colors[level.upcase]
87
- color + msg + Colors['DEFAULT']
88
- end
89
27
 
90
- def default_filename
91
- "#{Yell.config.env}.log"
92
28
  end
93
29
 
94
30
  end
95
31
  end
32
+
@@ -0,0 +1,89 @@
1
+ module Yell
2
+ module Adapters
3
+
4
+ class Io
5
+ include Yell::Adapters::Base
6
+
7
+ # The possible unix log colors
8
+ Colors = {
9
+ 'DEBUG' => "\e[32;1m", # green;bold
10
+ # 'INFO' => "\e[0m", # white
11
+ 'WARN' => "\e[33;1m", # yello;bold
12
+ 'ERROR' => "\e[31;1m", # red;bold
13
+ 'FATAL' => "\e[35;1m", # magenta;bold
14
+ 'UNKNOWN' => "\e[36m", # cyan
15
+ 'DEFAULT' => "\e[0m" # NONE
16
+ }
17
+
18
+ # Accessor to the io stream
19
+ attr_reader :stream
20
+
21
+
22
+ def initialize( stream, options = {}, &block )
23
+ @stream = stream
24
+ @options = options
25
+
26
+ level options.fetch(:level, nil)
27
+ format options.fetch(:format, nil)
28
+ colorize! options.fetch(:colorize, false)
29
+
30
+ instance_eval &block if block
31
+ end
32
+
33
+ # Main method to calling the file adapter.
34
+ #
35
+ # The method formats the message and writes it to the file handle.
36
+ #
37
+ # @example
38
+ # write( 'info', 'Hello World' )
39
+ def write( level, message )
40
+ msg = @formatter.format( level, message )
41
+
42
+ # colorize if applicable
43
+ if colorize? and color = Colors[level]
44
+ msg = color + msg + Colors['DEFAULT']
45
+ end
46
+
47
+ msg << "\n" unless msg[-1] == ?\n # add new line if there is none
48
+
49
+ write!( msg )
50
+ end
51
+
52
+ # Set the format for your message.
53
+ def format( pattern, date_pattern = nil )
54
+ @formatter = case pattern
55
+ when Yell::Formatter then pattern
56
+ when false then Yell::Formatter.new( "%m" )
57
+ else Yell::Formatter.new( pattern, date_pattern )
58
+ end
59
+ end
60
+
61
+ # Enable colorizing the log output.
62
+ def colorize!( color = true )
63
+ @colorize = color
64
+ end
65
+
66
+ # Determie whether to colorize the log output or nor
67
+ #
68
+ # @return [Boolean] true or false
69
+ def colorize?; !!@colorize; end
70
+
71
+
72
+ private
73
+
74
+ # TODO: Implement Buffer to not flush immediately.
75
+ def write!( message )
76
+ stream.print( message )
77
+ stream.flush
78
+ rescue => e
79
+ close
80
+
81
+ # re-raise the exception
82
+ raise( e, caller )
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+ end
89
+
@@ -1,37 +1,39 @@
1
- module Yell
1
+ # encoding: utf-8
2
+
3
+ module Yell #:nodoc:
4
+
5
+ # The +Formatter+ provides a handle to configure your log message style.
2
6
  class Formatter
3
7
 
4
8
  PatternTable = {
5
- "m" => "message",
9
+ "m" => "message",
6
10
  "d" => "date",
7
- "l" => "level.downcase",
11
+ "l" => "level[0]",
8
12
  "L" => "level.upcase",
9
- "p" => "$$", # pid
13
+ "p" => "$$",
10
14
  "h" => "hostname"
11
15
  }
12
16
  PatternRegexp = /([^%]*)(%\d*)?([dlLphm])?(.*)/
13
-
14
17
  DefaultPattern = "%d [%5L] %p %h: %m"
15
- DefaultDatePattern = "%Y-%m-%d %H:%M:%S" # ISO8601
16
-
17
-
18
- def initialize ( pattern = nil, date_pattern = nil )
19
- @pattern = pattern || DefaultPattern
20
- @date_pattern = date_pattern || DefaultDatePattern
21
-
22
- define_format_method
18
+
19
+
20
+ def initialize( pattern = nil, date_pattern = nil )
21
+ @pattern = pattern || DefaultPattern
22
+ @date_pattern = date_pattern
23
+
24
+ define!
23
25
  end
24
-
26
+
25
27
 
26
28
  private
27
29
 
28
- def define_format_method
30
+ def define!
29
31
  buff, args, _pattern = "", [], @pattern.dup
30
-
32
+
31
33
  while true
32
34
  match = PatternRegexp.match( _pattern )
33
35
 
34
- buff << match[1] unless match[1].empty?
36
+ buff << match[1] unless match[1].empty?
35
37
  break if match[2].nil?
36
38
 
37
39
  buff << match[2] + 's' # '%s'
@@ -41,18 +43,21 @@ module Yell
41
43
  end
42
44
 
43
45
  instance_eval %-
44
- def format ( level, message )
46
+ def format( level, message )
45
47
  sprintf( "#{buff}", #{args.join(',')} )
46
48
  end
47
49
  -
48
50
  end
49
51
 
50
- def date; Time.now.strftime( @date_pattern ); end
51
-
52
+ def date
53
+ @date_pattern ? Time.now.strftime( @date_pattern ) : Time.now.iso8601
54
+ end
55
+
52
56
  def hostname
53
57
  return @hostname if defined?( @hostname )
54
58
  @hostname = Socket.gethostname rescue nil
55
59
  end
56
60
 
57
61
  end
58
- end
62
+ end
63
+
data/lib/yell/level.rb ADDED
@@ -0,0 +1,139 @@
1
+ # encoding: utf-8
2
+
3
+ module Yell #:nodoc:
4
+
5
+ # The +Level+ class handles the severities for you in order to determine
6
+ # if an adapter should log or not.
7
+ #
8
+ # In order to setup your level, you have certain modifiers available:
9
+ # at :warn # will be set to :warn level only
10
+ # gt :warn # Will set from :error level onwards
11
+ # gte :warn # Will set from :warn level onwards
12
+ # lt :warn # Will set from :info level an below
13
+ # lte :warn # Will set from :warn level and below
14
+ #
15
+ #
16
+ # You are able to combine those modifiers to your convenience.
17
+ #
18
+ # @example Set from :info to :error (including)
19
+ # Yell::Level.new(:info).lte(:error)
20
+ #
21
+ # @example Set from :info to :error (excluding)
22
+ # Yell::Level.new(:info).lt(:error)
23
+ #
24
+ # @example Set at :info only
25
+ # Yell::Level.new.at(:info)
26
+ class Level
27
+
28
+ # Create a new level instance.
29
+ #
30
+ # @example Enable all severities
31
+ # Yell::Level.new
32
+ #
33
+ # @example Pass the minimum possible severity
34
+ # Yell::Level.new :warn
35
+ #
36
+ # @example Pass an array to exactly set the level at the given severities
37
+ # Yell::Level.new [:info, :error]
38
+ #
39
+ # @example Pass a range to set the level within the severities
40
+ # Yell::Level.new (:info..:error)
41
+ #
42
+ # @param [Integer,String,Symbol,Array,Range,nil] severity The severity for the level.
43
+ def initialize( severity = nil )
44
+ @severities = Yell::Severities.map { true } # all levels allowed by default
45
+
46
+ case severity
47
+ when Array then severity.each { |s| at(s) }
48
+ when Range then gte(severity.first).lte(severity.last)
49
+ when Integer, String, Symbol then gte(severity)
50
+ end
51
+ end
52
+
53
+ # Returns whether the level is allowed at the given severity
54
+ #
55
+ # @example
56
+ # at? :warn
57
+ # at? 0 # debug
58
+ def at?( severity )
59
+ index = index_from( severity )
60
+
61
+ index.nil? ? false : @severities[index]
62
+ end
63
+
64
+ def at( severity ) #:nodoc:
65
+ calculate! :==, severity
66
+ self
67
+ end
68
+
69
+ def gt( severity ) #:nodoc:
70
+ calculate! :>, severity
71
+ self
72
+ end
73
+
74
+ def gte( severity ) #:nodoc:
75
+ calculate! :>=, severity
76
+ self
77
+ end
78
+
79
+ def lt( severity ) #:nodoc:
80
+ calculate! :<, severity
81
+ self
82
+ end
83
+
84
+ def lte( severity ) #:nodoc:
85
+ calculate! :<=, severity
86
+ self
87
+ end
88
+
89
+
90
+ private
91
+
92
+ def calculate!( modifier, severity )
93
+ index = index_from( severity )
94
+ return if index.nil?
95
+
96
+ case modifier
97
+ when :> then ascending!( index+1 )
98
+ when :>= then ascending!( index )
99
+ when :< then descending!( index-1 )
100
+ when :<= then descending!( index )
101
+ else set!( index ) # :==
102
+ end
103
+
104
+ taint unless tainted?
105
+ end
106
+
107
+ def index_from( severity )
108
+ case severity
109
+ when Integer then severity
110
+ when String, Symbol then Yell::Severities.index( severity.to_s.upcase )
111
+ else nil
112
+ end
113
+ end
114
+
115
+ def ascending!( index )
116
+ @severities.each_with_index do |s, i|
117
+ next if s == false # skip
118
+
119
+ @severities[i] = i < index ? false : true
120
+ end
121
+ end
122
+
123
+ def descending!( index )
124
+ @severities.each_with_index do |s, i|
125
+ next if s == false # skip
126
+
127
+ @severities[i] = index < i ? false : true
128
+ end
129
+ end
130
+
131
+ def set!( index )
132
+ @severities.map! { false } unless tainted?
133
+
134
+ @severities[index] = true
135
+ end
136
+
137
+ end
138
+
139
+ end
data/lib/yell/logger.rb CHANGED
@@ -1,82 +1,145 @@
1
- module Yell
2
- class Logger
3
- Levels = [ 'debug', 'info', 'warn', 'error', 'fatal', 'unknown' ]
1
+ # encoding: utf-8
4
2
 
3
+ module Yell #:nodoc:
5
4
 
5
+ # The +Logger+ is your entrypoint. Anything onwards is derived from here.
6
+ class Logger
7
+ # Creates a new Logger instance
8
+ #
9
+ # @example A standard file logger
10
+ # Yell::Logger.new
11
+ # Yell::Logger.new 'development.log'
12
+ #
13
+ # @example A standard datefile logger
14
+ # Yell::Logger.new :datefile
15
+ # Yell::Logger.new :datefile, 'development.log'
16
+ #
17
+ # @example Setting the log level
18
+ # Yell::Logger.new :level => :warn
19
+ #
20
+ # Yell::Logger.new do
21
+ # level :warn
22
+ # end
23
+ #
24
+ # @example Combined settings
25
+ # Yell::Logger.new 'development.log', :level => :warn
26
+ #
27
+ # Yell::Logger.new :datefile, 'development.log' do
28
+ # level :info
29
+ # end
6
30
  def initialize( *args, &block )
7
31
  @adapters = []
8
32
 
9
33
  # extract options
10
34
  @options = args.last.is_a?(Hash) ? args.pop : {}
11
35
 
36
+ # set the log level when given
37
+ # level @options[:level] if @options[:level]
38
+ level @options[:level] # default
39
+
12
40
  # check if filename was given as argument and put it into the @options
13
41
  if args.last.is_a?( String )
14
42
  @options[:filename] = args.pop unless @options[:filename]
15
43
  end
16
44
 
17
- @default_adapter = args.last.is_a?( Symbol ) ? args.pop : :file
45
+ # extract adapter
46
+ adapter args.pop if args.any?
18
47
 
19
- # eval the given block if any
20
- instance_eval( &block ) if block
48
+ # set the log level when given
49
+ level @options[:level] if @options[:level]
21
50
 
22
- build
23
- end
51
+ # eval the given block
52
+ instance_eval &block if block
24
53
 
25
- # === the following methods are used for the logger setup
26
- def adapter ( type, options = {}, &block )
27
- @adapters << Yell::Adapters.new( type, @options.merge(options), &block )
28
- rescue LoadError => e
29
- raise Yell::NoSuchAdapter, e.message
54
+ define!
30
55
  end
31
56
 
32
- def level ( val )
33
- @level = case val
34
- when Integer then val
35
- when String, Symbol then Levels.index( val.to_s )
36
- else nil
57
+ # Define an adapter to be used for logging.
58
+ #
59
+ # @example Standard adapter
60
+ # adapter :file
61
+ #
62
+ # @example Standard adapter with filename
63
+ # adapter :file, 'development.log'
64
+ #
65
+ # # Alternative notation for filename in options
66
+ # adapter :file, :filename => 'developent.log'
67
+ #
68
+ # @example Standard adapter with filename and additional options
69
+ # adapter :file, 'development.log', :level => :warn
70
+ #
71
+ # @example Set the adapter directly from an adapter instance
72
+ # adapter( Yell::Adapter::File.new )
73
+ #
74
+ # @param [Symbol] type The type of the adapter, may be `:file` or `:datefile` (default `:file`)
75
+ #
76
+ # @return A new +Yell::Adapter+ instance
77
+ #
78
+ # @raise [Yell::NoSuchAdapter] Will be thrown when the adapter is not defined
79
+ def adapter( type = :file, *args, &block )
80
+ options = [@options, *args].inject( Hash.new ) do |h,c|
81
+ h.merge( c.is_a?(String) ? {:filename => c} : c )
37
82
  end
83
+
84
+ @adapters << Yell::Adapters[ type, options, &block ]
85
+ rescue NameError => e
86
+ raise Yell::NoSuchAdapter, type
87
+ end
88
+
89
+ # Set the minimum log level.
90
+ #
91
+ # @example Set the level to :warn
92
+ # level :warn
93
+ #
94
+ # @param [String, Symbol, Integer] val The minimum log level
95
+ def level( val = nil )
96
+ @level = Yell::Level.new( val )
38
97
  end
39
98
 
40
99
  # Convenience method for resetting all adapters of the Logger.
41
100
  #
42
- # @param [true, false] now Perform the reset immediately? (default false)
43
- def reset!( now = false )
44
- close
45
- open if now
101
+ # @param [Boolean] now Perform the reset immediately (default false)
102
+ def close( now = false )
103
+ @adapters.each(&:close)
46
104
  end
47
105
 
48
- def close; @adapters.each(&:close); end
49
- def open; @adapters.each(&:open); end
50
106
 
51
-
52
107
  private
53
108
 
54
- def build
55
- adapter @default_adapter if @adapters.empty? # default adapter when none defined
109
+ # Sets a default adapter if none was given explicitly and defines the log methods on
110
+ # the logger instance.
111
+ def define!
112
+ adapter :file if @adapters.empty? # default adapter when none defined
56
113
 
57
- define_log_methods
114
+ define_log_methods!
58
115
  end
59
116
 
60
- def define_log_methods
61
- Levels.each_with_index do |name, index|
62
- instance_eval %-
63
- def #{name}?; #{@level.nil? || index >= @level}; end
64
-
65
- def #{name} ( data = '' )
66
- return unless #{name}?
117
+ # Creates instance methods for every defined log level (debug, info, ...) depending
118
+ # on whether anything should be logged upon, for instance, #info.
119
+ def define_log_methods!
120
+ Yell::Severities.each do |l|
121
+ name = l.downcase
67
122
 
68
- data = yield if block_given?
69
- process( "#{name}", data )
70
-
71
- data
72
- end
123
+ instance_eval %-
124
+ def #{name}?; #{@level.at?(name)}; end # def info?; true; end
125
+ #
126
+ def #{name}( message = nil ) # def info( message = nil )
127
+ return unless #{name}? # return unless info?
128
+ #
129
+ message = yield if block_given? # message = yield if block_given?
130
+ write( "#{l}", message ) # write( "INFO", message )
131
+ #
132
+ true # true
133
+ end # end
73
134
  -
74
135
  end
75
136
  end
76
137
 
77
- def process ( level, data )
78
- @adapters.each { |a| a.call( level, data ) }
138
+ # Cycles all the adapters and writes the message
139
+ def write( level, message )
140
+ @adapters.each { |a| a.write(level, message) if a.write?(level) }
79
141
  end
80
142
 
81
143
  end
82
144
  end
145
+
data/lib/yell/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Yell
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
 
4
4
  end
data/spec/spec_helper.rb CHANGED
@@ -7,14 +7,5 @@ require 'rspec'
7
7
  require 'timecop'
8
8
 
9
9
  RSpec.configure do |config|
10
-
11
- config.before do
12
- Yell.config.stub!( :yaml_file ).and_return( File.dirname(__FILE__) + '/config/yell.yml' )
13
- end
14
-
15
- config.after do
16
- Yell.config.reload! # to not run into caching problems during tests
17
- end
18
-
19
10
  end
20
11
 
data/spec/yell_spec.rb CHANGED
@@ -15,3 +15,4 @@ describe Yell do
15
15
  end
16
16
 
17
17
  end
18
+
data/yell.gemspec CHANGED
@@ -9,10 +9,10 @@ Gem::Specification.new do |s|
9
9
  s.authors = ["Rudolf Schmidt"]
10
10
 
11
11
  s.homepage = "http://rubygems.org/gems/yell"
12
- s.summary = %q{Logging library to log into files and databases}
13
- s.description = %q{Logging library to log into files and databases}
12
+ s.summary = %q{Yell - Your Extensible Logging Library }
13
+ s.description = %q{An easy to use logging library to log into files and any other self-defined adapters}
14
14
 
15
- s.rubyforge_project = "d_log"
15
+ s.rubyforge_project = "yell"
16
16
 
17
17
  s.files = `git ls-files`.split("\n")
18
18
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yell
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,9 +9,10 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-23 00:00:00.000000000Z
12
+ date: 2012-03-17 00:00:00.000000000 Z
13
13
  dependencies: []
14
- description: Logging library to log into files and databases
14
+ description: An easy to use logging library to log into files and any other self-defined
15
+ adapters
15
16
  email:
16
17
  executables: []
17
18
  extensions: []
@@ -19,15 +20,19 @@ extra_rdoc_files: []
19
20
  files:
20
21
  - .gitignore
21
22
  - Gemfile
23
+ - LICENSE.txt
24
+ - README.md
22
25
  - Rakefile
23
26
  - init.rb
24
27
  - lib/yell.rb
25
28
  - lib/yell/adapters.rb
29
+ - lib/yell/adapters/.file.rb.swp
26
30
  - lib/yell/adapters/base.rb
27
31
  - lib/yell/adapters/datefile.rb
28
32
  - lib/yell/adapters/file.rb
29
- - lib/yell/config.rb
33
+ - lib/yell/adapters/io.rb
30
34
  - lib/yell/formatter.rb
35
+ - lib/yell/level.rb
31
36
  - lib/yell/logger.rb
32
37
  - lib/yell/version.rb
33
38
  - spec/spec.opts
@@ -53,9 +58,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
53
58
  - !ruby/object:Gem::Version
54
59
  version: '0'
55
60
  requirements: []
56
- rubyforge_project: d_log
57
- rubygems_version: 1.8.10
61
+ rubyforge_project: yell
62
+ rubygems_version: 1.8.17
58
63
  signing_key:
59
64
  specification_version: 3
60
- summary: Logging library to log into files and databases
61
- test_files: []
65
+ summary: Yell - Your Extensible Logging Library
66
+ test_files:
67
+ - spec/spec.opts
68
+ - spec/spec_helper.rb
69
+ - spec/yell_spec.rb
data/lib/yell/config.rb DELETED
@@ -1,53 +0,0 @@
1
- module Yell
2
- class Config
3
-
4
- def initialize( yaml_file = nil )
5
- @yaml_file = yaml_file
6
-
7
- reload!
8
- end
9
-
10
- def reload!; @options = nil; end
11
-
12
- def []( key ); options[key]; end
13
-
14
- def options
15
- @options ||= begin
16
- if yaml_file_defined?
17
- require 'yaml'
18
- require 'erb'
19
-
20
- (YAML.load( ERB.new( File.read( yaml_file ) ).result ) || {})[ env ] || {}
21
- else
22
- {} # default
23
- end
24
- end
25
- end
26
-
27
- def env
28
- ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'default'
29
- end
30
-
31
- def root
32
- return ENV['RAILS_ROOT'] if ENV['RAILS_ROOT']
33
- return RAILS_ROOT if defined?( RAILS_ROOT )
34
-
35
- '.'
36
- end
37
-
38
-
39
- private
40
-
41
- def yaml_file_defined?
42
- yaml_file && File.exist?( yaml_file )
43
- end
44
-
45
- # Locates the yell.yml file. The file can end in .yml or .yaml,
46
- # and be located in the current directory (eg. project root) or
47
- # in a .config/ or config/ subdirectory of the current directory.
48
- def yaml_file
49
- @yaml_file || Dir.glob( "#{root}/{,.config/,config/}yell{.yml,.yaml}" ).first
50
- end
51
-
52
- end
53
- end