bunyan 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ gem 'mongo', '>= 0.19'
2
+ gem 'mongo_ext', '>= 0.19'
3
+
4
+ group :test do
5
+ gem 'rspec', '>= 1.3.0'
6
+ gem 'ZenTest'
7
+ gem 'autotest-growl'
8
+ gem 'autotest-fsevent'
9
+ end
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ Bunyan
2
+ ======
3
+ Bunyan is a thin ruby wrapper around a MongoDB [capped collection](http://www.mongodb.org/display/DOCS/Capped+Collections),
4
+ created with high-performance, flexible logging in mind.
5
+
6
+ ![](http://img2.timeinc.net/ew/dynamic/imgs/080612/Paul-Bunyan-Blue-Ox_l.jpg)
7
+
8
+ Install
9
+ =======
10
+ gem install bunyan
11
+
12
+ Configure
13
+ =========
14
+ The only configuration options required are the database and collection name.
15
+
16
+ For rails apps, puts the config block in an initializer.
17
+
18
+ # config/initializers/bunyan.rb
19
+ Bunyan::Logger.configure do |config|
20
+ # required options
21
+ config.database 'bunyan_logger'
22
+ config.collection 'development_log'
23
+
24
+ # optional
25
+ config.disabled true
26
+ end
27
+
28
+ Usage
29
+ =====
30
+ You can access the bunyan logger anywhere is your app via Bunyan::Logger.
31
+ The Logger class is implemented as a singleton, and you can call any instance
32
+ method on the Logger class. This is implemented with some method_missing magic,
33
+ which is explained in a bit more detail below.
34
+
35
+ Internals
36
+ =========
37
+ Bunyan makes heavy usage of method\_missing both at the class and instance level.
38
+ At the class level, this is purely for convenience to pass missing class methods
39
+ to the singleton instance, which precludes us from needing to use Logger.instance
40
+ directly. At the instance level, method\_missing is used to provide a very thin
41
+ layer around MongoDB, via the Mongo driver.
42
+
43
+ The net effect of this is that there is no reason to muck around with
44
+ calling methods directly on Bunyan::Logger.instance, because all methods that
45
+ don't already exist at the class level will be sent to Bunyan::Logger.instance.
46
+
47
+ Bunyan::Logger.count == Bunyan::Logger.instance.count # => true
48
+
49
+ Also, you can call any instance methods Bunyan::Logger that you would otherwise
50
+ call on a Mongo collection object.
51
+
52
+ More
53
+ ====
54
+ * [MongoDB Capped Collections](http://www.mongodb.org/display/DOCS/Capped+Collections)
55
+ * [Mongo Ruby Driver](http://github.com/mongodb/mongo-ruby-driver)
56
+
57
+ TODO
58
+ ====
59
+ * Ability to limit bunyan to only run in certain environments
60
+ * Add middleware client for easy drop-in to rails/rack apps
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "bunyan"
5
+ gemspec.summary = "A MongoDB-based logging solution."
6
+ gemspec.description = "Bunyan is a thin ruby wrapper around a MongoDB capped collection, created with high-performance, flexible logging in mind."
7
+ gemspec.email = "ajsharp@gmail.com"
8
+ gemspec.homepage = "http://github.com/ajsharp/bunyan"
9
+ gemspec.authors = ["Alex Sharp"]
10
+ gemspec.add_dependency 'mongo', '>= 0.19'
11
+ gemspec.add_dependency 'mongo_ext', '>= 0.19'
12
+ end
13
+ Jeweler::GemcutterTasks.new
14
+ rescue LoadError
15
+ puts "Jeweler not available. Install it with: gem install jeweler"
16
+ end
17
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bunyan.gemspec ADDED
@@ -0,0 +1,56 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{bunyan}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Alex Sharp"]
12
+ s.date = %q{2010-03-17}
13
+ s.description = %q{Bunyan is a thin ruby wrapper around a MongoDB capped collection, created with high-performance, flexible logging in mind.}
14
+ s.email = %q{ajsharp@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "Gemfile",
21
+ "README.md",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "bunyan.gemspec",
25
+ "lib/bunyan.rb",
26
+ "spec/bunyan_spec.rb",
27
+ "spec/spec.opts",
28
+ "spec/spec_helper.rb"
29
+ ]
30
+ s.homepage = %q{http://github.com/ajsharp/bunyan}
31
+ s.rdoc_options = ["--charset=UTF-8"]
32
+ s.require_paths = ["lib"]
33
+ s.rubygems_version = %q{1.3.6}
34
+ s.summary = %q{A MongoDB-based logging solution.}
35
+ s.test_files = [
36
+ "spec/bunyan_spec.rb",
37
+ "spec/spec_helper.rb"
38
+ ]
39
+
40
+ if s.respond_to? :specification_version then
41
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
42
+ s.specification_version = 3
43
+
44
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
45
+ s.add_runtime_dependency(%q<mongo>, [">= 0.19"])
46
+ s.add_runtime_dependency(%q<mongo_ext>, [">= 0.19"])
47
+ else
48
+ s.add_dependency(%q<mongo>, [">= 0.19"])
49
+ s.add_dependency(%q<mongo_ext>, [">= 0.19"])
50
+ end
51
+ else
52
+ s.add_dependency(%q<mongo>, [">= 0.19"])
53
+ s.add_dependency(%q<mongo_ext>, [">= 0.19"])
54
+ end
55
+ end
56
+
data/lib/bunyan.rb ADDED
@@ -0,0 +1,90 @@
1
+ require 'rubygems'
2
+
3
+ #gem 'mongo_ext'
4
+
5
+ require 'mongo'
6
+ require 'singleton'
7
+
8
+ module Bunyan
9
+ class Logger
10
+ include Singleton
11
+
12
+ class InvalidConfigurationError < RuntimeError; end
13
+
14
+ attr_reader :db, :connection, :config
15
+
16
+ # Bunyan::Logger.configure do |config|
17
+ # # required options
18
+ # config.database 'bunyan_logger'
19
+ # config.collection 'development_log'
20
+ # end
21
+ def configure(&block)
22
+ @config = {}
23
+
24
+ yield self
25
+
26
+ ensure_required_options_exist
27
+ initialize_connection unless disabled?
28
+ end
29
+
30
+ # First time called sets the database name.
31
+ # Otherwise, returns the database name.
32
+ def database(db_name = nil)
33
+ @config[:database] ||= db_name
34
+ end
35
+ alias_method :database=, :database
36
+
37
+ # First time called sets the collection name.
38
+ # Otherwise, returns the collection name.
39
+ # For the actual collection object returned by Mongo, see #db.
40
+ def collection(coll = nil)
41
+ @config[:collection] ||= coll
42
+ end
43
+ alias_method :collection=, :collection
44
+
45
+ def disabled(dis = nil)
46
+ @config[:disabled] ||= dis
47
+ end
48
+ alias_method :disabled=, :disabled
49
+
50
+ def disabled?
51
+ !!disabled
52
+ end
53
+
54
+ def method_missing(method, *args, &block)
55
+ begin
56
+ db.send(method, *args)
57
+ rescue
58
+ super(method, *args, &block)
59
+ end
60
+ end
61
+
62
+ # Pass all missing class methods to the singleton instance
63
+ def self.method_missing(method, *args, &block)
64
+ Logger.instance.send(method, *args, &block)
65
+ end
66
+
67
+ private
68
+ def initialize_connection
69
+ @connection = Mongo::Connection.new.db(database)
70
+ @db = retrieve_or_initialize_collection(collection)
71
+ end
72
+
73
+ def ensure_required_options_exist
74
+ raise InvalidConfigurationError, 'Error! Please provide a database name.' unless database
75
+ raise InvalidConfigurationError, 'Error! Please provide a collection name.' unless collection
76
+ end
77
+
78
+ def retrieve_or_initialize_collection(collection_name)
79
+ if collection_exists?(collection_name)
80
+ connection.collection(collection_name)
81
+ else
82
+ connection.create_collection(collection_name, :capped => true)
83
+ end
84
+ end
85
+
86
+ def collection_exists?(collection_name)
87
+ connection.collection_names.include? collection_name
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,137 @@
1
+ require 'spec_helper'
2
+
3
+ describe Bunyan::Logger do
4
+
5
+ before do
6
+ @conn = mock_mongo_connection
7
+ @logger = Bunyan::Logger.instance
8
+ @logger.stub!(:connection).and_return(@conn)
9
+ end
10
+
11
+ it 'should have a connection' do
12
+ @logger.should respond_to :connection
13
+ end
14
+
15
+ it 'should have a collection' do
16
+ @logger.should respond_to :collection
17
+ end
18
+
19
+ it 'should have a config hash' do
20
+ @logger.config.should be_a Hash
21
+ end
22
+
23
+ it 'should create a new capped collection if the collection does not already exist' do
24
+ @conn.should_receive(:create_collection).with('collection_1', :capped => true)
25
+ @conn.stub!(:collection_names).and_return([])
26
+ Bunyan::Logger.configure do |config|
27
+ config.database 'database_1'
28
+ config.collection 'collection_1'
29
+ end
30
+ end
31
+
32
+ it 'should not create a new collection if one already exists by that name' do
33
+ @conn.should_not_receive(:create_collection)
34
+ @conn.collection_names.should_receive(:include?).with('collection_1').and_return(true)
35
+ Bunyan::Logger.configure do |config|
36
+ config.database 'database_1'
37
+ config.collection 'collection_1'
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ describe 'the required config options' do
44
+ it 'should raise an error if a db name is not provided' do
45
+ lambda {
46
+ Bunyan::Logger.configure do |c|
47
+ c.collection 'collection_without_database'
48
+ end
49
+ }.should raise_exception(Bunyan::Logger::InvalidConfigurationError, 'Error! Please provide a database name.')
50
+ end
51
+
52
+ it 'should raise an error if a db collection is not provided' do
53
+ lambda {
54
+ Bunyan::Logger.configure do |c|
55
+ c.database 'db_without_collection'
56
+ end
57
+ }.should raise_exception(Bunyan::Logger::InvalidConfigurationError, 'Error! Please provide a collection name.')
58
+ end
59
+ end
60
+
61
+ describe 'bunyan logger configuration' do
62
+ describe 'setting config values' do
63
+ before do
64
+ Bunyan::Logger.configure do |c|
65
+ c.database 'database2'
66
+ c.collection 'collection2'
67
+ end
68
+ end
69
+
70
+ it 'should allow setting of the database' do
71
+ Bunyan::Logger.database.should == 'database2'
72
+ end
73
+
74
+ it 'shoudl allow setting of the collection name' do
75
+ Bunyan::Logger.collection.should == 'collection2'
76
+ end
77
+ end
78
+
79
+ describe 'the optional config options' do
80
+ it 'should allow the user to mark bunyan as disabled' do
81
+ Bunyan::Logger.configure do |c|
82
+ c.database 'test_db'
83
+ c.collection 'test_collection'
84
+ c.disabled true
85
+ end
86
+ Bunyan::Logger.should be_disabled
87
+ end
88
+ end
89
+
90
+ describe "when the disabled flag is set" do
91
+ it 'should not create a new logger instance' do
92
+ Bunyan::Logger.should_not_receive(:initialize_connection)
93
+ Bunyan::Logger.configure do |c|
94
+ c.database 'test_db'
95
+ c.collection 'test_collection'
96
+ c.disabled true
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ describe Bunyan::Logger, "#disabled?" do
103
+ it "should return false if nothing is set" do
104
+ Bunyan::Logger.configure do |config|
105
+ config.database 'my_database'
106
+ config.collection 'my_collection'
107
+ end
108
+ Bunyan::Logger.disabled?.should == false
109
+ end
110
+ end
111
+
112
+ describe 'the database getter' do
113
+ it 'should allow setting of the database' do
114
+ Bunyan::Logger.configure do |config|
115
+ config.database 'my_database'
116
+ config.collection 'my_collection'
117
+ end
118
+ Bunyan::Logger.instance.database.should == 'my_database'
119
+ end
120
+ end
121
+
122
+ describe 'mongodb instance methods passed to a logger instance' do
123
+ it 'should be passed through to the collection' do
124
+ Bunyan::Logger.db.should_receive(:count)
125
+ Bunyan::Logger.count
126
+ end
127
+ end
128
+
129
+ describe 'alternate configuration syntax' do
130
+ it 'should allow a user to set config options with traditional setters' do
131
+ Bunyan::Logger.configure do |config|
132
+ config.database = 'some_database'
133
+ config.collection = 'some_collection'
134
+ end
135
+ Bunyan::Logger.config[:database].should == 'some_database'
136
+ end
137
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,5 @@
1
+ --colour
2
+ --format
3
+ s
4
+ --loadby mtime
5
+ --reverse
@@ -0,0 +1,33 @@
1
+ Bundler.setup
2
+ Bundler.require :default, :test
3
+
4
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/bunyan')
5
+ $LOAD_PATH.unshift File.expand_path(__FILE__)
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ config.after :each do
10
+ cleanup_bunyan_config
11
+ end
12
+
13
+ config.before :each do
14
+ mock_mongo_connection
15
+ end
16
+
17
+ def mock_mongo_connection
18
+ @mock_collection = mock("Mongo Collection")
19
+ @mock_database = mock("Mongo Database",
20
+ :collection => @mock_collection,
21
+ :create_collection => @mock_collection,
22
+ :collection_names => ['name 1'])
23
+ @mock_connection = mock("Mongo Connection", :db => @mock_database)
24
+ Mongo::Connection.stub!(:new).and_return(@mock_connection)
25
+ @mock_database
26
+ end
27
+
28
+ def cleanup_bunyan_config
29
+ Bunyan::Logger.instance_variable_set(:@database, nil)
30
+ Bunyan::Logger.instance_variable_set(:@collection, nil)
31
+ Bunyan::Logger.instance_variable_set(:@db, nil)
32
+ end
33
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bunyan
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Alex Sharp
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-17 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: mongo
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 19
30
+ version: "0.19"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: mongo_ext
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 0
42
+ - 19
43
+ version: "0.19"
44
+ type: :runtime
45
+ version_requirements: *id002
46
+ description: Bunyan is a thin ruby wrapper around a MongoDB capped collection, created with high-performance, flexible logging in mind.
47
+ email: ajsharp@gmail.com
48
+ executables: []
49
+
50
+ extensions: []
51
+
52
+ extra_rdoc_files:
53
+ - README.md
54
+ files:
55
+ - .gitignore
56
+ - Gemfile
57
+ - README.md
58
+ - Rakefile
59
+ - VERSION
60
+ - bunyan.gemspec
61
+ - lib/bunyan.rb
62
+ - spec/bunyan_spec.rb
63
+ - spec/spec.opts
64
+ - spec/spec_helper.rb
65
+ has_rdoc: true
66
+ homepage: http://github.com/ajsharp/bunyan
67
+ licenses: []
68
+
69
+ post_install_message:
70
+ rdoc_options:
71
+ - --charset=UTF-8
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ requirements: []
89
+
90
+ rubyforge_project:
91
+ rubygems_version: 1.3.6
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: A MongoDB-based logging solution.
95
+ test_files:
96
+ - spec/bunyan_spec.rb
97
+ - spec/spec_helper.rb