mongodb_logger 0.2.6-jruby
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/.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
|