influxdb-rails 0.0.1

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 (45) hide show
  1. checksums.yaml +15 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +95 -0
  4. data/README.md +3 -0
  5. data/Rakefile +34 -0
  6. data/config.ru +7 -0
  7. data/gemfiles/Gemfile.rails-3.0.x +8 -0
  8. data/gemfiles/Gemfile.rails-3.0.x.lock +94 -0
  9. data/gemfiles/Gemfile.rails-3.1.x +8 -0
  10. data/gemfiles/Gemfile.rails-3.1.x.lock +121 -0
  11. data/gemfiles/Gemfile.rails-3.2.x +8 -0
  12. data/gemfiles/Gemfile.rails-3.2.x.lock +104 -0
  13. data/gemfiles/Gemfile.rails-4.0.x +8 -0
  14. data/gemfiles/Gemfile.rails-4.0.x.lock +109 -0
  15. data/generators/influxdb/influxdb_generator.rb +48 -0
  16. data/generators/influxdb/templates/initializer.rb +5 -0
  17. data/influxdb-rails.gemspec +33 -0
  18. data/lib/influxdb-rails.rb +82 -0
  19. data/lib/influxdb/rails/air_traffic_controller.rb +39 -0
  20. data/lib/influxdb/rails/backtrace.rb +44 -0
  21. data/lib/influxdb/rails/configuration.rb +117 -0
  22. data/lib/influxdb/rails/exception_presenter.rb +90 -0
  23. data/lib/influxdb/rails/instrumentation.rb +27 -0
  24. data/lib/influxdb/rails/logger.rb +13 -0
  25. data/lib/influxdb/rails/middleware/hijack_render_exception.rb +21 -0
  26. data/lib/influxdb/rails/middleware/hijack_rescue_action_everywhere.rb +32 -0
  27. data/lib/influxdb/rails/rack.rb +28 -0
  28. data/lib/influxdb/rails/rails.rb +39 -0
  29. data/lib/influxdb/rails/railtie.rb +67 -0
  30. data/lib/influxdb/rails/version.rb +5 -0
  31. data/lib/rails/generators/influxdb/influxdb_generator.rb +52 -0
  32. data/lib/rails/generators/influxdb/templates/initializer.rb +4 -0
  33. data/spec/controllers/widgets_controller_spec.rb +15 -0
  34. data/spec/integration/exceptions_spec.rb +37 -0
  35. data/spec/integration/integration_helper.rb +1 -0
  36. data/spec/spec_helper.rb +29 -0
  37. data/spec/suite.sh +42 -0
  38. data/spec/support/rails3/app.rb +24 -0
  39. data/spec/support/rails3/log/test.log +1120 -0
  40. data/spec/support/rails4/app.rb +27 -0
  41. data/spec/unit/backtrace_spec.rb +88 -0
  42. data/spec/unit/configuration_spec.rb +29 -0
  43. data/spec/unit/exception_presenter_spec.rb +69 -0
  44. data/spec/unit/influxdb_rails_spec.rb +67 -0
  45. metadata +226 -0
