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.
- checksums.yaml +15 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +95 -0
- data/README.md +3 -0
- data/Rakefile +34 -0
- data/config.ru +7 -0
- data/gemfiles/Gemfile.rails-3.0.x +8 -0
- data/gemfiles/Gemfile.rails-3.0.x.lock +94 -0
- data/gemfiles/Gemfile.rails-3.1.x +8 -0
- data/gemfiles/Gemfile.rails-3.1.x.lock +121 -0
- data/gemfiles/Gemfile.rails-3.2.x +8 -0
- data/gemfiles/Gemfile.rails-3.2.x.lock +104 -0
- data/gemfiles/Gemfile.rails-4.0.x +8 -0
- data/gemfiles/Gemfile.rails-4.0.x.lock +109 -0
- data/generators/influxdb/influxdb_generator.rb +48 -0
- data/generators/influxdb/templates/initializer.rb +5 -0
- data/influxdb-rails.gemspec +33 -0
- data/lib/influxdb-rails.rb +82 -0
- data/lib/influxdb/rails/air_traffic_controller.rb +39 -0
- data/lib/influxdb/rails/backtrace.rb +44 -0
- data/lib/influxdb/rails/configuration.rb +117 -0
- data/lib/influxdb/rails/exception_presenter.rb +90 -0
- data/lib/influxdb/rails/instrumentation.rb +27 -0
- data/lib/influxdb/rails/logger.rb +13 -0
- data/lib/influxdb/rails/middleware/hijack_render_exception.rb +21 -0
- data/lib/influxdb/rails/middleware/hijack_rescue_action_everywhere.rb +32 -0
- data/lib/influxdb/rails/rack.rb +28 -0
- data/lib/influxdb/rails/rails.rb +39 -0
- data/lib/influxdb/rails/railtie.rb +67 -0
- data/lib/influxdb/rails/version.rb +5 -0
- data/lib/rails/generators/influxdb/influxdb_generator.rb +52 -0
- data/lib/rails/generators/influxdb/templates/initializer.rb +4 -0
- data/spec/controllers/widgets_controller_spec.rb +15 -0
- data/spec/integration/exceptions_spec.rb +37 -0
- data/spec/integration/integration_helper.rb +1 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/suite.sh +42 -0
- data/spec/support/rails3/app.rb +24 -0
- data/spec/support/rails3/log/test.log +1120 -0
- data/spec/support/rails4/app.rb +27 -0
- data/spec/unit/backtrace_spec.rb +88 -0
- data/spec/unit/configuration_spec.rb +29 -0
- data/spec/unit/exception_presenter_spec.rb +69 -0
- data/spec/unit/influxdb_rails_spec.rb +67 -0
- 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,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,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
|
+
|