yell 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/Gemfile +12 -0
- data/Rakefile +26 -0
- data/init.rb +1 -0
- data/lib/yell/adapters/base.rb +72 -0
- data/lib/yell/adapters/datefile.rb +39 -0
- data/lib/yell/adapters/file.rb +95 -0
- data/lib/yell/adapters.rb +19 -0
- data/lib/yell/config.rb +53 -0
- data/lib/yell/formatter.rb +58 -0
- data/lib/yell/logger.rb +82 -0
- data/lib/yell/version.rb +4 -0
- data/lib/yell.rb +21 -0
- data/yell.gemspec +21 -0
- metadata +58 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
$LOAD_PATH.unshift( 'lib' )
|
2
|
+
|
3
|
+
require 'bundler'
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
|
6
|
+
# === RSpec
|
7
|
+
require 'rspec/core/rake_task'
|
8
|
+
|
9
|
+
desc "Run specs"
|
10
|
+
RSpec::Core::RakeTask.new do |t|
|
11
|
+
t.rspec_opts = %w(-fs --color)
|
12
|
+
end
|
13
|
+
|
14
|
+
task :default => :spec
|
15
|
+
|
16
|
+
|
17
|
+
# === Rdoc
|
18
|
+
require 'rake/rdoctask'
|
19
|
+
Rake::RDocTask.new do |rdoc|
|
20
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
21
|
+
|
22
|
+
rdoc.rdoc_dir = 'rdoc'
|
23
|
+
rdoc.title = "inventory #{version}"
|
24
|
+
rdoc.rdoc_files.include('README*')
|
25
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
26
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'yell'
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Yell::Adapters
|
2
|
+
class Base
|
3
|
+
|
4
|
+
attr_reader :name # name of the logger this adapter belongs to
|
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.
|
30
|
+
#
|
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
|
41
|
+
|
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
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Yell::Adapters
|
2
|
+
class Datefile < Yell::Adapters::File
|
3
|
+
|
4
|
+
DefaultDatePattern = "%Y%m%d"
|
5
|
+
|
6
|
+
def initialize ( options = {}, &block )
|
7
|
+
@date_pattern = options[:date_pattern] || DefaultDatePattern
|
8
|
+
@date = nil # default; do not override --R
|
9
|
+
|
10
|
+
@file_basename = options[:filename] || default_filename
|
11
|
+
options[:filename] = @file_basename
|
12
|
+
|
13
|
+
super( options, &block )
|
14
|
+
end
|
15
|
+
|
16
|
+
def reset!( now )
|
17
|
+
@filename = new_filename
|
18
|
+
super( now )
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def reset?
|
25
|
+
_date = Time.now.strftime( @date_pattern )
|
26
|
+
unless opened? && _date == @date
|
27
|
+
@date = _date
|
28
|
+
return true
|
29
|
+
end
|
30
|
+
|
31
|
+
false
|
32
|
+
end
|
33
|
+
|
34
|
+
def new_filename
|
35
|
+
@file_basename.sub( /(\.\w+)?$/, ".#{@date}\\1" )
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Yell::Adapters
|
2
|
+
class File < Yell::Adapters::Base
|
3
|
+
|
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
|
+
}
|
13
|
+
|
14
|
+
def initialize ( options = {}, &block )
|
15
|
+
super
|
16
|
+
|
17
|
+
@formatter = formatter_from( options )
|
18
|
+
|
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." )
|
27
|
+
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
|
+
|
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 )
|
60
|
+
|
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
|
+
|
66
|
+
def opened?; !@file.nil?; end
|
67
|
+
|
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
|
82
|
+
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
|
+
|
90
|
+
def default_filename
|
91
|
+
"#{Yell.config.env}.log"
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Yell
|
2
|
+
module Adapters
|
3
|
+
|
4
|
+
Dir[ ::File.dirname(__FILE__) + '/adapters/*.rb' ].each do |file|
|
5
|
+
autoload ::File.basename(file, '.rb').capitalize, file
|
6
|
+
end
|
7
|
+
|
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
|
13
|
+
end
|
14
|
+
|
15
|
+
klass.new( options, &block )
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/lib/yell/config.rb
ADDED
@@ -0,0 +1,53 @@
|
|
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
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Yell
|
2
|
+
class Formatter
|
3
|
+
|
4
|
+
PatternTable = {
|
5
|
+
"m" => "message",
|
6
|
+
"d" => "date",
|
7
|
+
"l" => "level.downcase",
|
8
|
+
"L" => "level.upcase",
|
9
|
+
"p" => "$$", # pid
|
10
|
+
"h" => "hostname"
|
11
|
+
}
|
12
|
+
PatternRegexp = /([^%]*)(%\d*)?([dlLphm])?(.*)/
|
13
|
+
|
14
|
+
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
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def define_format_method
|
29
|
+
buff, args, _pattern = "", [], @pattern.dup
|
30
|
+
|
31
|
+
while true
|
32
|
+
match = PatternRegexp.match( _pattern )
|
33
|
+
|
34
|
+
buff << match[1] unless match[1].empty?
|
35
|
+
break if match[2].nil?
|
36
|
+
|
37
|
+
buff << match[2] + 's' # '%s'
|
38
|
+
args << PatternTable[ match[3] ]
|
39
|
+
|
40
|
+
_pattern = match[4]
|
41
|
+
end
|
42
|
+
|
43
|
+
instance_eval %-
|
44
|
+
def format ( level, message )
|
45
|
+
sprintf( "#{buff}", #{args.join(',')} )
|
46
|
+
end
|
47
|
+
-
|
48
|
+
end
|
49
|
+
|
50
|
+
def date; Time.now.strftime( @date_pattern ); end
|
51
|
+
|
52
|
+
def hostname
|
53
|
+
return @hostname if defined?( @hostname )
|
54
|
+
@hostname = Socket.gethostname rescue nil
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
data/lib/yell/logger.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
module Yell
|
2
|
+
class Logger
|
3
|
+
Levels = [ 'debug', 'info', 'warn', 'error', 'fatal', 'unknown' ]
|
4
|
+
|
5
|
+
|
6
|
+
def initialize( *args, &block )
|
7
|
+
@adapters = []
|
8
|
+
|
9
|
+
# extract options
|
10
|
+
@options = args.last.is_a?(Hash) ? args.pop : {}
|
11
|
+
|
12
|
+
# check if filename was given as argument and put it into the @options
|
13
|
+
if args.last.is_a?( String )
|
14
|
+
@options[:filename] = args.pop unless @options[:filename]
|
15
|
+
end
|
16
|
+
|
17
|
+
@default_adapter = args.last.is_a?( Symbol ) ? args.pop : :file
|
18
|
+
|
19
|
+
# eval the given block if any
|
20
|
+
instance_eval( &block ) if block
|
21
|
+
|
22
|
+
build
|
23
|
+
end
|
24
|
+
|
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
|
+
|
30
|
+
end
|
31
|
+
|
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
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Convenience method for resetting all adapters of the Logger.
|
41
|
+
#
|
42
|
+
# @param [true, false] now Perform the reset immediately? (default false)
|
43
|
+
def reset!( now = false )
|
44
|
+
close
|
45
|
+
open if now
|
46
|
+
end
|
47
|
+
|
48
|
+
def close; @adapters.each(&:close); end
|
49
|
+
def open; @adapters.each(&:open); end
|
50
|
+
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def build
|
55
|
+
adapter @default_adapter if @adapters.empty? # default adapter when none defined
|
56
|
+
|
57
|
+
define_log_methods
|
58
|
+
end
|
59
|
+
|
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}?
|
67
|
+
|
68
|
+
data = yield if block_given?
|
69
|
+
process( "#{name}", data )
|
70
|
+
|
71
|
+
data
|
72
|
+
end
|
73
|
+
-
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def process ( level, data )
|
78
|
+
@adapters.each { |a| a.call( level, data ) }
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
data/lib/yell/version.rb
ADDED
data/lib/yell.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Yell
|
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'
|
7
|
+
|
8
|
+
# custom errors
|
9
|
+
class NoAdaptersDefined < StandardError; end
|
10
|
+
class NoSuchAdapter < StandardError; end
|
11
|
+
|
12
|
+
|
13
|
+
def self.new( *args, &block )
|
14
|
+
Yell::Logger.new( *args, &block )
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.config
|
18
|
+
@@config ||= Yell::Config.new
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/yell.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "yell/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "yell"
|
7
|
+
s.version = Yell::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Rudolf Schmidt"]
|
10
|
+
|
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}
|
14
|
+
|
15
|
+
s.rubyforge_project = "d_log"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yell
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Rudolf Schmidt
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-23 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description: Logging library to log into files and databases
|
15
|
+
email:
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- .gitignore
|
21
|
+
- Gemfile
|
22
|
+
- Rakefile
|
23
|
+
- init.rb
|
24
|
+
- lib/yell.rb
|
25
|
+
- lib/yell/adapters.rb
|
26
|
+
- lib/yell/adapters/base.rb
|
27
|
+
- lib/yell/adapters/datefile.rb
|
28
|
+
- lib/yell/adapters/file.rb
|
29
|
+
- lib/yell/config.rb
|
30
|
+
- lib/yell/formatter.rb
|
31
|
+
- lib/yell/logger.rb
|
32
|
+
- lib/yell/version.rb
|
33
|
+
- yell.gemspec
|
34
|
+
homepage: http://rubygems.org/gems/yell
|
35
|
+
licenses: []
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubyforge_project: d_log
|
54
|
+
rubygems_version: 1.8.10
|
55
|
+
signing_key:
|
56
|
+
specification_version: 3
|
57
|
+
summary: Logging library to log into files and databases
|
58
|
+
test_files: []
|