mongodb_logger 0.2.6-jruby
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +20 -0
- data/.rvmrc +1 -0
- data/.travis.yml +19 -0
- data/CHANGELOG.md +30 -0
- data/Gemfile +10 -0
- data/LICENSE +22 -0
- data/README.md +207 -0
- data/Rakefile +169 -0
- data/SUPPORTED_RAILS_VERSIONS +17 -0
- data/TESTING.md +24 -0
- data/bin/mongodb_logger_web +24 -0
- data/config.ru +17 -0
- data/examples/server_config.yml +5 -0
- data/features/mongodb_logger_web.feature +14 -0
- data/features/rails.feature +12 -0
- data/features/step_definitions/mongodb_logger_web_steps.rb +45 -0
- data/features/step_definitions/rails_application_steps.rb +65 -0
- data/features/support/env.rb +15 -0
- data/features/support/rails.rb +98 -0
- data/features/support/terminal.rb +95 -0
- data/lib/mongodb_logger/initializer_mixin.rb +26 -0
- data/lib/mongodb_logger/logger.rb +239 -0
- data/lib/mongodb_logger/railtie.rb +12 -0
- data/lib/mongodb_logger/replica_set_helper.rb +19 -0
- data/lib/mongodb_logger/server/coffee/logs.coffee +250 -0
- data/lib/mongodb_logger/server/content_for.rb +58 -0
- data/lib/mongodb_logger/server/model/additional_filter.rb +104 -0
- data/lib/mongodb_logger/server/model/analytic.rb +82 -0
- data/lib/mongodb_logger/server/model/filter.rb +84 -0
- data/lib/mongodb_logger/server/partials.rb +24 -0
- data/lib/mongodb_logger/server/public/images/arrow-down.png +0 -0
- data/lib/mongodb_logger/server/public/images/arrow-up.png +0 -0
- data/lib/mongodb_logger/server/public/images/date.png +0 -0
- data/lib/mongodb_logger/server/public/images/external.png +0 -0
- data/lib/mongodb_logger/server/public/images/failure.png +0 -0
- data/lib/mongodb_logger/server/public/images/logo.png +0 -0
- data/lib/mongodb_logger/server/public/images/mongodb.png +0 -0
- data/lib/mongodb_logger/server/public/images/newlog.png +0 -0
- data/lib/mongodb_logger/server/public/images/play-icon.png +0 -0
- data/lib/mongodb_logger/server/public/images/spinner.gif +0 -0
- data/lib/mongodb_logger/server/public/images/spinner2.gif +0 -0
- data/lib/mongodb_logger/server/public/images/stop-icon.png +0 -0
- data/lib/mongodb_logger/server/public/images/success.png +0 -0
- data/lib/mongodb_logger/server/public/javascripts/logs.js +1 -0
- data/lib/mongodb_logger/server/public/javascripts/vendors/highlight.pack.js +1 -0
- data/lib/mongodb_logger/server/public/javascripts/vendors/jquery-1.7.1.min.js +4 -0
- data/lib/mongodb_logger/server/public/javascripts/vendors/jquery-ui-1.8.16.min.js +791 -0
- data/lib/mongodb_logger/server/public/javascripts/vendors/jquery.pjax.min.js +6 -0
- data/lib/mongodb_logger/server/public/stylesheets/all.css +12 -0
- data/lib/mongodb_logger/server/public/stylesheets/grids.css +18 -0
- data/lib/mongodb_logger/server/public/stylesheets/group-buttons.css +81 -0
- data/lib/mongodb_logger/server/public/stylesheets/group-forms.css +59 -0
- data/lib/mongodb_logger/server/public/stylesheets/group-headers.css +8 -0
- data/lib/mongodb_logger/server/public/stylesheets/group-tables.css +87 -0
- data/lib/mongodb_logger/server/public/stylesheets/highlight/zenburn.css +115 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_flat_75_aaaaaa_40x100.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_glass_100_f5f0e5_1x400.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_glass_25_cb842e_1x400.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_glass_70_ede4d4_1x400.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_highlight-hard_100_f4f0ec_1x100.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_highlight-hard_65_fee4bd_1x100.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_highlight-hard_75_f5f5b5_1x100.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_inset-soft_100_f4f0ec_1x100.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_c47a23_256x240.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_cb672b_256x240.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_f08000_256x240.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_f35f07_256x240.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_ff7519_256x240.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_ffffff_256x240.png +0 -0
- data/lib/mongodb_logger/server/public/stylesheets/humanity/jquery-ui-1.8.16.custom.css +568 -0
- data/lib/mongodb_logger/server/public/stylesheets/layout.css +205 -0
- data/lib/mongodb_logger/server/public/stylesheets/library.css +330 -0
- data/lib/mongodb_logger/server/public/stylesheets/reset.css +43 -0
- data/lib/mongodb_logger/server/public/stylesheets/spaces.css +42 -0
- data/lib/mongodb_logger/server/view_helpers.rb +113 -0
- data/lib/mongodb_logger/server/views/analytics.erb +61 -0
- data/lib/mongodb_logger/server/views/error.erb +2 -0
- data/lib/mongodb_logger/server/views/layout.erb +47 -0
- data/lib/mongodb_logger/server/views/overview.erb +119 -0
- data/lib/mongodb_logger/server/views/shared/_collection_stats.erb +14 -0
- data/lib/mongodb_logger/server/views/shared/_dynamic_filter.erb +34 -0
- data/lib/mongodb_logger/server/views/shared/_log.erb +8 -0
- data/lib/mongodb_logger/server/views/shared/_log_info.erb +27 -0
- data/lib/mongodb_logger/server/views/shared/_message_tabs.erb +15 -0
- data/lib/mongodb_logger/server/views/shared/_tabs.erb +4 -0
- data/lib/mongodb_logger/server/views/shared/_tail_panel.erb +13 -0
- data/lib/mongodb_logger/server/views/shared/_top_panel.erb +7 -0
- data/lib/mongodb_logger/server/views/show_log.erb +105 -0
- data/lib/mongodb_logger/server.rb +174 -0
- data/lib/mongodb_logger/server_config.rb +77 -0
- data/lib/mongodb_logger/version.rb +3 -0
- data/lib/mongodb_logger.rb +31 -0
- data/mongodb_logger.gemspec +44 -0
- data/mongodb_logger.java.gemspec +42 -0
- data/spec/javascripts/MongodbLoggerMainSpec.js +13 -0
- data/spec/javascripts/helpers/SpecHelper.js +3 -0
- data/spec/javascripts/support/jasmine.yml +77 -0
- data/spec/javascripts/support/jasmine_config.rb +23 -0
- data/spec/javascripts/support/jasmine_runner.rb +32 -0
- data/test/active_record.rb +13 -0
- data/test/config/samples/database.yml +9 -0
- data/test/config/samples/database_no_file_logging.yml +10 -0
- data/test/config/samples/database_replica_set.yml +12 -0
- data/test/config/samples/database_with_auth.yml +9 -0
- data/test/config/samples/database_with_collection.yml +8 -0
- data/test/config/samples/mongodb_logger.yml +2 -0
- data/test/config/samples/mongoid.yml +30 -0
- data/test/config/samples/server_config.yml +3 -0
- data/test/rails/app/controllers/order_controller.rb +23 -0
- data/test/rails/test/functional/order_controller_test.rb +116 -0
- data/test/rails/test/test_helper.rb +10 -0
- data/test/rails.rb +22 -0
- data/test/shoulda_macros/log_macros.rb +13 -0
- data/test/test.sh +6 -0
- data/test/test_helper.rb +89 -0
- data/test/unit/mongodb_logger_replica_test.rb +56 -0
- data/test/unit/mongodb_logger_test.rb +270 -0
- metadata +383 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'active_support/core_ext/string/inflections'
|
2
|
+
|
3
|
+
Given /^I have built and installed the "([^\"]*)" gem$/ do |gem_name|
|
4
|
+
@terminal.build_and_install_gem(File.join(PROJECT_ROOT, "#{gem_name}.gemspec"))
|
5
|
+
end
|
6
|
+
|
7
|
+
When /^I generate a new Rails application$/ do
|
8
|
+
@terminal.cd(TEMP_DIR)
|
9
|
+
version_string = ENV['RAILS_VERSION']
|
10
|
+
rails_create_command = 'new'
|
11
|
+
|
12
|
+
rails_dir_search = (version_string =~ /^3.(0|1)/) ? "rails" : "railties"
|
13
|
+
|
14
|
+
load_rails = <<-RUBY
|
15
|
+
gem "rails", "#{version_string}"; \
|
16
|
+
load Gem.bin_path("#{rails_dir_search}", "rails", "#{version_string}")
|
17
|
+
RUBY
|
18
|
+
|
19
|
+
@terminal.run(%{ruby -rrubygems -rthread -e "#{load_rails.gsub("\"", "\\\"").strip!}" #{rails_create_command} rails_root})
|
20
|
+
if rails_root_exists?
|
21
|
+
@terminal.echo("Generated a Rails #{version_string} application")
|
22
|
+
else
|
23
|
+
raise "Unable to generate a Rails application:\n#{@terminal.output}"
|
24
|
+
end
|
25
|
+
#require_thread if rails30?
|
26
|
+
end
|
27
|
+
|
28
|
+
When /^I configure my application to require the "([^\"]*)" gem(?: with version "(.+)")?$/ do |gem_name, version|
|
29
|
+
bundle_gem(gem_name, version)
|
30
|
+
end
|
31
|
+
|
32
|
+
When /^I setup mongodb_logger tests$/ do
|
33
|
+
copy_tests
|
34
|
+
add_routes
|
35
|
+
end
|
36
|
+
|
37
|
+
When /^I setup all gems for rails$/ do
|
38
|
+
bundle_gem("therubyracer", nil) if rails31?
|
39
|
+
step %{I run "bundle install"}
|
40
|
+
@terminal.status.exitstatus.should == 0
|
41
|
+
end
|
42
|
+
|
43
|
+
When /^I prepare rails environment for testing$/ do
|
44
|
+
step %{I run "rake db:create db:migrate RAILS_ENV=test --trace"}
|
45
|
+
@terminal.status.exitstatus.should == 0
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
Then /^the tests should have run successfully$/ do
|
50
|
+
step %{I run "rake test RAILS_ENV=test --trace"}
|
51
|
+
@terminal.status.exitstatus.should == 0
|
52
|
+
# show errors
|
53
|
+
output_log = @terminal.output
|
54
|
+
is_pass = false
|
55
|
+
# TODO: fix regexp later, because can PASS in 10 or 100 failures
|
56
|
+
is_pass = true if ((1 == output_log.scan(/([.*]?)fail: 0(\D+)error: 0([\D+]?)/i).size) || (1 == output_log.scan(/(.*)0 failures(.*)0 errors(.*)/i).size))
|
57
|
+
puts @terminal.output unless is_pass
|
58
|
+
# check if have errors
|
59
|
+
is_pass.should == true
|
60
|
+
end
|
61
|
+
|
62
|
+
When /^I run "([^\"]*)"$/ do |command|
|
63
|
+
@terminal.cd(rails_root)
|
64
|
+
@terminal.run(command)
|
65
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'rspec'
|
3
|
+
|
4
|
+
PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..')).freeze
|
5
|
+
TEMP_DIR = File.join(PROJECT_ROOT, 'tmp').freeze
|
6
|
+
LOCAL_RAILS_ROOT = File.join(TEMP_DIR, 'rails_root').freeze
|
7
|
+
BUILT_GEM_ROOT = File.join(TEMP_DIR, 'built_gems').freeze
|
8
|
+
LOCAL_GEM_ROOT = File.join(TEMP_DIR, 'local_gems').freeze
|
9
|
+
|
10
|
+
Before do
|
11
|
+
FileUtils.mkdir_p(TEMP_DIR)
|
12
|
+
FileUtils.rm_rf(BUILT_GEM_ROOT)
|
13
|
+
FileUtils.rm_rf(LOCAL_RAILS_ROOT)
|
14
|
+
FileUtils.mkdir_p(BUILT_GEM_ROOT)
|
15
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module RailsHelpers
|
2
|
+
def rails_root_exists?
|
3
|
+
File.exists?(environment_path)
|
4
|
+
end
|
5
|
+
|
6
|
+
def environment_path
|
7
|
+
File.join(rails_root, 'config', 'environment.rb')
|
8
|
+
end
|
9
|
+
|
10
|
+
def application_controller_filename
|
11
|
+
controller_filename = File.join(rails_root, 'app', 'controllers', "application_controller.rb")
|
12
|
+
end
|
13
|
+
|
14
|
+
def rails_root
|
15
|
+
LOCAL_RAILS_ROOT
|
16
|
+
end
|
17
|
+
|
18
|
+
def rails30?
|
19
|
+
rails_version =~ /^3.0/
|
20
|
+
end
|
21
|
+
|
22
|
+
def rails31?
|
23
|
+
rails_version =~ /^3.1/
|
24
|
+
end
|
25
|
+
|
26
|
+
def rails_version
|
27
|
+
@rails_version ||= begin
|
28
|
+
rails_version = open(gemfile_path).read.match(/gem.*rails["'].*["'](.+)["']/)[1]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def gemfile_path
|
33
|
+
File.join(rails_root, 'Gemfile')
|
34
|
+
end
|
35
|
+
|
36
|
+
def rakefile_path
|
37
|
+
File.join(rails_root, 'Rakefile')
|
38
|
+
end
|
39
|
+
|
40
|
+
def routes_path
|
41
|
+
File.join(rails_root, 'config', 'routes.rb')
|
42
|
+
end
|
43
|
+
|
44
|
+
def logs_path
|
45
|
+
File.join(rails_root, 'log')
|
46
|
+
end
|
47
|
+
|
48
|
+
def bundle_gem(gem_name, version = nil)
|
49
|
+
File.open(gemfile_path, 'a') do |file|
|
50
|
+
gem = "gem '#{gem_name}'"
|
51
|
+
gem += ", '#{version}'" if version
|
52
|
+
file.puts(gem)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def require_thread
|
57
|
+
content = File.read(rakefile_path)
|
58
|
+
content = "require 'thread'\n#{content}"
|
59
|
+
File.open(rakefile_path, 'wb') { |file| file.write(content) }
|
60
|
+
end
|
61
|
+
|
62
|
+
def add_routes
|
63
|
+
content = File.read(routes_path)
|
64
|
+
flag = Regexp.escape("Application.routes.draw do\n")
|
65
|
+
order_routes = <<STR
|
66
|
+
resources :order do
|
67
|
+
collection do
|
68
|
+
post :test_post
|
69
|
+
end
|
70
|
+
end
|
71
|
+
STR
|
72
|
+
content.gsub!(/#{flag}/m, '\0 ' + order_routes)
|
73
|
+
File.open(routes_path, 'wb') { |file| file.write(content) }
|
74
|
+
end
|
75
|
+
|
76
|
+
def copy_tests
|
77
|
+
FileUtils.cp(
|
78
|
+
File.join(PROJECT_ROOT, 'test', 'rails', 'app', 'controllers', 'order_controller.rb'),
|
79
|
+
File.join(rails_root, 'app', 'controllers', 'order_controller.rb')
|
80
|
+
)
|
81
|
+
FileUtils.cp(
|
82
|
+
File.join(PROJECT_ROOT, 'test', 'config', 'samples', 'database.yml'),
|
83
|
+
File.join(rails_root, 'config', 'database.yml')
|
84
|
+
)
|
85
|
+
FileUtils.cp(
|
86
|
+
File.join(PROJECT_ROOT, 'test', 'rails', 'test', 'test_helper.rb'),
|
87
|
+
File.join(rails_root, 'test', 'test_helper.rb')
|
88
|
+
)
|
89
|
+
FileUtils.cp(
|
90
|
+
File.join(PROJECT_ROOT, 'test', 'rails', 'test', 'functional', 'order_controller_test.rb'),
|
91
|
+
File.join(rails_root, 'test', 'functional', 'order_controller_test.rb')
|
92
|
+
)
|
93
|
+
FileUtils.chmod 0777, logs_path
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
World(RailsHelpers)
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
Before do
|
4
|
+
@terminal = Terminal.new
|
5
|
+
end
|
6
|
+
|
7
|
+
After do |story|
|
8
|
+
if story.failed?
|
9
|
+
# puts @terminal.output
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Terminal
|
14
|
+
attr_reader :output, :status
|
15
|
+
attr_accessor :environment_variables
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@cwd = FileUtils.pwd
|
19
|
+
@output = ""
|
20
|
+
@status = 0
|
21
|
+
@logger = Logger.new(File.join(TEMP_DIR, 'terminal.log'))
|
22
|
+
|
23
|
+
@environment_variables = {
|
24
|
+
"GEM_HOME" => LOCAL_GEM_ROOT,
|
25
|
+
"GEM_PATH" => "#{LOCAL_GEM_ROOT}:#{BUILT_GEM_ROOT}",
|
26
|
+
"PATH" => "#{gem_bin_path}:#{ENV['PATH']}",
|
27
|
+
"BUNDLE_GEMFILE" => File.join(LOCAL_RAILS_ROOT, 'Gemfile')
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def cd(directory)
|
32
|
+
@cwd = directory
|
33
|
+
end
|
34
|
+
|
35
|
+
def run(command)
|
36
|
+
output << "#{command}\n"
|
37
|
+
current_dir = FileUtils.pwd
|
38
|
+
|
39
|
+
# The ; forces ruby to shell out so the env settings work right
|
40
|
+
cmdline = "sh -c 'cd #{@cwd} && #{environment_settings} #{command} 2>&1 ; '"
|
41
|
+
logger.debug(cmdline)
|
42
|
+
result = `#{cmdline}`
|
43
|
+
logger.debug(result)
|
44
|
+
output << result
|
45
|
+
|
46
|
+
`sh -c 'cd #{current_dir}'`
|
47
|
+
@status = $?
|
48
|
+
end
|
49
|
+
|
50
|
+
def echo(string)
|
51
|
+
logger.debug(string)
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def build_and_install_gem(gemspec)
|
56
|
+
pkg_dir = File.join(TEMP_DIR, 'pkg')
|
57
|
+
FileUtils.mkdir_p(pkg_dir)
|
58
|
+
output = `gem build #{gemspec} 2>&1`
|
59
|
+
gem_file = Dir.glob("*.gem").first
|
60
|
+
unless gem_file
|
61
|
+
raise "Gem didn't build:\n#{output}"
|
62
|
+
end
|
63
|
+
target = File.join(pkg_dir, gem_file)
|
64
|
+
FileUtils.mv(gem_file, target)
|
65
|
+
install_gem_to(LOCAL_GEM_ROOT, target)
|
66
|
+
end
|
67
|
+
|
68
|
+
def install_gem(gem)
|
69
|
+
install_gem_to(LOCAL_GEM_ROOT, gem)
|
70
|
+
end
|
71
|
+
|
72
|
+
def uninstall_gem(gem)
|
73
|
+
`gem uninstall -i #{LOCAL_GEM_ROOT} #{gem}`
|
74
|
+
end
|
75
|
+
|
76
|
+
def prepend_path(path)
|
77
|
+
@environment_variables['PATH'] = path + ":" + @environment_variables['PATH']
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def install_gem_to(root, gem)
|
83
|
+
`gem install -i #{root} --no-ri --no-rdoc #{gem}`
|
84
|
+
end
|
85
|
+
|
86
|
+
def environment_settings
|
87
|
+
@environment_variables.map { |key, value| "#{key}=#{value}" }.join(' ')
|
88
|
+
end
|
89
|
+
|
90
|
+
def gem_bin_path
|
91
|
+
File.join(LOCAL_GEM_ROOT, "bin")
|
92
|
+
end
|
93
|
+
|
94
|
+
attr_reader :logger
|
95
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module MongodbLogger
|
2
|
+
module InitializerMixin
|
3
|
+
|
4
|
+
def rails30?
|
5
|
+
3 == Rails::VERSION::MAJOR && 0 == Rails::VERSION::MINOR
|
6
|
+
end
|
7
|
+
|
8
|
+
def create_logger(config)
|
9
|
+
path = rails30? ? config.paths.log.to_a.first : config.paths['log'].first
|
10
|
+
level = ActiveSupport::BufferedLogger.const_get(config.log_level.to_s.upcase)
|
11
|
+
logger = MongodbLogger::Logger.new(:path => path, :level => level)
|
12
|
+
logger.auto_flushing = false if Rails.env.production?
|
13
|
+
logger
|
14
|
+
rescue StandardError => e
|
15
|
+
logger = ActiveSupport::BufferedLogger.new(STDERR)
|
16
|
+
logger.level = ActiveSupport::BufferedLogger::WARN
|
17
|
+
logger.warn(
|
18
|
+
"MongodbLogger Initializer Error: Unable to access log file. Please ensure that #{path} exists and is chmod 0666. " +
|
19
|
+
"The log level has been raised to WARN and the output directed to STDERR until the problem is fixed." + "\n" +
|
20
|
+
e.message + "\n" + e.backtrace.join("\n")
|
21
|
+
)
|
22
|
+
logger
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,239 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'mongo'
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_support/core_ext'
|
5
|
+
require 'action_dispatch/http/upload'
|
6
|
+
require 'mongodb_logger/replica_set_helper'
|
7
|
+
|
8
|
+
module MongodbLogger
|
9
|
+
class Logger < ActiveSupport::BufferedLogger
|
10
|
+
include ReplicaSetHelper
|
11
|
+
|
12
|
+
DEFAULT_COLLECTION_SIZE = 250.megabytes
|
13
|
+
# Looks for configuration files in this order
|
14
|
+
CONFIGURATION_FILES = ["mongodb_logger.yml", "mongoid.yml", "database.yml"]
|
15
|
+
LOG_LEVEL_SYM = [:debug, :info, :warn, :error, :fatal, :unknown]
|
16
|
+
|
17
|
+
attr_reader :db_configuration, :mongo_connection, :mongo_collection_name, :mongo_collection, :mongo_connection_type
|
18
|
+
|
19
|
+
def initialize(options={})
|
20
|
+
path = options[:path] || File.join(Rails.root, "log/#{Rails.env}.log")
|
21
|
+
level = options[:level] || DEBUG
|
22
|
+
internal_initialize
|
23
|
+
rescue => e
|
24
|
+
# should use a config block for this
|
25
|
+
Rails.env.production? ? (raise e) : (puts "MongodbLogger WARNING: Using BufferedLogger due to exception: " + e.message)
|
26
|
+
ensure
|
27
|
+
if disable_file_logging?
|
28
|
+
@level = level
|
29
|
+
@buffer = {}
|
30
|
+
@auto_flushing = 1
|
31
|
+
@guard = Mutex.new
|
32
|
+
else
|
33
|
+
super(path, level)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_metadata(options={})
|
38
|
+
options.each do |key, value|
|
39
|
+
unless [:messages, :request_time, :ip, :runtime, :application_name, :is_exception, :params, :method].include?(key.to_sym)
|
40
|
+
@mongo_record[key] = value
|
41
|
+
else
|
42
|
+
raise ArgumentError, ":#{key} is a reserved key for the mongodb logger. Please choose a different key"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def add(severity, message = nil, progname = nil, &block)
|
48
|
+
if @level && @level <= severity && message.present? && @mongo_record.present?
|
49
|
+
# do not modify the original message used by the buffered logger
|
50
|
+
msg = logging_colorized? ? message.to_s.gsub(/(\e(\[([\d;]*[mz]?))?)?/, '').strip : message
|
51
|
+
@mongo_record[:messages][LOG_LEVEL_SYM[severity]] << msg
|
52
|
+
end
|
53
|
+
# may modify the original message
|
54
|
+
disable_file_logging? ? message : (@level ? super : message)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Drop the capped_collection and recreate it
|
58
|
+
def reset_collection
|
59
|
+
if @mongo_connection && @mongo_collection
|
60
|
+
@mongo_collection.drop
|
61
|
+
create_collection
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def mongoize(options={})
|
66
|
+
@mongo_record = options.merge({
|
67
|
+
:messages => Hash.new { |hash, key| hash[key] = Array.new },
|
68
|
+
:request_time => Time.now.getutc,
|
69
|
+
:application_name => @application_name
|
70
|
+
})
|
71
|
+
|
72
|
+
runtime = Benchmark.measure{ yield }.real if block_given?
|
73
|
+
rescue Exception => e
|
74
|
+
add(3, e.message + "\n" + e.backtrace.join("\n"))
|
75
|
+
# log exceptions
|
76
|
+
@mongo_record[:is_exception] = true
|
77
|
+
# Reraise the exception for anyone else who cares
|
78
|
+
raise e
|
79
|
+
ensure
|
80
|
+
# In case of exception, make sure runtime is set
|
81
|
+
@mongo_record[:runtime] = ((runtime ||= 0) * 1000).ceil
|
82
|
+
begin
|
83
|
+
@insert_block.call
|
84
|
+
rescue
|
85
|
+
begin
|
86
|
+
# try to nice serialize record
|
87
|
+
nice_serialize @mongo_record
|
88
|
+
@insert_block.call
|
89
|
+
rescue
|
90
|
+
# do extra work to inpect (and flatten)
|
91
|
+
force_serialize @mongo_record
|
92
|
+
@insert_block.call rescue nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def authenticated?
|
98
|
+
@authenticated
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
# facilitate testing
|
103
|
+
def internal_initialize
|
104
|
+
configure
|
105
|
+
connect
|
106
|
+
check_for_collection
|
107
|
+
end
|
108
|
+
|
109
|
+
def disable_file_logging?
|
110
|
+
@db_configuration.fetch('disable_file_logging', false)
|
111
|
+
end
|
112
|
+
|
113
|
+
def configure
|
114
|
+
default_capsize = DEFAULT_COLLECTION_SIZE
|
115
|
+
@authenticated = false
|
116
|
+
@db_configuration = {
|
117
|
+
'host' => 'localhost',
|
118
|
+
'port' => 27017,
|
119
|
+
'capsize' => default_capsize}.merge(resolve_config)
|
120
|
+
@mongo_collection_name = @db_configuration['collection'] || "#{Rails.env}_log"
|
121
|
+
@application_name = resolve_application_name
|
122
|
+
@safe_insert = @db_configuration['safe_insert'] || false
|
123
|
+
|
124
|
+
@insert_block = @db_configuration.has_key?('replica_set') && @db_configuration['replica_set'] ?
|
125
|
+
lambda { rescue_connection_failure{ insert_log_record(@safe_insert) } } :
|
126
|
+
lambda { insert_log_record }
|
127
|
+
end
|
128
|
+
|
129
|
+
def resolve_application_name
|
130
|
+
if @db_configuration.has_key?('application_name')
|
131
|
+
@db_configuration['application_name']
|
132
|
+
else
|
133
|
+
Rails.application.class.to_s.split("::").first
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def resolve_config
|
138
|
+
config = {}
|
139
|
+
CONFIGURATION_FILES.each do |filename|
|
140
|
+
config_file = Rails.root.join("config", filename)
|
141
|
+
if config_file.file?
|
142
|
+
config = YAML.load(ERB.new(config_file.read).result)[Rails.env]
|
143
|
+
config = config['mongodb_logger'] if config && config.has_key?('mongodb_logger')
|
144
|
+
break unless config.blank?
|
145
|
+
end
|
146
|
+
end
|
147
|
+
config
|
148
|
+
end
|
149
|
+
|
150
|
+
def mongo_connection_object
|
151
|
+
if @db_configuration['hosts']
|
152
|
+
conn = Mongo::ReplSetConnection.new(*(@db_configuration['hosts'] <<
|
153
|
+
{:auto_reconnect => true, :pool_timeout => 6}))
|
154
|
+
@db_configuration['replica_set'] = true
|
155
|
+
else
|
156
|
+
conn = Mongo::Connection.new(@db_configuration['host'],
|
157
|
+
@db_configuration['port'],
|
158
|
+
:auto_reconnect => true,
|
159
|
+
:pool_timeout => 6)
|
160
|
+
end
|
161
|
+
@mongo_connection_type = conn.class
|
162
|
+
conn
|
163
|
+
end
|
164
|
+
|
165
|
+
def connect
|
166
|
+
@mongo_connection ||= mongo_connection_object.db(@db_configuration['database'])
|
167
|
+
if @db_configuration['username'] && @db_configuration['password']
|
168
|
+
# the driver stores credentials in case reconnection is required
|
169
|
+
@authenticated = @mongo_connection.authenticate(@db_configuration['username'],
|
170
|
+
@db_configuration['password'])
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def create_collection
|
175
|
+
@mongo_connection.create_collection(@mongo_collection_name,
|
176
|
+
{:capped => true, :size => @db_configuration['capsize'].to_i})
|
177
|
+
end
|
178
|
+
|
179
|
+
def check_for_collection
|
180
|
+
# setup the capped collection if it doesn't already exist
|
181
|
+
create_collection unless @mongo_connection.collection_names.include?(@mongo_collection_name)
|
182
|
+
@mongo_collection = @mongo_connection[@mongo_collection_name]
|
183
|
+
end
|
184
|
+
|
185
|
+
def insert_log_record(safe = false)
|
186
|
+
@mongo_collection.insert(@mongo_record, :safe => safe)
|
187
|
+
end
|
188
|
+
|
189
|
+
def logging_colorized?
|
190
|
+
# Cache it since these ActiveRecord attributes are assigned after logger initialization occurs in Rails boot
|
191
|
+
@colorized ||= Object.const_defined?(:ActiveRecord) && ActiveRecord::LogSubscriber.colorize_logging
|
192
|
+
end
|
193
|
+
|
194
|
+
# try to serialyze data by each key and found invalid object
|
195
|
+
def nice_serialize(rec)
|
196
|
+
if msgs = rec[:messages]
|
197
|
+
msgs.each do |i, j|
|
198
|
+
msgs[i] = nice_serialize_object(j)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
if pms = rec[:params]
|
202
|
+
pms.each do |i, j|
|
203
|
+
pms[i] = nice_serialize_object(j)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def nice_serialize_object(data)
|
209
|
+
case data
|
210
|
+
when NilClass, String, Fixnum, Bignum, Float, TrueClass, FalseClass, Time, Regexp, Symbol
|
211
|
+
data
|
212
|
+
when Hash
|
213
|
+
hvalues = Hash.new
|
214
|
+
data.each{|k,v| hvalues[k] = nice_serialize_object(v) }
|
215
|
+
hvalues
|
216
|
+
when Array
|
217
|
+
data.map{|v| nice_serialize_object(v) }
|
218
|
+
when ActionDispatch::Http::UploadedFile, Rack::Test::UploadedFile # uploaded files
|
219
|
+
hvalues = {
|
220
|
+
:original_filename => data.original_filename,
|
221
|
+
:content_type => data.content_type
|
222
|
+
}
|
223
|
+
else
|
224
|
+
data.inspect
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# force the data in the db by inspecting each top level array and hash element
|
229
|
+
# this will flatten other hashes and arrays
|
230
|
+
def force_serialize(rec)
|
231
|
+
if msgs = rec[:messages]
|
232
|
+
msgs.each { |i, j| msgs[i] = j.inspect }
|
233
|
+
end
|
234
|
+
if pms = rec[:params]
|
235
|
+
pms.each { |i, j| pms[i] = j.inspect }
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'mongodb_logger/initializer_mixin'
|
2
|
+
module MongodbLogger
|
3
|
+
class Railtie < Rails::Railtie
|
4
|
+
include MongodbLogger::InitializerMixin
|
5
|
+
|
6
|
+
initializer :initialize_mongodb_logger, :before => :initialize_logger do
|
7
|
+
app_config = Rails.application.config
|
8
|
+
Rails.logger = config.logger = create_logger(app_config)
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module MongodbLogger
|
2
|
+
module ReplicaSetHelper
|
3
|
+
# Use retry alg from mongodb to gobble up connection failures during replica set master vote
|
4
|
+
# Defaults to a 10 second wait
|
5
|
+
def rescue_connection_failure(max_retries=40)
|
6
|
+
success = false
|
7
|
+
retries = 0
|
8
|
+
while !success
|
9
|
+
begin
|
10
|
+
yield
|
11
|
+
success = true
|
12
|
+
rescue Mongo::ConnectionFailure => e
|
13
|
+
raise e if (retries += 1) >= max_retries
|
14
|
+
sleep 0.25
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|