unilogger 0.0.1

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.
@@ -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