central_logger 0.1.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/.rvmrc +1 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +108 -0
- data/MIT-LICENSE +20 -0
- data/README.md +97 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/central_logger.gemspec +93 -0
- data/lib/central_logger.rb +8 -0
- data/lib/central_logger/filter.rb +22 -0
- data/lib/central_logger/initializer.rb +16 -0
- data/lib/central_logger/initializer_mixin.rb +20 -0
- data/lib/central_logger/mongo_logger.rb +131 -0
- data/lib/railtie.rb +16 -0
- data/test/active_record.rb +13 -0
- data/test/config/database.yml +6 -0
- data/test/rails.rb +13 -0
- data/test/shoulda_macros/log_macros.rb +7 -0
- data/test/test_helper.rb +34 -0
- data/test/unit/central_logger_test.rb +107 -0
- metadata +222 -0
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.2@central_logger
|
data/Gemfile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem "rake"
|
4
|
+
gem "bundler", "~> 1.0.0"
|
5
|
+
gem "mongo"
|
6
|
+
gem "bson_ext"
|
7
|
+
|
8
|
+
group :production do
|
9
|
+
# don't want to force development to have this requirement, because every
|
10
|
+
# Rails dependency is mocked
|
11
|
+
gem "rails",">= 2.3.8"
|
12
|
+
end
|
13
|
+
|
14
|
+
group :development do
|
15
|
+
# adds Bundler support for gemspec generation
|
16
|
+
gem "jeweler", "~> 1.5.0.pre5"
|
17
|
+
gem "shoulda"
|
18
|
+
gem "i18n"
|
19
|
+
gem "activesupport"
|
20
|
+
gem "mocha"
|
21
|
+
gem (RUBY_VERSION =~ /^1\.9/ ? "ruby-debug19" : "ruby-debug")
|
22
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
abstract (1.0.0)
|
5
|
+
actionmailer (3.0.1)
|
6
|
+
actionpack (= 3.0.1)
|
7
|
+
mail (~> 2.2.5)
|
8
|
+
actionpack (3.0.1)
|
9
|
+
activemodel (= 3.0.1)
|
10
|
+
activesupport (= 3.0.1)
|
11
|
+
builder (~> 2.1.2)
|
12
|
+
erubis (~> 2.6.6)
|
13
|
+
i18n (~> 0.4.1)
|
14
|
+
rack (~> 1.2.1)
|
15
|
+
rack-mount (~> 0.6.12)
|
16
|
+
rack-test (~> 0.5.4)
|
17
|
+
tzinfo (~> 0.3.23)
|
18
|
+
activemodel (3.0.1)
|
19
|
+
activesupport (= 3.0.1)
|
20
|
+
builder (~> 2.1.2)
|
21
|
+
i18n (~> 0.4.1)
|
22
|
+
activerecord (3.0.1)
|
23
|
+
activemodel (= 3.0.1)
|
24
|
+
activesupport (= 3.0.1)
|
25
|
+
arel (~> 1.0.0)
|
26
|
+
tzinfo (~> 0.3.23)
|
27
|
+
activeresource (3.0.1)
|
28
|
+
activemodel (= 3.0.1)
|
29
|
+
activesupport (= 3.0.1)
|
30
|
+
activesupport (3.0.1)
|
31
|
+
archive-tar-minitar (0.5.2)
|
32
|
+
arel (1.0.1)
|
33
|
+
activesupport (~> 3.0.0)
|
34
|
+
bson (1.1.1)
|
35
|
+
bson_ext (1.1.1)
|
36
|
+
builder (2.1.2)
|
37
|
+
columnize (0.3.1)
|
38
|
+
erubis (2.6.6)
|
39
|
+
abstract (>= 1.0.0)
|
40
|
+
git (1.2.5)
|
41
|
+
i18n (0.4.2)
|
42
|
+
jeweler (1.5.0.pre5)
|
43
|
+
bundler (~> 1.0.0)
|
44
|
+
git (>= 1.2.5)
|
45
|
+
rake
|
46
|
+
linecache19 (0.5.11)
|
47
|
+
ruby_core_source (>= 0.1.4)
|
48
|
+
mail (2.2.9)
|
49
|
+
activesupport (>= 2.3.6)
|
50
|
+
i18n (~> 0.4.1)
|
51
|
+
mime-types (~> 1.16)
|
52
|
+
treetop (~> 1.4.8)
|
53
|
+
mime-types (1.16)
|
54
|
+
mocha (0.9.9)
|
55
|
+
rake
|
56
|
+
mongo (1.1.1)
|
57
|
+
bson (>= 1.1.1)
|
58
|
+
polyglot (0.3.1)
|
59
|
+
rack (1.2.1)
|
60
|
+
rack-mount (0.6.13)
|
61
|
+
rack (>= 1.0.0)
|
62
|
+
rack-test (0.5.6)
|
63
|
+
rack (>= 1.0)
|
64
|
+
rails (3.0.1)
|
65
|
+
actionmailer (= 3.0.1)
|
66
|
+
actionpack (= 3.0.1)
|
67
|
+
activerecord (= 3.0.1)
|
68
|
+
activeresource (= 3.0.1)
|
69
|
+
activesupport (= 3.0.1)
|
70
|
+
bundler (~> 1.0.0)
|
71
|
+
railties (= 3.0.1)
|
72
|
+
railties (3.0.1)
|
73
|
+
actionpack (= 3.0.1)
|
74
|
+
activesupport (= 3.0.1)
|
75
|
+
rake (>= 0.8.4)
|
76
|
+
thor (~> 0.14.0)
|
77
|
+
rake (0.8.7)
|
78
|
+
ruby-debug-base19 (0.11.24)
|
79
|
+
columnize (>= 0.3.1)
|
80
|
+
linecache19 (>= 0.5.11)
|
81
|
+
ruby_core_source (>= 0.1.4)
|
82
|
+
ruby-debug19 (0.11.6)
|
83
|
+
columnize (>= 0.3.1)
|
84
|
+
linecache19 (>= 0.5.11)
|
85
|
+
ruby-debug-base19 (>= 0.11.19)
|
86
|
+
ruby_core_source (0.1.4)
|
87
|
+
archive-tar-minitar (>= 0.5.2)
|
88
|
+
shoulda (2.11.3)
|
89
|
+
thor (0.14.3)
|
90
|
+
treetop (1.4.8)
|
91
|
+
polyglot (>= 0.3.1)
|
92
|
+
tzinfo (0.3.23)
|
93
|
+
|
94
|
+
PLATFORMS
|
95
|
+
ruby
|
96
|
+
|
97
|
+
DEPENDENCIES
|
98
|
+
activesupport
|
99
|
+
bson_ext
|
100
|
+
bundler (~> 1.0.0)
|
101
|
+
i18n
|
102
|
+
jeweler (~> 1.5.0.pre5)
|
103
|
+
mocha
|
104
|
+
mongo
|
105
|
+
rails (>= 2.3.8)
|
106
|
+
rake
|
107
|
+
ruby-debug19
|
108
|
+
shoulda
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 [name of plugin creator]
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# CentralLogger
|
2
|
+
|
3
|
+
Log to a central MongoDB from Rails apps.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
1. Install the gem:
|
8
|
+
|
9
|
+
gem install central_logger
|
10
|
+
|
11
|
+
1. Add the following line to your ApplicationController:
|
12
|
+
|
13
|
+
include CentralLogger::Filter
|
14
|
+
|
15
|
+
1. If using Rails < 3, configure environment.rb as shown below (in config/environment.rb). Otherwise, the logger is
|
16
|
+
automatically initialized for all environments.
|
17
|
+
|
18
|
+
require 'central_logger'
|
19
|
+
CentralLogger::Initializer.initialize_deprecated_logger(config)
|
20
|
+
|
21
|
+
1. Add mongo settings to database.yml for each environment in which you want to use MongoDB for logging. The values below are defaults:
|
22
|
+
|
23
|
+
development:
|
24
|
+
adapter: mysql
|
25
|
+
database: my_app_development
|
26
|
+
user: root
|
27
|
+
mongo:
|
28
|
+
database: my_app # required
|
29
|
+
capsize: <%= 10.megabytes %> # default: 250MB for production; 100MB otherwise
|
30
|
+
host: localhost # default: localhost
|
31
|
+
port: 27017 # default: 27017
|
32
|
+
|
33
|
+
With that in place, a new MongoDB document (record) will be created for each request and,
|
34
|
+
by default will record the following information: Runtime, IP Address, Request Time, Controller,
|
35
|
+
Action, Params, Application Name and All messages sent to the logger. The structure of the Mongo document looks like this:
|
36
|
+
|
37
|
+
{
|
38
|
+
'action' : action_name,
|
39
|
+
'application_name' : action_name,
|
40
|
+
'controller' : controller_name,
|
41
|
+
'ip' : ip_address,
|
42
|
+
'messages' : {
|
43
|
+
'info' : [ ],
|
44
|
+
'debug' : [ ],
|
45
|
+
'error' : [ ],
|
46
|
+
'warn' : [ ],
|
47
|
+
'fatal' : [ ]
|
48
|
+
},
|
49
|
+
'params' : { },
|
50
|
+
'path' : path,
|
51
|
+
'request_time' : date_of_request,
|
52
|
+
'runtime' : elapsed_execution_time_in_seconds,
|
53
|
+
'url' : full_url
|
54
|
+
}
|
55
|
+
|
56
|
+
Beyond that, if you want to add extra information to the base of the document
|
57
|
+
(let's say something like user_guid on every request that it's available),
|
58
|
+
you can just call the Rails.logger.add_metadata method on your logger like so
|
59
|
+
(for example from a before_filter):
|
60
|
+
|
61
|
+
# make sure we're using the CentralLogger in this environment
|
62
|
+
if Rails.logger.respond_to?(:add_metadata)
|
63
|
+
Rails.logger.add_metadata(:user_guid => @user_guid)
|
64
|
+
end
|
65
|
+
|
66
|
+
## Examples
|
67
|
+
|
68
|
+
And now, for a couple quick examples on getting ahold of this log data...
|
69
|
+
First, here's how to get a handle on the MongoDB from within a Rails console:
|
70
|
+
|
71
|
+
>> db = Rails.logger.mongo_connection
|
72
|
+
=> #<Mongo::DB:0x102f19ac0 @slave_ok=nil, @name="my_app" ... >
|
73
|
+
|
74
|
+
>> collection = db[Rails.logger.mongo_collection_name]
|
75
|
+
=> #<Mongo::Collection:0x1031b3ee8 @name="development_log" ... >
|
76
|
+
|
77
|
+
Once you've got the collection, you can find all requests for a specific user (with guid):
|
78
|
+
|
79
|
+
>> cursor = collection.find(:user_guid => '12355')
|
80
|
+
=> #<Mongo::Cursor:0x1031a3e30 ... >
|
81
|
+
>> cursor.count
|
82
|
+
=> 5
|
83
|
+
|
84
|
+
Find all requests that took more that one second to complete:
|
85
|
+
|
86
|
+
>> collection.find({:runtime => {'$gt' => 1000}}).count
|
87
|
+
=> 3
|
88
|
+
|
89
|
+
Find all order#show requests with a particular order id (id=order_id):
|
90
|
+
|
91
|
+
>> collection.find({"controller" => "order", "action"=> "show", "params.id" => order_id})
|
92
|
+
|
93
|
+
Find all requests with an exception that contains "RoutingError" in the message or stack trace:
|
94
|
+
|
95
|
+
>> collection.find({"messages.error" => /RoutingError/})
|
96
|
+
|
97
|
+
Copyright (c) 2009 Phil Burrows, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'rubygems'
|
5
|
+
require 'bundler'
|
6
|
+
require 'jeweler'
|
7
|
+
|
8
|
+
desc 'Default: run unit tests.'
|
9
|
+
task :default => :test
|
10
|
+
task :test => :check_dependencies
|
11
|
+
|
12
|
+
begin
|
13
|
+
Bundler.setup(:default, :development)
|
14
|
+
rescue Bundler::BundlerError => e
|
15
|
+
$stderr.puts e.message
|
16
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
17
|
+
exit e.status_code
|
18
|
+
end
|
19
|
+
|
20
|
+
Jeweler::Tasks.new do |gem|
|
21
|
+
gem.name = "central_logger"
|
22
|
+
gem.summary = %Q{Central Logger for Rails}
|
23
|
+
gem.description = %Q{Centralized logging for rails apps using MongoDB. The idea and the core code is from http://github.com/peburrows/central_logger}
|
24
|
+
gem.email = "astupka@customink.com"
|
25
|
+
gem.homepage = "http://github.com/customink/central_logger"
|
26
|
+
gem.authors = ["Phil Burrows", "Alex Stupka"]
|
27
|
+
gem.rubyforge_project = "central_logger"
|
28
|
+
end
|
29
|
+
Jeweler::RubyforgeTasks.new do |rubyforge|
|
30
|
+
rubyforge.doc_task = "rdoc"
|
31
|
+
end
|
32
|
+
# dependencies defined in Gemfile
|
33
|
+
|
34
|
+
Rake::TestTask.new(:test) do |test|
|
35
|
+
test.libs << 'lib' << 'test'
|
36
|
+
test.pattern = 'test/**/*_test.rb'
|
37
|
+
test.verbose = true
|
38
|
+
end
|
39
|
+
|
40
|
+
Rake::RDocTask.new do |rdoc|
|
41
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
42
|
+
|
43
|
+
rdoc.rdoc_dir = 'rdoc'
|
44
|
+
rdoc.title = "central_logger #{version}"
|
45
|
+
rdoc.rdoc_files.include('README*')
|
46
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
47
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,93 @@
|
|
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{central_logger}
|
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 = ["Phil Burrows", "Alex Stupka"]
|
12
|
+
s.date = %q{2010-11-01}
|
13
|
+
s.description = %q{Centralized logging for rails apps using MongoDB. The idea and the core code is from http://github.com/peburrows/central_logger}
|
14
|
+
s.email = %q{astupka@customink.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.md"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".rvmrc",
|
20
|
+
"Gemfile",
|
21
|
+
"Gemfile.lock",
|
22
|
+
"MIT-LICENSE",
|
23
|
+
"README.md",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"central_logger.gemspec",
|
27
|
+
"lib/central_logger.rb",
|
28
|
+
"lib/central_logger/filter.rb",
|
29
|
+
"lib/central_logger/initializer.rb",
|
30
|
+
"lib/central_logger/initializer_mixin.rb",
|
31
|
+
"lib/central_logger/mongo_logger.rb",
|
32
|
+
"lib/railtie.rb",
|
33
|
+
"test/active_record.rb",
|
34
|
+
"test/config/database.yml",
|
35
|
+
"test/rails.rb",
|
36
|
+
"test/shoulda_macros/log_macros.rb",
|
37
|
+
"test/test_helper.rb",
|
38
|
+
"test/unit/central_logger_test.rb"
|
39
|
+
]
|
40
|
+
s.homepage = %q{http://github.com/customink/central_logger}
|
41
|
+
s.require_paths = ["lib"]
|
42
|
+
s.rubyforge_project = %q{central_logger}
|
43
|
+
s.rubygems_version = %q{1.3.7}
|
44
|
+
s.summary = %q{Central Logger for Rails}
|
45
|
+
s.test_files = [
|
46
|
+
"test/active_record.rb",
|
47
|
+
"test/rails.rb",
|
48
|
+
"test/shoulda_macros/log_macros.rb",
|
49
|
+
"test/test_helper.rb",
|
50
|
+
"test/unit/central_logger_test.rb"
|
51
|
+
]
|
52
|
+
|
53
|
+
if s.respond_to? :specification_version then
|
54
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
55
|
+
s.specification_version = 3
|
56
|
+
|
57
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
58
|
+
s.add_runtime_dependency(%q<rake>, [">= 0"])
|
59
|
+
s.add_runtime_dependency(%q<bundler>, ["~> 1.0.0"])
|
60
|
+
s.add_runtime_dependency(%q<mongo>, [">= 0"])
|
61
|
+
s.add_runtime_dependency(%q<bson_ext>, [">= 0"])
|
62
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.0.pre5"])
|
63
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
64
|
+
s.add_development_dependency(%q<i18n>, [">= 0"])
|
65
|
+
s.add_development_dependency(%q<activesupport>, [">= 0"])
|
66
|
+
s.add_development_dependency(%q<mocha>, [">= 0"])
|
67
|
+
s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
|
68
|
+
else
|
69
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
70
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
71
|
+
s.add_dependency(%q<mongo>, [">= 0"])
|
72
|
+
s.add_dependency(%q<bson_ext>, [">= 0"])
|
73
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre5"])
|
74
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
75
|
+
s.add_dependency(%q<i18n>, [">= 0"])
|
76
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
77
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
78
|
+
s.add_dependency(%q<ruby-debug19>, [">= 0"])
|
79
|
+
end
|
80
|
+
else
|
81
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
82
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
83
|
+
s.add_dependency(%q<mongo>, [">= 0"])
|
84
|
+
s.add_dependency(%q<bson_ext>, [">= 0"])
|
85
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.0.pre5"])
|
86
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
87
|
+
s.add_dependency(%q<i18n>, [">= 0"])
|
88
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
89
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
90
|
+
s.add_dependency(%q<ruby-debug19>, [">= 0"])
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module CentralLogger
|
2
|
+
module Filter
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval { around_filter :enable_central_logger }
|
5
|
+
end
|
6
|
+
|
7
|
+
def enable_central_logger
|
8
|
+
return yield unless Rails.logger.respond_to?(:mongoize)
|
9
|
+
|
10
|
+
# make sure the controller knows how to filter its parameters
|
11
|
+
f_params = respond_to?(:filter_parameters) ? filter_parameters(params) : params
|
12
|
+
Rails.logger.mongoize({
|
13
|
+
:action => action_name,
|
14
|
+
:controller => controller_name,
|
15
|
+
:path => request.path,
|
16
|
+
:url => request.url,
|
17
|
+
:params => f_params,
|
18
|
+
:ip => request.remote_ip
|
19
|
+
}) { yield }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
if Rails::VERSION::MAJOR == 2
|
2
|
+
require 'central_logger/initializer_mixin'
|
3
|
+
|
4
|
+
module CentralLogger
|
5
|
+
class Initializer
|
6
|
+
extend CentralLogger::InitializerMixin
|
7
|
+
|
8
|
+
# mirrors code in Rails 2 initializer.rb#initialize_logger
|
9
|
+
def self.initialize_deprecated_logger(config)
|
10
|
+
logger = config.logger = create_logger(config, config.log_path)
|
11
|
+
|
12
|
+
silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module CentralLogger
|
2
|
+
module InitializerMixin
|
3
|
+
# initialization common to Rails 2.3.8 and 3.0
|
4
|
+
def create_logger(config, path)
|
5
|
+
level = ActiveSupport::BufferedLogger.const_get(config.log_level.to_s.upcase)
|
6
|
+
logger = MongoLogger.new(:path => path, :level => level)
|
7
|
+
logger.auto_flushing = false if Rails.env.production?
|
8
|
+
logger
|
9
|
+
rescue StandardError => e
|
10
|
+
logger = ActiveSupport::BufferedLogger.new(STDERR)
|
11
|
+
logger.level = ActiveSupport::BufferedLogger::WARN
|
12
|
+
logger.warn(
|
13
|
+
"CentralLogger Initializer Error: Unable to access log file. Please ensure that #{path} exists and is chmod 0666. " +
|
14
|
+
"The log level has been raised to WARN and the output directed to STDERR until the problem is fixed." + "\n" +
|
15
|
+
e.message + "\n" + e.backtrace.join("\n")
|
16
|
+
)
|
17
|
+
logger
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'mongo'
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_support/core_ext'
|
5
|
+
|
6
|
+
module CentralLogger
|
7
|
+
class MongoLogger < ActiveSupport::BufferedLogger
|
8
|
+
PRODUCTION_COLLECTION_SIZE = 250.megabytes
|
9
|
+
DEFAULT_COLLECTION_SIZE = 100.megabytes
|
10
|
+
|
11
|
+
attr_reader :db_configuration, :mongo_connection, :mongo_collection_name
|
12
|
+
|
13
|
+
def initialize(options={})
|
14
|
+
path = options[:path] || File.join(Rails.root, "log/#{Rails.env}.log")
|
15
|
+
level = options[:level] || DEBUG
|
16
|
+
super(path, level)
|
17
|
+
internal_initialize
|
18
|
+
rescue => e
|
19
|
+
# in case the logger is fouled up use stdout
|
20
|
+
puts "=> !! A connection to mongo could not be established - the logger will function like a normal ActiveSupport::BufferedLogger !!"
|
21
|
+
puts e.message + "\n" + e.backtrace.join("\n")
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_metadata(options={})
|
25
|
+
options.each_pair do |key, value|
|
26
|
+
unless [:messages, :request_time, :ip, :runtime, :application_name].include?(key.to_sym)
|
27
|
+
@mongo_record[key] = value
|
28
|
+
else
|
29
|
+
raise ArgumentError, ":#{key} is a reserved key for the central logger. Please choose a different key"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def add(severity, message = nil, progname = nil, &block)
|
35
|
+
if @level <= severity && message.present? && @mongo_record.present?
|
36
|
+
# remove Rails colorization to get the actual message
|
37
|
+
message.gsub!(/(\e(\[([\d;]*[mz]?))?)?/, '').strip! if logging_colorized?
|
38
|
+
@mongo_record[:messages][level_to_sym(severity)] << message
|
39
|
+
end
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
43
|
+
# Drop the capped_collection and recreate it
|
44
|
+
def reset_collection
|
45
|
+
@mongo_connection[@mongo_collection_name].drop
|
46
|
+
create_collection
|
47
|
+
end
|
48
|
+
|
49
|
+
def mongoize(options={})
|
50
|
+
@mongo_record = options.merge({
|
51
|
+
:messages => Hash.new { |hash, key| hash[key] = Array.new },
|
52
|
+
:request_time => Time.now.getutc,
|
53
|
+
:application_name => @application_name
|
54
|
+
})
|
55
|
+
# In case of exception, make sure it's set
|
56
|
+
runtime = 0
|
57
|
+
runtime = Benchmark.measure do
|
58
|
+
yield
|
59
|
+
end
|
60
|
+
rescue Exception => e
|
61
|
+
add(3, e.message + "\n" + e.backtrace.join("\n"))
|
62
|
+
# Reraise the exception for anyone else who cares
|
63
|
+
raise e
|
64
|
+
ensure
|
65
|
+
insert_log_record(runtime)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
# facilitate testing
|
70
|
+
def internal_initialize
|
71
|
+
configure
|
72
|
+
connect
|
73
|
+
check_for_collection
|
74
|
+
end
|
75
|
+
|
76
|
+
def configure
|
77
|
+
default_capsize = Rails.env.production? ? PRODUCTION_COLLECTION_SIZE : DEFAULT_COLLECTION_SIZE
|
78
|
+
user_config = YAML::load(ERB.new(IO.read(File.join(Rails.root, 'config/database.yml'))).result)[Rails.env]['mongo'] || {}
|
79
|
+
@application_name = Rails.root.basename.to_s
|
80
|
+
|
81
|
+
@mongo_collection_name = "#{Rails.env}_log"
|
82
|
+
|
83
|
+
@db_configuration = {
|
84
|
+
'host' => 'localhost',
|
85
|
+
'port' => 27017,
|
86
|
+
'capsize' => default_capsize}.merge(user_config)
|
87
|
+
end
|
88
|
+
|
89
|
+
def connect
|
90
|
+
@mongo_connection ||= Mongo::Connection.new(@db_configuration['host'],
|
91
|
+
@db_configuration['port'],
|
92
|
+
:auto_reconnect => true).db(@db_configuration['database'])
|
93
|
+
end
|
94
|
+
|
95
|
+
def create_collection
|
96
|
+
@mongo_connection.create_collection(@mongo_collection_name,
|
97
|
+
{:capped => true, :size => @db_configuration['capsize']})
|
98
|
+
end
|
99
|
+
|
100
|
+
def check_for_collection
|
101
|
+
# setup the capped collection if it doesn't already exist
|
102
|
+
unless @mongo_connection.collection_names.include?(@mongo_collection_name)
|
103
|
+
create_collection
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def insert_log_record(runtime)
|
108
|
+
@mongo_record[:runtime] = (runtime.real * 1000).ceil
|
109
|
+
@mongo_connection[@mongo_collection_name].insert(@mongo_record) rescue nil
|
110
|
+
end
|
111
|
+
|
112
|
+
def level_to_sym(level)
|
113
|
+
case level
|
114
|
+
when 0 then :debug
|
115
|
+
when 1 then :info
|
116
|
+
when 2 then :warn
|
117
|
+
when 3 then :error
|
118
|
+
when 4 then :fatal
|
119
|
+
when 5 then :unknown
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def logging_colorized?
|
124
|
+
# Cache it since these ActiveRecord attributes are assigned after logger initialization occurs
|
125
|
+
@colorized ||= Object.const_defined?(:ActiveRecord) &&
|
126
|
+
(Rails::VERSION::MAJOR >= 3 ?
|
127
|
+
ActiveRecord::LogSubscriber.colorize_logging :
|
128
|
+
ActiveRecord::Base.colorize_logging)
|
129
|
+
end
|
130
|
+
end # class MongoLogger
|
131
|
+
end
|
data/lib/railtie.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
if Rails::VERSION::MAJOR == 3
|
2
|
+
require 'central_logger/initializer_mixin'
|
3
|
+
|
4
|
+
class Railtie < Rails::Railtie
|
5
|
+
include CentralLogger::InitializerMixin
|
6
|
+
|
7
|
+
# load earlier than bootstrap.rb initializer loads the default logger. bootstrap
|
8
|
+
# initializer will then skip its own initialization once Rails.logger is defined
|
9
|
+
initializer :initialize_central_logger, :before => :initialize_logger do
|
10
|
+
app_config = Rails.application.config
|
11
|
+
Rails.logger = config.logger = create_logger(app_config,
|
12
|
+
app_config.paths.log.to_a.first)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
data/test/rails.rb
ADDED
data/test/test_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'shoulda'
|
3
|
+
require 'mocha'
|
4
|
+
# mock rails class
|
5
|
+
require 'pathname'
|
6
|
+
require 'rails'
|
7
|
+
|
8
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
9
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
10
|
+
|
11
|
+
Shoulda.autoload_macros("#{File.dirname(__FILE__)}/..")
|
12
|
+
|
13
|
+
class Test::Unit::TestCase
|
14
|
+
def log(msg)
|
15
|
+
@central_logger.mongoize({"id" => 1}) do
|
16
|
+
@central_logger.debug(msg)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def log_metadata(options)
|
21
|
+
@central_logger.mongoize({"id" => 1}) do
|
22
|
+
@central_logger.add_metadata(options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def require_bogus_active_record
|
27
|
+
require 'active_record'
|
28
|
+
end
|
29
|
+
|
30
|
+
def common_setup
|
31
|
+
@con = @central_logger.mongo_connection
|
32
|
+
@collection = @con[@central_logger.mongo_collection_name]
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'central_logger/mongo_logger'
|
3
|
+
|
4
|
+
# test the basic stuff
|
5
|
+
class CentralLogger::MongoLoggerTest < Test::Unit::TestCase
|
6
|
+
extend LogMacros
|
7
|
+
|
8
|
+
context "A CentralLogger::MongoLogger" do
|
9
|
+
context "during configuration in instantiation" do
|
10
|
+
setup do
|
11
|
+
CentralLogger::MongoLogger.any_instance.stubs(:internal_initialize).returns(nil)
|
12
|
+
@central_logger = CentralLogger::MongoLogger.new
|
13
|
+
@central_logger.send(:configure)
|
14
|
+
end
|
15
|
+
|
16
|
+
should "set the default host, port, and capsize if not configured" do
|
17
|
+
assert_equal 'localhost', @central_logger.db_configuration['host']
|
18
|
+
assert_equal 27017, @central_logger.db_configuration['port']
|
19
|
+
assert_equal CentralLogger::MongoLogger::DEFAULT_COLLECTION_SIZE, @central_logger.db_configuration['capsize']
|
20
|
+
end
|
21
|
+
|
22
|
+
should "set the mongo collection name depending on the Rails environment" do
|
23
|
+
assert_equal "#{Rails.env}_log", @central_logger.mongo_collection_name
|
24
|
+
end
|
25
|
+
|
26
|
+
context "upon connecting to an empty database" do
|
27
|
+
setup do
|
28
|
+
@central_logger.send(:connect)
|
29
|
+
common_setup
|
30
|
+
@collection.drop
|
31
|
+
end
|
32
|
+
|
33
|
+
should "expose a valid mongo connection" do
|
34
|
+
assert_instance_of Mongo::DB, @central_logger.mongo_connection
|
35
|
+
end
|
36
|
+
|
37
|
+
should "create a capped collection in the database with the configured size" do
|
38
|
+
@central_logger.send(:check_for_collection)
|
39
|
+
assert @con.collection_names.include?(@central_logger.mongo_collection_name)
|
40
|
+
# new capped collections are X MB + 5888 bytes, but don't be too strict in case that changes
|
41
|
+
assert @collection.stats["storageSize"] < CentralLogger::MongoLogger::DEFAULT_COLLECTION_SIZE + 1.megabyte
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "after instantiation" do
|
47
|
+
setup do
|
48
|
+
@central_logger = CentralLogger::MongoLogger.new
|
49
|
+
common_setup
|
50
|
+
end
|
51
|
+
|
52
|
+
context "upon insertion of a log record when active record is not used" do
|
53
|
+
# mock ActiveRecord has not been included
|
54
|
+
setup do
|
55
|
+
log("Test")
|
56
|
+
end
|
57
|
+
|
58
|
+
should_contain_one_log_record
|
59
|
+
|
60
|
+
should "allow recreation of the capped collection to remove all records" do
|
61
|
+
@central_logger.reset_collection
|
62
|
+
assert_equal 0, @collection.count
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "upon insertion of a colorized log record when ActiveRecord is used" do
|
67
|
+
setup do
|
68
|
+
@log_message = "TESTING"
|
69
|
+
require_bogus_active_record
|
70
|
+
@central_logger.reset_collection
|
71
|
+
log("\e[31m #{@log_message} \e[0m")
|
72
|
+
end
|
73
|
+
|
74
|
+
should "detect logging is colorized" do
|
75
|
+
assert @central_logger.send(:logging_colorized?)
|
76
|
+
end
|
77
|
+
|
78
|
+
should_contain_one_log_record
|
79
|
+
|
80
|
+
should "strip out colorization from log messages" do
|
81
|
+
assert_equal 1, @collection.find({"messages.debug" => @log_message}).count
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
should "add application metadata to the log record" do
|
86
|
+
options = {"application" => self.class.name}
|
87
|
+
log_metadata(options)
|
88
|
+
assert_equal 1, @collection.find({"application" => self.class.name}).count
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "logging at INFO level" do
|
93
|
+
setup do
|
94
|
+
@central_logger = CentralLogger::MongoLogger.new(:level => CentralLogger::MongoLogger::INFO)
|
95
|
+
@central_logger.reset_collection
|
96
|
+
common_setup
|
97
|
+
log("INFO")
|
98
|
+
end
|
99
|
+
|
100
|
+
should_contain_one_log_record
|
101
|
+
|
102
|
+
should "not log DEBUG messages" do
|
103
|
+
assert_equal 0, @collection.find_one({}, :fields => ["messages"])["messages"].count
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
metadata
ADDED
@@ -0,0 +1,222 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: central_logger
|
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
|
+
- Phil Burrows
|
13
|
+
- Alex Stupka
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-11-01 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rake
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: bundler
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ~>
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
segments:
|
43
|
+
- 1
|
44
|
+
- 0
|
45
|
+
- 0
|
46
|
+
version: 1.0.0
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: mongo
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
type: :runtime
|
61
|
+
version_requirements: *id003
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: bson_ext
|
64
|
+
prerelease: false
|
65
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
segments:
|
71
|
+
- 0
|
72
|
+
version: "0"
|
73
|
+
type: :runtime
|
74
|
+
version_requirements: *id004
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: jeweler
|
77
|
+
prerelease: false
|
78
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ~>
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
segments:
|
84
|
+
- 1
|
85
|
+
- 5
|
86
|
+
- 0
|
87
|
+
- pre5
|
88
|
+
version: 1.5.0.pre5
|
89
|
+
type: :development
|
90
|
+
version_requirements: *id005
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: shoulda
|
93
|
+
prerelease: false
|
94
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
segments:
|
100
|
+
- 0
|
101
|
+
version: "0"
|
102
|
+
type: :development
|
103
|
+
version_requirements: *id006
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: i18n
|
106
|
+
prerelease: false
|
107
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
108
|
+
none: false
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
segments:
|
113
|
+
- 0
|
114
|
+
version: "0"
|
115
|
+
type: :development
|
116
|
+
version_requirements: *id007
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: activesupport
|
119
|
+
prerelease: false
|
120
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
segments:
|
126
|
+
- 0
|
127
|
+
version: "0"
|
128
|
+
type: :development
|
129
|
+
version_requirements: *id008
|
130
|
+
- !ruby/object:Gem::Dependency
|
131
|
+
name: mocha
|
132
|
+
prerelease: false
|
133
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
segments:
|
139
|
+
- 0
|
140
|
+
version: "0"
|
141
|
+
type: :development
|
142
|
+
version_requirements: *id009
|
143
|
+
- !ruby/object:Gem::Dependency
|
144
|
+
name: ruby-debug19
|
145
|
+
prerelease: false
|
146
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
147
|
+
none: false
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
segments:
|
152
|
+
- 0
|
153
|
+
version: "0"
|
154
|
+
type: :development
|
155
|
+
version_requirements: *id010
|
156
|
+
description: Centralized logging for rails apps using MongoDB. The idea and the core code is from http://github.com/peburrows/central_logger
|
157
|
+
email: astupka@customink.com
|
158
|
+
executables: []
|
159
|
+
|
160
|
+
extensions: []
|
161
|
+
|
162
|
+
extra_rdoc_files:
|
163
|
+
- README.md
|
164
|
+
files:
|
165
|
+
- .rvmrc
|
166
|
+
- Gemfile
|
167
|
+
- Gemfile.lock
|
168
|
+
- MIT-LICENSE
|
169
|
+
- README.md
|
170
|
+
- Rakefile
|
171
|
+
- VERSION
|
172
|
+
- central_logger.gemspec
|
173
|
+
- lib/central_logger.rb
|
174
|
+
- lib/central_logger/filter.rb
|
175
|
+
- lib/central_logger/initializer.rb
|
176
|
+
- lib/central_logger/initializer_mixin.rb
|
177
|
+
- lib/central_logger/mongo_logger.rb
|
178
|
+
- lib/railtie.rb
|
179
|
+
- test/active_record.rb
|
180
|
+
- test/config/database.yml
|
181
|
+
- test/rails.rb
|
182
|
+
- test/shoulda_macros/log_macros.rb
|
183
|
+
- test/test_helper.rb
|
184
|
+
- test/unit/central_logger_test.rb
|
185
|
+
has_rdoc: true
|
186
|
+
homepage: http://github.com/customink/central_logger
|
187
|
+
licenses: []
|
188
|
+
|
189
|
+
post_install_message:
|
190
|
+
rdoc_options: []
|
191
|
+
|
192
|
+
require_paths:
|
193
|
+
- lib
|
194
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
195
|
+
none: false
|
196
|
+
requirements:
|
197
|
+
- - ">="
|
198
|
+
- !ruby/object:Gem::Version
|
199
|
+
segments:
|
200
|
+
- 0
|
201
|
+
version: "0"
|
202
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
203
|
+
none: false
|
204
|
+
requirements:
|
205
|
+
- - ">="
|
206
|
+
- !ruby/object:Gem::Version
|
207
|
+
segments:
|
208
|
+
- 0
|
209
|
+
version: "0"
|
210
|
+
requirements: []
|
211
|
+
|
212
|
+
rubyforge_project: central_logger
|
213
|
+
rubygems_version: 1.3.7
|
214
|
+
signing_key:
|
215
|
+
specification_version: 3
|
216
|
+
summary: Central Logger for Rails
|
217
|
+
test_files:
|
218
|
+
- test/active_record.rb
|
219
|
+
- test/rails.rb
|
220
|
+
- test/shoulda_macros/log_macros.rb
|
221
|
+
- test/test_helper.rb
|
222
|
+
- test/unit/central_logger_test.rb
|