@@ -0,0 +1,90 @@
1
+ require "base64"
2
+ require "socket"
3
+
4
+ module InfluxDB
5
+ module Rails
6
+ class ExceptionPresenter
7
+ attr_accessor :hash
8
+
9
+ attr_reader :exception
10
+ attr_reader :backtrace
11
+ attr_reader :params
12
+ attr_reader :session_data
13
+ attr_reader :current_user
14
+ attr_reader :controller
15
+ attr_reader :action
16
+ attr_reader :request_url
17
+ attr_reader :referer
18
+ attr_reader :remote_ip
19
+ attr_reader :user_agent
20
+ attr_reader :custom_data
21
+
22
+ def initialize(e, params = {})
23
+ e = e.continued_exception if e.respond_to?(:continued_exception)
24
+ e = e.original_exception if e.respond_to?(:original_exception)
25
+
26
+ @exception = e.is_a?(String) ? Exception.new(e) : e
27
+ @backtrace = InfluxDB::Rails::Backtrace.new(@exception.backtrace)
28
+ @params = params[:params]
29
+ @session_data = params[:session_data] || {}
30
+ @current_user = params[:current_user]
31
+ @controller = params[:controller]
32
+ @action = params[:action]
33
+ @request_url = params[:request_url]
34
+ @user_agent = params[:user_agent]
35
+ @referer = params[:referer]
36
+ @remote_ip = params[:remote_ip]
37
+ @custom_data = params[:custom_data] || {}
38
+ @environment_variables = ENV.to_hash || {}
39
+ @dimensions = {}
40
+ end
41
+
42
+ def context
43
+ c = {
44
+ :time => Time.now.utc.to_i,
45
+ :application_name => InfluxDB::Rails.configuration.application_name,
46
+ :application_root => InfluxDB::Rails.configuration.application_root,
47
+ :framework => InfluxDB::Rails.configuration.framework,
48
+ :framework_version => InfluxDB::Rails.configuration.framework_version,
49
+ :message => @exception.message,
50
+ :backtrace => @backtrace.to_a,
51
+ :language => "Ruby",
52
+ :language_version => "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}",
53
+ :custom_data => @custom_data
54
+ }
55
+
56
+ c[:environment_variables] = @environment_variables.reject do |k,v|
57
+ InfluxDB::Rails.configuration.environment_variable_filters.any? { |filter| k =~ filter }
58
+ end
59
+
60
+ InfluxDB::Rails.configuration.add_custom_exception_data(self)
61
+
62
+ c[:request_data] = request_data if @controller || @action || !@params.blank?
63
+ c
64
+ end
65
+
66
+ def dimensions
67
+ d = {
68
+ :class => @exception.class.to_s,
69
+ :method => "#{@controller}##{@action}",
70
+ :filename => File.basename(@backtrace.lines.first.try(:file)),
71
+ :server => Socket.gethostname,
72
+ :status => "open"
73
+ }.merge(@dimensions)
74
+ end
75
+
76
+ def request_data
77
+ {
78
+ :params => @params,
79
+ :session_data => @session_data,
80
+ :controller => @controller,
81
+ :action => @action,
82
+ :request_url => @request_url,
83
+ :referer => @referer,
84
+ :remote_ip => @remote_ip,
85
+ :user_agent => @user_agent
86
+ }
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,27 @@
1
+ module InfluxDB
2
+ module Rails
3
+ module Instrumentation
4
+ def benchmark_for_instrumentation
5
+ start = Time.now
6
+ yield
7
+
8
+ unless InfluxDB.configuration.ignore_current_environment?
9
+ elapsed = ((Time.now - start) * 1000).ceil
10
+ dimensions = { :method => "#{controller_name}##{action_name}", :server => Socket.gethostname }
11
+ InfluxDB.aggregate "instrumentation", :value => elapsed, :dimensions => dimensions
12
+ end
13
+ end
14
+
15
+ def self.included(base)
16
+ base.extend(ClassMethods)
17
+ end
18
+
19
+ module ClassMethods
20
+ def instrument(methods = [])
21
+ methods = [methods] unless methods.is_a?(Array)
22
+ around_filter :benchmark_for_instrumentation, :only => methods
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ module InfluxDB
2
+ module Rails
3
+ module Logger
4
+ PREFIX = "[InfluxDB::Rails] "
5
+
6
+ private
7
+ def log(level, message)
8
+ return if level != :error && ! InfluxDB::Rails.configuration.debug?
9
+ InfluxDB::Rails.configuration.logger.send(level, PREFIX + message) if InfluxDB.configuration.logger
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ module InfluxDB
2
+ module Rails
3
+ module Middleware
4
+ module HijackRenderException
5
+ def self.included(base)
6
+ base.send(:alias_method_chain, :render_exception, :influxdb)
7
+ end
8
+
9
+ def render_exception_with_influxdb(env, e)
10
+ controller = env["action_controller.instance"]
11
+ request_data = controller.try(:influxdb_request_data) || {}
12
+ unless InfluxDB::Rails.configuration.ignore_user_agent?(request_data[:user_agent])
13
+ InfluxDB::Rails.report_exception_unless_ignorable(e, request_data)
14
+ end
15
+ render_exception_without_influxdb(env, e)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,32 @@
1
+ module InfluxDB
2
+ module Rails
3
+ module Middleware
4
+ module HijackRescueActionEverywhere
5
+ def self.included(base)
6
+ base.send(:alias_method_chain, :rescue_action_in_public, :influxdb)
7
+ base.send(:alias_method_chain, :rescue_action_locally, :influxdb)
8
+ end
9
+
10
+ private
11
+ def rescue_action_in_public_with_influxdb(e)
12
+ handle_exception(e)
13
+ rescue_action_in_public_without_influxdb(e)
14
+ end
15
+
16
+ def rescue_action_locally_with_influxdb(e)
17
+ handle_exception(e)
18
+ rescue_action_locally_without_influxdb(e)
19
+ end
20
+
21
+ def handle_exception(e)
22
+ request_data = influxdb_request_data || {}
23
+
24
+ unless InfluxDB.configuration.ignore_user_agent?(request_data[:user_agent])
25
+ InfluxDB.report_exception_unless_ignorable(e, request_data)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+
@@ -0,0 +1,28 @@
1
+ module InfluxDB
2
+ module Rails
3
+ class Rack
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ dup._call(env)
10
+ end
11
+
12
+ def _call(env)
13
+ begin
14
+ status, headers, body = @app.call(env)
15
+ rescue => e
16
+ InfluxDB.transmit_unless_ignorable(e, env)
17
+ raise(e)
18
+ ensure
19
+ _body = []
20
+ body.each { |line| _body << line } unless body.nil?
21
+ body.close if body.respond_to?(:close)
22
+ end
23
+
24
+ [status, headers, _body]
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,39 @@
1
+ require 'action_controller'
2
+ require 'influxdb'
3
+ require 'influxdb/rails/middleware/hijack_rescue_action_everywhere'
4
+ require 'influxdb/rails/air_traffic_controller'
5
+ require 'influxdb/rails/benchmarking'
6
+ require 'influxdb/rails/instrumentation'
7
+
8
+ module InfluxDB
9
+ module Rails
10
+ def self.initialize
11
+ ActionController::Base.send(:include, InfluxDB::Rails::AirTrafficController)
12
+ ActionController::Base.send(:include, InfluxDB::Rails::Middleware::HijackRescueActionEverywhere)
13
+ ActionController::Base.send(:include, InfluxDB::Rails::Benchmarking)
14
+ ActionController::Base.send(:include, InfluxDB::Rails::Instrumentation)
15
+
16
+ ::Rails.configuration.middleware.insert_after 'ActionController::Failsafe', InfluxDB::Rack
17
+
18
+ InfluxDB.configure(true) do |config|
19
+ config.logger ||= ::Rails.logger
20
+ config.debug = true
21
+ config.environment ||= ::Rails.env
22
+ config.application_root ||= ::Rails.root
23
+ config.application_name ||= "Application"
24
+ config.framework = "Rails"
25
+ config.framework_version = ::Rails.version
26
+ end
27
+
28
+ if defined?(PhusionPassenger)
29
+ PhusionPassenger.on_event(:starting_worker_process) do |forked|
30
+ InfluxDB::Worker.spawn_threads() if forked
31
+ end
32
+ else
33
+ InfluxDB::Worker.spawn_threads()
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ InfluxDB::Rails.initialize
@@ -0,0 +1,67 @@
1
+ require 'influxdb'
2
+ require 'rails'
3
+
4
+ module InfluxDB
5
+ module Rails
6
+ class Railtie < ::Rails::Railtie
7
+ initializer "influxdb.insert_rack_middleware" do |app|
8
+ app.config.middleware.insert 0, InfluxDB::Rails::Rack
9
+ end
10
+
11
+ config.after_initialize do
12
+ InfluxDB::Rails.configure(true) do |config|
13
+ config.logger ||= ::Rails.logger
14
+ config.environment ||= ::Rails.env
15
+ config.application_root ||= ::Rails.root
16
+ config.application_name ||= ::Rails.application.class.parent_name
17
+ config.framework = "Rails"
18
+ config.framework_version = ::Rails.version
19
+ end
20
+
21
+ ActiveSupport.on_load(:action_controller) do
22
+ require 'influxdb/rails/air_traffic_controller'
23
+ include InfluxDB::Rails::AirTrafficController
24
+ require 'influxdb/rails/instrumentation'
25
+ include InfluxDB::Rails::Instrumentation
26
+ end
27
+
28
+ if defined?(::ActionDispatch::DebugExceptions)
29
+ require 'influxdb/rails/middleware/hijack_render_exception'
30
+ ::ActionDispatch::DebugExceptions.send(:include, InfluxDB::Rails::Middleware::HijackRenderException)
31
+ elsif defined?(::ActionDispatch::ShowExceptions)
32
+ require 'influxdb/rails/middleware/hijack_render_exception'
33
+ ::ActionDispatch::ShowExceptions.send(:include, InfluxDB::Rails::Middleware::HijackRenderException)
34
+ end
35
+
36
+ if defined?(ActiveSupport::Notifications)
37
+ ActiveSupport::Notifications.subscribe "process_action.action_controller" do |name, start, finish, id, payload|
38
+ if InfluxDB::Rails.configuration.instrumentation_enabled && ! InfluxDB::Rails.configuration.ignore_current_environment?
39
+ timestamp = finish.utc.to_i
40
+ controller_runtime = ((finish - start)*1000).ceil
41
+ view_runtime = (payload[:view_runtime] || 0).ceil
42
+ db_runtime = (payload[:db_runtime] || 0).ceil
43
+ controller_name = payload[:controller]
44
+ action_name = payload[:action]
45
+ hostname = Socket.gethostname
46
+
47
+ InfluxDB::Rails.client.write_point "rails.controllers",
48
+ :value => controller_runtime,
49
+ :method => "#{controller_name}##{action_name}",
50
+ :server => hostname
51
+
52
+ InfluxDB::Rails.client.write_point "rails.views",
53
+ :value => view_runtime,
54
+ :method => "#{controller_name}##{action_name}",
55
+ :server => hostname
56
+
57
+ InfluxDB::Rails.client.write_point "rails.db",
58
+ :value => db_runtime,
59
+ :method => "#{controller_name}##{action_name}",
60
+ :server => hostname
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,5 @@
1
+ module InfluxDB
2
+ module Rails
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,52 @@
1
+ require 'rails/generators'
2
+
3
+ class InfluxDBGenerator < Rails::Generators::Base
4
+ desc "Description:\n This creates a Rails initializer for InfluxDB."
5
+
6
+ begin
7
+ if ARGV.count == 1
8
+ puts "No Application ID provided, contacting InfluxDB API."
9
+ application_name = Rails.application.class.parent_name || "NewApplication"
10
+ api_key = ARGV.first
11
+
12
+ connection = Net::HTTP.new("influxdb.com", 443)
13
+ connection.use_ssl = true
14
+ connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
15
+ url = "/api/v1/applications?api_key=#{api_key}&name=#{application_name}"
16
+ response = connection.post(url, nil)
17
+
18
+ unless response.is_a?(Net::HTTPSuccess)
19
+ raise "The InfluxDB API returned an error: #{response.inspect}"
20
+ end
21
+
22
+ @application = JSON.parse(response.body)
23
+ @application_id = @application["key"]
24
+ else
25
+ @application_id = ARGV[1]
26
+ end
27
+ puts "Received Application ID: #{@application_id}"
28
+
29
+ rescue => e
30
+ puts "We ran into a problem creating your application via the API!"
31
+ puts "If this issue persists, contact us at support@influxdb.com with the following details:"
32
+ puts "#{e.class}: #{e.message}"
33
+ end
34
+
35
+ source_root File.expand_path('../templates', __FILE__)
36
+ argument :api_key,
37
+ :required => true,
38
+ :type => :string,
39
+ :description => "API key for your InfluxDB organization"
40
+ argument :application_id,
41
+ :required => false,
42
+ :default => @application_id,
43
+ :type => :string,
44
+ :description => "Identifier for this application (Leave blank and a new one will be generated for you)"
45
+
46
+ def copy_initializer_file
47
+ template "initializer.rb", "config/initializers/influxdb.rb"
48
+ end
49
+
50
+ def install
51
+ end
52
+ end
@@ -0,0 +1,4 @@
1
+ InfluxDB.configure do |config|
2
+ config.api_key = "<%= api_key %>"
3
+ config.application_id = "<%= application_id %>"
4
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe WidgetsController do
4
+ describe "#new" do
5
+ it "should raise an exception" do
6
+ expect { get :new }.to raise_error(ZeroDivisionError)
7
+ end
8
+ end
9
+
10
+ describe "#index" do
11
+ it "should not raise an exception" do
12
+ expect { get :index }.to_not raise_error
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,37 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/integration_helper")
2
+
3
+ describe "exception handling" do
4
+ before do
5
+ InfluxDB::Rails.configure do |config|
6
+ config.ignored_environments = %w{development}
7
+ config.instrumentation_enabled = false
8
+ end
9
+ end
10
+
11
+ describe "in an action that raises an exception" do
12
+ it "should add an exception to the queue" do
13
+ InfluxDB::Rails.client.should_receive(:write_point)
14
+ get "/widgets/new"
15
+ end
16
+ end
17
+
18
+ describe "in an action that does not raise an exception" do
19
+ it "should not add anything to the queue" do
20
+ InfluxDB::Rails.client.should_not_receive(:write_point)
21
+ get "/widgets"
22
+ end
23
+ end
24
+
25
+ describe "for an ignored user agent" do
26
+ it "should not make an HTTP call to the API" do
27
+ InfluxDB::Rails.client.should_not_receive(:write_point)
28
+
29
+ InfluxDB::Rails.configure do |config|
30
+ config.ignored_user_agents = %w{Googlebot}
31
+ end
32
+
33
+ get "/widgets/new", {}, { "HTTP_USER_AGENT" => "Googlebot/2.1" }
34
+ end
35
+ end
36
+ end
37
+