unilogger 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ log/
5
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in unilogger.gemspec
4
+ gemspec
data/README ADDED
@@ -0,0 +1,49 @@
1
+ Unified logger that writes to a log file.
2
+ Could eventually also write to a redis queue, mongo collection, and hoptoad.
3
+
4
+ Unilogger is composed at runtime of a Logger instance which delegates log messages to a set of emitters.
5
+ The emitters do the actual work of sending log messages to stderr, a file, redis, or elsewhere.
6
+
7
+ Unilogger will initialize itself from a logger.yml or logger.yml.erb configuration file, if present.
8
+
9
+ The configuration file should contain an entry named after the current environment, e.g.
10
+ "development", "test", "production", etc.
11
+
12
+ Logger options
13
+ --------------
14
+ level: overall level; messages of severity less than this will not be emitted regardless of the level of the emitter.
15
+ emitters: a list of emitters.
16
+
17
+ Standard (log file) emitter
18
+ ---------------------------
19
+ kind: LogFileEmitter
20
+ logdev: "stderr", "stdout", or a filename
21
+ shift_age: "daily", "weekly" or "monthly" to rotate based on the calendar
22
+ if rotating based on file size, number of files to keep
23
+ default 7
24
+ shift_size: a file size, to rotate based on the file size
25
+ default 1048576
26
+
27
+ Redis emitter
28
+ -------------
29
+ kind: RedisEmitter
30
+
31
+
32
+ Example logger.yml
33
+ ------------------
34
+ stderr: &stderr
35
+ logger:
36
+ logdev: stderr
37
+
38
+ standard: &standard
39
+ logger:
40
+ logdev: "<%= ENV["RACK_ENV"] || "development" %>.log"
41
+ shift_age: daily
42
+
43
+ development:
44
+ level: 0
45
+ emitters: [ *standard ]
46
+
47
+ test:
48
+ level: 1
49
+ emitters: [ *stderr ]
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,13 @@
1
+ require "unilogger/builder"
2
+ require "unilogger/log_file_emitter"
3
+ require "unilogger/logger"
4
+
5
+ module Unilogger
6
+
7
+ class << self
8
+ def build( options )
9
+ Builder.build( options )
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,63 @@
1
+ require "erb"
2
+ require "unilogger/logger"
3
+ require "yaml"
4
+
5
+ module Unilogger
6
+ class Builder
7
+
8
+ class << self
9
+
10
+ # options must include
11
+ # env => "development", "test", "production", etc.
12
+ # root => parent of config and log directories
13
+ def build( options )
14
+ env = options[:env] || ENV["RACK_ENV"] || ENV["RAILS_ENV"] || "development"
15
+ root = options[:root]
16
+
17
+ if File.exist?( yml = "#{root}/config/logger.yml" ) then
18
+ cfg = YAML.load(IO.read( yml )) [env]
19
+ elsif File.exist?( yml = "#{root}/config/logger.yml.erb" )
20
+ cfg = YAML.load( (ERB.new( IO.read( yml ) ).result) ) [env]
21
+ else
22
+ cfg = { "level" => "debug", "emitters" => [ { "logger" => { "logdev" => "stderr" } } ] }
23
+ end
24
+
25
+ Unilogger::Builder.new( cfg ).logger
26
+ end
27
+
28
+ def as_level( level, default_level = ::Logger::Severity::INFO )
29
+ return default_level if level.nil? || level.size == 0
30
+ return level if level.kind_of?(Integer)
31
+ ::Logger::Severity.const_get( level.to_s.upcase )
32
+ end
33
+
34
+ def as_factory( kind )
35
+ kind = "LogFileEmitter" if kind =~ /^logger$/i
36
+ factory = Unilogger.const_get(kind) rescue Object.const_get(kind) rescue nil
37
+ raise "unknown kind of emitter (#{kind})" if ! factory
38
+ return factory
39
+ end
40
+
41
+ end # class
42
+
43
+ def initialize( configuration )
44
+ @configuration = configuration
45
+ end
46
+
47
+ def logger
48
+ # accept debug...fatal, 0...4, default info
49
+ level = self.class.as_level( @configuration["level"] )
50
+
51
+ # emitters
52
+ emitters = @configuration["emitters"].map do |options|
53
+ options = options.first
54
+ kind = options.first
55
+ factory = self.class.as_factory( kind )
56
+ factory.build( options.last )
57
+ end
58
+
59
+ Logger.new( level, emitters )
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,41 @@
1
+ require "logger"
2
+
3
+ module Unilogger
4
+
5
+ class LogFileEmitter
6
+
7
+ class << self
8
+ def build( options )
9
+ logdev = options.delete("logdev")
10
+ case logdev
11
+ when nil, /stderr/i
12
+ new( STDERR, :logdev => "STDERR" )
13
+ when /stdout/i
14
+ new( STDOUT, :logdev => "STDOUT" )
15
+ else
16
+ new( logdev, options.merge( :logdev => logdev ) )
17
+ end
18
+ end
19
+ end
20
+
21
+ # options includes a JSON representation of logdev
22
+ def initialize( logdev, options = {} )
23
+ @options = options
24
+ @logdev = ::Logger::LogDevice.new( logdev, options )
25
+ end
26
+
27
+ def emit( details, message, options )
28
+ if options && options.size > 0 then
29
+ options = options.map { |k,v| [k, v.to_json].join(":") }.join(",")
30
+ message = "#{message}; #{options}"
31
+ end
32
+ @logdev.write "#{details[:time].to_i} [#{details[:pid]}:#{details[:fiber]}] #{details[:pri_sym]} #{message}\n"
33
+ end
34
+
35
+ def as_json
36
+ { :log_file => @options }
37
+ end
38
+
39
+ end # LogFileEmitter
40
+
41
+ end # Unilogger
@@ -0,0 +1,92 @@
1
+ require "fiber" unless RUBY_VERSION =~ /^1\.8/
2
+ require "json"
3
+ require "logger"
4
+
5
+ module Unilogger
6
+
7
+ # Adds pid and timestamp to each log entry.
8
+ # Implements IO API (<<) which is equivalent to info()
9
+ # Implements Logger API (debug, info, warn, error, fatal)
10
+ class Logger
11
+
12
+ include ::Logger::Severity
13
+ attr :level, true
14
+ attr :emitters
15
+
16
+ def initialize( level = DEBUG, emitters = [] )
17
+ @level = level
18
+ @emitters = emitters.dup
19
+ end
20
+
21
+ def emit( details, message, options )
22
+ @emitters.each { |e| e.emit( details, message, options ) }
23
+ end
24
+
25
+ def <<( message )
26
+ details = { :pri_sym => :INFO, :pri_num => Logger::Severity::INFO, :pid => Process.pid, :time => Time.now }
27
+ self.emit( details, message, nil )
28
+ end
29
+
30
+ # level methods may take 0..2 arguments, or a block parameter
31
+ # argument 1 or the block is stringified as the primary message
32
+ # argument 2 is a set of named parameters (e.g. a hash)
33
+ ::Logger::Severity.constants.each do |const|
34
+
35
+ # const e.g. INFO; label e.g. info; priority e.g. 1
36
+ label = const.to_s.downcase.to_sym
37
+ priority = ::Logger::Severity.const_get(const)
38
+
39
+ # def info( message, options = {}, &block ) ...
40
+ define_method( label ) do |*args,&block|
41
+ raise ArgumentError if args.size > 2
42
+ if @level <= priority then
43
+ details = { :pri_sym => const, :pri_num => priority, :pid => Process.pid, :time => Time.now, :fiber => 0 } if RUBY_VERSION =~ /^1\.8/
44
+ details = { :pri_sym => const, :pri_num => priority, :pid => Process.pid, :time => Time.now, :fiber => Fiber.current.object_id } unless RUBY_VERSION =~ /^1\.8/
45
+ case args.size
46
+ when 0
47
+ message = block.call if block
48
+ options = nil
49
+ when 1
50
+ message = args.first
51
+ options = nil
52
+ when 2
53
+ message = args.first
54
+ options = args.last
55
+ end
56
+ self.emit( details, message.to_s, options )
57
+ end
58
+ @level <= priority
59
+ end # info()
60
+
61
+ # def info?
62
+ define_method( "#{label}?".to_sym ) do
63
+ @level <= priority
64
+ end # info?
65
+
66
+ end # each
67
+
68
+ def as_json
69
+ { :level => @level, :emitters => as_json_helper(@emitters) }
70
+ end
71
+
72
+ def as_json_helper( it )
73
+ if it.nil? then
74
+ it
75
+ elsif it.respond_to?(:as_json) then
76
+ it.as_json
77
+ elsif it.kind_of?(Hash) then
78
+ it.inject({}) { |a,i| a[i.first] = as_json_helper(i.last); a }
79
+ elsif it.kind_of?(Array) || it.kind_of?(Enumerable)
80
+ it.map { |i| as_json_helper(i) }
81
+ else
82
+ it
83
+ end
84
+ end
85
+
86
+ def to_json
87
+ as_json.to_json
88
+ end
89
+
90
+ end # Logger
91
+
92
+ end # Unilogger
@@ -0,0 +1,18 @@
1
+ require "logger"
2
+ require "mongo"
3
+
4
+ module Unilogger
5
+
6
+ class MongoEmitter
7
+
8
+ class << self
9
+ def build( options )
10
+ end
11
+ end
12
+
13
+ def emit( details, message, options )
14
+ end
15
+
16
+ end # MongoEmitter
17
+
18
+ end # Unilogger
@@ -0,0 +1,19 @@
1
+ require "logger"
2
+ require "redis"
3
+ require "redis/namespace"
4
+
5
+ module Unilogger
6
+
7
+ class RedisEmitter
8
+
9
+ class << self
10
+ def build( options )
11
+ end
12
+ end
13
+
14
+ def emit( details, message, options )
15
+ end
16
+
17
+ end # RedisEmitter
18
+
19
+ end # Unilogger
@@ -0,0 +1,3 @@
1
+ module Unilogger
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,28 @@
1
+ stderr: &stderr
2
+ LogFileEmitter:
3
+ logdev: stderr
4
+
5
+ standard: &standard
6
+ LogFileEmitter:
7
+ logdev: "./log/<%= ENV["RACK_ENV"] || ENV["RAILS_ENV"] || "development" %>.log"
8
+ shift_age: daily
9
+
10
+ development:
11
+ level: debug
12
+ emitters: [ *standard ]
13
+
14
+ test:
15
+ level: info
16
+ emitters: [ *stderr ]
17
+
18
+ beta:
19
+ level: info
20
+ emitters: [ *standard ]
21
+
22
+ staging:
23
+ level: info
24
+ emitters: [ *standard ]
25
+
26
+ production:
27
+ level: info
28
+ emitters: [ *standard ]
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root = File.expand_path( "../..", __FILE__ )
4
+ $: << root + "/lib"
5
+ require "unilogger"
6
+
7
+ logger = Unilogger::Builder.build :root => root
8
+ puts logger.to_json
9
+
10
+ logger.debug "Starting."
11
+ logger.info "started", :root => root
12
+ logger.warn "nothing to do"
13
+ logger.error "end of file"
14
+ logger.fatal "exiting"
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "unilogger/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "unilogger"
7
+ s.version = Unilogger::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Mark Lanett"]
10
+ s.email = ["mark.lanett@gmail.com"]
11
+ s.homepage = ""
12
+ s.summary = "Unified logger that writes to a log file, redis queue, mongo collection, and hoptoad."
13
+
14
+ s.rubyforge_project = "unilogger"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency "json"
22
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: unilogger
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Mark Lanett
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-04-04 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: json
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ description:
34
+ email:
35
+ - mark.lanett@gmail.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files: []
41
+
42
+ files:
43
+ - .gitignore
44
+ - Gemfile
45
+ - README
46
+ - Rakefile
47
+ - lib/unilogger.rb
48
+ - lib/unilogger/builder.rb
49
+ - lib/unilogger/log_file_emitter.rb
50
+ - lib/unilogger/logger.rb
51
+ - lib/unilogger/mongo_emitter.rb
52
+ - lib/unilogger/redis_emitter.rb
53
+ - lib/unilogger/version.rb
54
+ - test/logger.yml.erb
55
+ - test/test.rb
56
+ - unilogger.gemspec
57
+ has_rdoc: true
58
+ homepage: ""
59
+ licenses: []
60
+
61
+ post_install_message:
62
+ rdoc_options: []
63
+
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ requirements: []
83
+
84
+ rubyforge_project: unilogger
85
+ rubygems_version: 1.3.7
86
+ signing_key:
87
+ specification_version: 3
88
+ summary: Unified logger that writes to a log file, redis queue, mongo collection, and hoptoad.
89
+ test_files:
90
+ - test/logger.yml.erb
91
+ - test/test.rb