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.
Files changed (118) hide show
  1. data/.gitignore +20 -0
  2. data/.rvmrc +1 -0
  3. data/.travis.yml +19 -0
  4. data/CHANGELOG.md +30 -0
  5. data/Gemfile +10 -0
  6. data/LICENSE +22 -0
  7. data/README.md +207 -0
  8. data/Rakefile +169 -0
  9. data/SUPPORTED_RAILS_VERSIONS +17 -0
  10. data/TESTING.md +24 -0
  11. data/bin/mongodb_logger_web +24 -0
  12. data/config.ru +17 -0
  13. data/examples/server_config.yml +5 -0
  14. data/features/mongodb_logger_web.feature +14 -0
  15. data/features/rails.feature +12 -0
  16. data/features/step_definitions/mongodb_logger_web_steps.rb +45 -0
  17. data/features/step_definitions/rails_application_steps.rb +65 -0
  18. data/features/support/env.rb +15 -0
  19. data/features/support/rails.rb +98 -0
  20. data/features/support/terminal.rb +95 -0
  21. data/lib/mongodb_logger/initializer_mixin.rb +26 -0
  22. data/lib/mongodb_logger/logger.rb +239 -0
  23. data/lib/mongodb_logger/railtie.rb +12 -0
  24. data/lib/mongodb_logger/replica_set_helper.rb +19 -0
  25. data/lib/mongodb_logger/server/coffee/logs.coffee +250 -0
  26. data/lib/mongodb_logger/server/content_for.rb +58 -0
  27. data/lib/mongodb_logger/server/model/additional_filter.rb +104 -0
  28. data/lib/mongodb_logger/server/model/analytic.rb +82 -0
  29. data/lib/mongodb_logger/server/model/filter.rb +84 -0
  30. data/lib/mongodb_logger/server/partials.rb +24 -0
  31. data/lib/mongodb_logger/server/public/images/arrow-down.png +0 -0
  32. data/lib/mongodb_logger/server/public/images/arrow-up.png +0 -0
  33. data/lib/mongodb_logger/server/public/images/date.png +0 -0
  34. data/lib/mongodb_logger/server/public/images/external.png +0 -0
  35. data/lib/mongodb_logger/server/public/images/failure.png +0 -0
  36. data/lib/mongodb_logger/server/public/images/logo.png +0 -0
  37. data/lib/mongodb_logger/server/public/images/mongodb.png +0 -0
  38. data/lib/mongodb_logger/server/public/images/newlog.png +0 -0
  39. data/lib/mongodb_logger/server/public/images/play-icon.png +0 -0
  40. data/lib/mongodb_logger/server/public/images/spinner.gif +0 -0
  41. data/lib/mongodb_logger/server/public/images/spinner2.gif +0 -0
  42. data/lib/mongodb_logger/server/public/images/stop-icon.png +0 -0
  43. data/lib/mongodb_logger/server/public/images/success.png +0 -0
  44. data/lib/mongodb_logger/server/public/javascripts/logs.js +1 -0
  45. data/lib/mongodb_logger/server/public/javascripts/vendors/highlight.pack.js +1 -0
  46. data/lib/mongodb_logger/server/public/javascripts/vendors/jquery-1.7.1.min.js +4 -0
  47. data/lib/mongodb_logger/server/public/javascripts/vendors/jquery-ui-1.8.16.min.js +791 -0
  48. data/lib/mongodb_logger/server/public/javascripts/vendors/jquery.pjax.min.js +6 -0
  49. data/lib/mongodb_logger/server/public/stylesheets/all.css +12 -0
  50. data/lib/mongodb_logger/server/public/stylesheets/grids.css +18 -0
  51. data/lib/mongodb_logger/server/public/stylesheets/group-buttons.css +81 -0
  52. data/lib/mongodb_logger/server/public/stylesheets/group-forms.css +59 -0
  53. data/lib/mongodb_logger/server/public/stylesheets/group-headers.css +8 -0
  54. data/lib/mongodb_logger/server/public/stylesheets/group-tables.css +87 -0
  55. data/lib/mongodb_logger/server/public/stylesheets/highlight/zenburn.css +115 -0
  56. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_flat_75_aaaaaa_40x100.png +0 -0
  57. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_glass_100_f5f0e5_1x400.png +0 -0
  58. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_glass_25_cb842e_1x400.png +0 -0
  59. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_glass_70_ede4d4_1x400.png +0 -0
  60. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_highlight-hard_100_f4f0ec_1x100.png +0 -0
  61. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_highlight-hard_65_fee4bd_1x100.png +0 -0
  62. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_highlight-hard_75_f5f5b5_1x100.png +0 -0
  63. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-bg_inset-soft_100_f4f0ec_1x100.png +0 -0
  64. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_c47a23_256x240.png +0 -0
  65. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_cb672b_256x240.png +0 -0
  66. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_f08000_256x240.png +0 -0
  67. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_f35f07_256x240.png +0 -0
  68. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_ff7519_256x240.png +0 -0
  69. data/lib/mongodb_logger/server/public/stylesheets/humanity/images/ui-icons_ffffff_256x240.png +0 -0
  70. data/lib/mongodb_logger/server/public/stylesheets/humanity/jquery-ui-1.8.16.custom.css +568 -0
  71. data/lib/mongodb_logger/server/public/stylesheets/layout.css +205 -0
  72. data/lib/mongodb_logger/server/public/stylesheets/library.css +330 -0
  73. data/lib/mongodb_logger/server/public/stylesheets/reset.css +43 -0
  74. data/lib/mongodb_logger/server/public/stylesheets/spaces.css +42 -0
  75. data/lib/mongodb_logger/server/view_helpers.rb +113 -0
  76. data/lib/mongodb_logger/server/views/analytics.erb +61 -0
  77. data/lib/mongodb_logger/server/views/error.erb +2 -0
  78. data/lib/mongodb_logger/server/views/layout.erb +47 -0
  79. data/lib/mongodb_logger/server/views/overview.erb +119 -0
  80. data/lib/mongodb_logger/server/views/shared/_collection_stats.erb +14 -0
  81. data/lib/mongodb_logger/server/views/shared/_dynamic_filter.erb +34 -0
  82. data/lib/mongodb_logger/server/views/shared/_log.erb +8 -0
  83. data/lib/mongodb_logger/server/views/shared/_log_info.erb +27 -0
  84. data/lib/mongodb_logger/server/views/shared/_message_tabs.erb +15 -0
  85. data/lib/mongodb_logger/server/views/shared/_tabs.erb +4 -0
  86. data/lib/mongodb_logger/server/views/shared/_tail_panel.erb +13 -0
  87. data/lib/mongodb_logger/server/views/shared/_top_panel.erb +7 -0
  88. data/lib/mongodb_logger/server/views/show_log.erb +105 -0
  89. data/lib/mongodb_logger/server.rb +174 -0
  90. data/lib/mongodb_logger/server_config.rb +77 -0
  91. data/lib/mongodb_logger/version.rb +3 -0
  92. data/lib/mongodb_logger.rb +31 -0
  93. data/mongodb_logger.gemspec +44 -0
  94. data/mongodb_logger.java.gemspec +42 -0
  95. data/spec/javascripts/MongodbLoggerMainSpec.js +13 -0
  96. data/spec/javascripts/helpers/SpecHelper.js +3 -0
  97. data/spec/javascripts/support/jasmine.yml +77 -0
  98. data/spec/javascripts/support/jasmine_config.rb +23 -0
  99. data/spec/javascripts/support/jasmine_runner.rb +32 -0
  100. data/test/active_record.rb +13 -0
  101. data/test/config/samples/database.yml +9 -0
  102. data/test/config/samples/database_no_file_logging.yml +10 -0
  103. data/test/config/samples/database_replica_set.yml +12 -0
  104. data/test/config/samples/database_with_auth.yml +9 -0
  105. data/test/config/samples/database_with_collection.yml +8 -0
  106. data/test/config/samples/mongodb_logger.yml +2 -0
  107. data/test/config/samples/mongoid.yml +30 -0
  108. data/test/config/samples/server_config.yml +3 -0
  109. data/test/rails/app/controllers/order_controller.rb +23 -0
  110. data/test/rails/test/functional/order_controller_test.rb +116 -0
  111. data/test/rails/test/test_helper.rb +10 -0
  112. data/test/rails.rb +22 -0
  113. data/test/shoulda_macros/log_macros.rb +13 -0
  114. data/test/test.sh +6 -0
  115. data/test/test_helper.rb +89 -0
  116. data/test/unit/mongodb_logger_replica_test.rb +56 -0
  117. data/test/unit/mongodb_logger_test.rb +270 -0
  118. 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