copperegg-apm 1.0.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +102 -0
- data/README.md +181 -0
- data/Rakefile +4 -0
- data/bin/copperegg-apm-init +45 -0
- data/bin/copperegg-apm-methods +27 -0
- data/copperegg-apm-1.0.0.pre1.gem +0 -0
- data/copperegg-apm.gemspec +34 -0
- data/copperegg_apm_test.db +0 -0
- data/ext/mkrf_conf.rb +19 -0
- data/lib/copperegg-apm.rb +1 -0
- data/lib/copperegg/apm.rb +28 -0
- data/lib/copperegg/apm/action_controller/base.rb +31 -0
- data/lib/copperegg/apm/active_record/connection_adapters/abstract_adapter.rb +35 -0
- data/lib/copperegg/apm/benchmark.rb +212 -0
- data/lib/copperegg/apm/benchmark_methods_table.rb +65 -0
- data/lib/copperegg/apm/configuration.rb +188 -0
- data/lib/copperegg/apm/engine.rb +15 -0
- data/lib/copperegg/apm/errors.rb +6 -0
- data/lib/copperegg/apm/ethon/easy/operations.rb +37 -0
- data/lib/copperegg/apm/kernel.rb +19 -0
- data/lib/copperegg/apm/middleware.rb +20 -0
- data/lib/copperegg/apm/mysql.rb +31 -0
- data/lib/copperegg/apm/mysql2/client.rb +35 -0
- data/lib/copperegg/apm/net/http.rb +39 -0
- data/lib/copperegg/apm/pg/connection.rb +35 -0
- data/lib/copperegg/apm/restclient/request.rb +33 -0
- data/lib/copperegg/apm/rum.rb +24 -0
- data/lib/copperegg/apm/sqlite3/database.rb +35 -0
- data/lib/copperegg/apm/tasks.rb +11 -0
- data/lib/copperegg/apm/typhoeus/hydra.rb +33 -0
- data/lib/copperegg/apm/unbound_method.rb +116 -0
- data/lib/copperegg/apm/version.rb +5 -0
- data/lib/generators/copperegg/apm/init_generator.rb +20 -0
- data/lib/generators/copperegg/apm/templates/config.rb +10 -0
- data/performance/mysql2.rb +44 -0
- data/screenshot01.png +0 -0
- data/spec/action_controller_spec.rb +139 -0
- data/spec/apm_spec.rb +330 -0
- data/spec/ethon_spec.rb +73 -0
- data/spec/helpers/mysql2_setup.rb +51 -0
- data/spec/helpers/mysql_setup.rb +45 -0
- data/spec/helpers/pg_setup.rb +43 -0
- data/spec/helpers/rails.rb +18 -0
- data/spec/helpers/sqlite3_setup.rb +30 -0
- data/spec/kernel_spec.rb +37 -0
- data/spec/mysql2_spec.rb +58 -0
- data/spec/mysql_spec.rb +66 -0
- data/spec/net_http_spec.rb +52 -0
- data/spec/pg_spec.rb +45 -0
- data/spec/restclient_spec.rb +67 -0
- data/spec/rum_spec.rb +23 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/sqlite3_spec.rb +45 -0
- data/spec/typhoeus_spec.rb +66 -0
- metadata +316 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
module Copperegg
|
2
|
+
module Apm
|
3
|
+
module Generators
|
4
|
+
class InitGenerator < Rails::Generators::Base
|
5
|
+
source_root File.expand_path("../templates", __FILE__)
|
6
|
+
desc "Creates an initializer file at config/initializers/copperegg_apm_config.rb"
|
7
|
+
|
8
|
+
def create_initializer
|
9
|
+
template "config.rb", "#{Rails.root}/config/initializers/copperegg_apm_config.rb", :verbose => true
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def instrument_key
|
15
|
+
@instrument_key = ask("Enter your app key:")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
CopperEgg::APM.configure do |config|
|
2
|
+
config.instrument_key = "<%= instrument_key %>"
|
3
|
+
config.benchmark_sql = true
|
4
|
+
config.benchmark_exceptions = true
|
5
|
+
config.benchmark_http = true
|
6
|
+
config.benchmark_methods :disabled # To enable, set to :basic, :moderate, or :full
|
7
|
+
# Below are examples of customizing method benchmarking
|
8
|
+
# config.benchmark_methods :basic, :exclude => %w(UsersController#new UsersController#edit), :include => %w(User UserRole perform)
|
9
|
+
# config.benchmark_methods :custom, %w(User Client index ClientsController#create)
|
10
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require File.dirname(__FILE__) + '/../spec/helpers/mysql2_setup'
|
3
|
+
require 'copperegg/apm'
|
4
|
+
require 'benchmark'
|
5
|
+
|
6
|
+
CopperEgg::APM.configure do |config|
|
7
|
+
config.instrument_key = "key"
|
8
|
+
config.benchmark_sql = false
|
9
|
+
end
|
10
|
+
|
11
|
+
client = Mysql2::Client.new :host => "localhost", :database => "copperegg_apm_test", :username => ENV["MYSQL_USER"]
|
12
|
+
sql = "UPDATE `users` SET `details` = '512.777.9311', `updated_at` = '#{Time.now.strftime('%Y-%m-%d %H:%M%S')}' WHERE `users`.`id` = 1"
|
13
|
+
n = 10000
|
14
|
+
|
15
|
+
puts "\nFor \"#{sql}\"\n\n"
|
16
|
+
|
17
|
+
Benchmark.bm(31) do |x|
|
18
|
+
x.report("#{n} queries w/o instrumentation") { n.times { client.query(sql) } }
|
19
|
+
end
|
20
|
+
|
21
|
+
puts
|
22
|
+
|
23
|
+
CopperEgg::APM.configure do |config|
|
24
|
+
config.instrument_key = "key"
|
25
|
+
config.benchmark_sql = true
|
26
|
+
end
|
27
|
+
|
28
|
+
Benchmark.bm(31) do |x|
|
29
|
+
x.report("#{n} queries w/ sql obfuscation") { n.times { client.query(sql) } }
|
30
|
+
end
|
31
|
+
|
32
|
+
puts
|
33
|
+
|
34
|
+
# class String
|
35
|
+
# def bytesize
|
36
|
+
# 1025
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
|
40
|
+
Benchmark.bm(31) do |x|
|
41
|
+
x.report("#{n} queries w/o sql obfuscation") { n.times { client.query(sql) } }
|
42
|
+
end
|
43
|
+
|
44
|
+
puts
|
data/screenshot01.png
ADDED
Binary file
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# Props to @relishapp (http://www.relishapp.com/rspec/rspec-rails/docs/controller-specs/anonymous-controller) and
|
2
|
+
# @AlexandrZaytsev (http://say26.com/rspec-testing-controllers-outside-of-a-rails-application) for their helpful blog posts
|
3
|
+
require File.dirname(__FILE__) + '/helpers/rails'
|
4
|
+
require 'spec_helper'
|
5
|
+
|
6
|
+
RSpec.configure do |c|
|
7
|
+
c.infer_base_class_for_anonymous_controllers = true
|
8
|
+
end
|
9
|
+
|
10
|
+
class ApplicationController < ActionController::Base
|
11
|
+
include Rails.application.routes.url_helpers
|
12
|
+
end
|
13
|
+
|
14
|
+
class ExceptionController < ApplicationController; end
|
15
|
+
|
16
|
+
class BenchmarkAllActionsController < ApplicationController; end
|
17
|
+
|
18
|
+
class BenchmarkOnlyActionsController < ApplicationController; end
|
19
|
+
|
20
|
+
class BenchmarkExceptActionsController < ApplicationController; end
|
21
|
+
|
22
|
+
describe ExceptionController, :type => :controller do
|
23
|
+
controller(ExceptionController) do
|
24
|
+
def index
|
25
|
+
@count = 1/0
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should instrument all exceptions not rescued" do
|
30
|
+
expect { get :index, {:id => 1, :sort => "name"} }.to raise_error
|
31
|
+
|
32
|
+
last_payload = CopperEgg::APM.send(:class_variable_get, :@@payload_cache).split("\x00").select {|i| i.size > 2}.map {|i| i.sub(/^[^\{]+/,'')}.last
|
33
|
+
hash = JSON.parse last_payload
|
34
|
+
|
35
|
+
expect(hash.keys.sort).to eq ["excp", "id"]
|
36
|
+
expect(hash["id"]).to match(/\A[0-1a-z]{16}\z/i)
|
37
|
+
expect(hash["excp"].keys.sort).to eq ["error", "stacktrace", "ts"]
|
38
|
+
expect(hash["excp"]["error"]).to match(/\AZeroDivisionError\|/)
|
39
|
+
expect(hash["excp"]["error"]).to match(/\{Ruby\}\Z/)
|
40
|
+
expect(hash["excp"]["stacktrace"]).to match(/\Adivided by 0\n/)
|
41
|
+
expect(hash["excp"]["ts"]).to be_an_instance_of(Fixnum)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe BenchmarkAllActionsController, :type => :controller do
|
46
|
+
controller(BenchmarkAllActionsController) do
|
47
|
+
add_benchmarks
|
48
|
+
|
49
|
+
def index
|
50
|
+
100.times.reduce(:+)
|
51
|
+
render :nothing => true
|
52
|
+
end
|
53
|
+
alias_method :create, :index
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should benchmark all actions" do
|
57
|
+
get :index
|
58
|
+
|
59
|
+
last_payload = CopperEgg::APM.send(:class_variable_get, :@@payload_cache).split("\x00").select {|i| i.size > 2}.map {|i| i.sub(/^[^\{]+/,'')}.last
|
60
|
+
hash = JSON.parse last_payload
|
61
|
+
|
62
|
+
expect(hash.keys.sort).to eq ["id", "inst"]
|
63
|
+
expect(hash["id"]).to match(/\A[0-1a-z]{16}\z/i)
|
64
|
+
expect(hash["inst"].keys.sort).to eq ["method", "time"]
|
65
|
+
expect(hash["inst"]["method"]).to match(/#index \{Ruby\}/)
|
66
|
+
expect(hash["inst"]["time"].to_s).to match(/\A\d+\Z/)
|
67
|
+
|
68
|
+
post :create
|
69
|
+
|
70
|
+
last_payload = CopperEgg::APM.send(:class_variable_get, :@@payload_cache).split("\x00").select {|i| i.size > 2}.map {|i| i.sub(/^[^\{]+/,'')}.last
|
71
|
+
hash = JSON.parse last_payload
|
72
|
+
|
73
|
+
expect(hash["inst"]["method"]).to match(/#create \{Ruby\}/)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe BenchmarkOnlyActionsController, :type => :controller do
|
78
|
+
controller(BenchmarkOnlyActionsController) do
|
79
|
+
add_benchmarks :only => [:index]
|
80
|
+
|
81
|
+
def index
|
82
|
+
100.times.reduce(:+)
|
83
|
+
render :nothing => true
|
84
|
+
end
|
85
|
+
alias_method :create, :index
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should benchmark all actions" do
|
89
|
+
get :index
|
90
|
+
|
91
|
+
last_payload = CopperEgg::APM.send(:class_variable_get, :@@payload_cache).split("\x00").select {|i| i.size > 2}.map {|i| i.sub(/^[^\{]+/,'')}.last
|
92
|
+
hash = JSON.parse last_payload
|
93
|
+
|
94
|
+
expect(hash.keys.sort).to eq ["id", "inst"]
|
95
|
+
expect(hash["id"]).to match(/\A[0-1a-z]{16}\z/i)
|
96
|
+
expect(hash["inst"].keys.sort).to eq ["method", "time"]
|
97
|
+
expect(hash["inst"]["method"]).to match(/#index \{Ruby\}/)
|
98
|
+
expect(hash["inst"]["time"].to_s).to match(/\A\d+\Z/)
|
99
|
+
|
100
|
+
post :create
|
101
|
+
|
102
|
+
last_payload = CopperEgg::APM.send(:class_variable_get, :@@payload_cache).split("\x00").select {|i| i.size > 2}.map {|i| i.sub(/^[^\{]+/,'')}.last
|
103
|
+
hash = JSON.parse last_payload
|
104
|
+
|
105
|
+
expect(hash["inst"]["method"]).to match(/#index \{Ruby\}/)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe BenchmarkExceptActionsController, :type => :controller do
|
110
|
+
controller(BenchmarkExceptActionsController) do
|
111
|
+
add_benchmarks :except => [:create]
|
112
|
+
|
113
|
+
def index
|
114
|
+
100.times.reduce(:+)
|
115
|
+
render :nothing => true
|
116
|
+
end
|
117
|
+
alias_method :create, :index
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should benchmark all actions" do
|
121
|
+
get :index
|
122
|
+
|
123
|
+
last_payload = CopperEgg::APM.send(:class_variable_get, :@@payload_cache).split("\x00").select {|i| i.size > 2}.map {|i| i.sub(/^[^\{]+/,'')}.last
|
124
|
+
hash = JSON.parse last_payload
|
125
|
+
|
126
|
+
expect(hash.keys.sort).to eq ["id", "inst"]
|
127
|
+
expect(hash["id"]).to match(/\A[0-1a-z]{16}\z/i)
|
128
|
+
expect(hash["inst"].keys.sort).to eq ["method", "time"]
|
129
|
+
expect(hash["inst"]["method"]).to match(/#index \{Ruby\}/)
|
130
|
+
expect(hash["inst"]["time"].to_s).to match(/\A\d+\Z/)
|
131
|
+
|
132
|
+
post :create
|
133
|
+
|
134
|
+
last_payload = CopperEgg::APM.send(:class_variable_get, :@@payload_cache).split("\x00").select {|i| i.size > 2}.map {|i| i.sub(/^[^\{]+/,'')}.last
|
135
|
+
hash = JSON.parse last_payload
|
136
|
+
|
137
|
+
expect(hash["inst"]["method"]).to match(/#index \{Ruby\}/)
|
138
|
+
end
|
139
|
+
end
|
data/spec/apm_spec.rb
ADDED
@@ -0,0 +1,330 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
class Foo
|
5
|
+
def self.bar
|
6
|
+
CopperEgg::APM.benchmark(self) { 100.times.reduce(:+) }
|
7
|
+
end
|
8
|
+
|
9
|
+
def bar
|
10
|
+
CopperEgg::APM.benchmark(self) { 100.times.reduce(:+) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def baz
|
14
|
+
CopperEgg::APM.benchmark(nil) { 100.times.reduce(:+) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module Baz
|
19
|
+
def self.bar
|
20
|
+
CopperEgg::APM.benchmark(self) { 100.times.reduce(:+) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe CopperEgg::APM do
|
25
|
+
describe ".trim_stacktrace" do
|
26
|
+
it "should remove lines not in app root" do
|
27
|
+
CopperEgg::APM::Configuration.app_root = "/deploy/current/"
|
28
|
+
|
29
|
+
stacktrace = <<-LINES
|
30
|
+
#{File.dirname(File.dirname(__FILE__))}/mysql2/client.rb:10:in `query'
|
31
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/mysql2-0.2.18/lib/active_record/connection_adapters/mysql2_adapter.rb:265:in `block in execute'
|
32
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract_adapter.rb:202:in `block in log'
|
33
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activesupport-3.0.20/lib/active_support/notifications/instrumenter.rb:21:in `instrument'
|
34
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract_adapter.rb:200:in `log'
|
35
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/mysql2-0.2.18/lib/active_record/connection_adapters/mysql2_adapter.rb:265:in `execute'
|
36
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/mysql2-0.2.18/lib/active_record/connection_adapters/mysql2_adapter.rb:586:in `select'
|
37
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract/database_statements.rb:7:in `select_all'
|
38
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract/query_cache.rb:56:in `select_all'
|
39
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/base.rb:473:in `find_by_sql'
|
40
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/relation.rb:64:in `to_a'
|
41
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/r>elation/finder_methods.rb:143:in `all'
|
42
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job_active_record-0.3.3/lib/delayed/backend/active_record.rb:58:in `block in find_available'
|
43
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activesupport-3.0.20/lib/active_support/benchmarkable.rb:55:in `silence'
|
44
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job_active_record-0.3.3/lib/delayed/backend/active_record.rb:57:in `find_available'
|
45
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/backend/base.rb:45:in `reserve'
|
46
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/worker.rb:258:in `reserve_and_run_one_job'
|
47
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/worker.rb:187:in `block in work_off'
|
48
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/worker.rb:186:in `times'
|
49
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/worker.rb:186:in `work_off'
|
50
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/worker.rb:151:in `block (4 levels) in start'
|
51
|
+
/home/copperegg/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/benchmark.rb:310:in `realtime'
|
52
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/worker.rb:150:in `block (3 levels) in start'
|
53
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/lifecycle.rb:60:in `call'
|
54
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/lifecycle.rb:60:in `block in initialize'
|
55
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/lifecycle.rb:65:in `call'
|
56
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/lifecycle.rb:65:in `execute'
|
57
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/lifecycle.rb:38:in `run_callbacks'
|
58
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/worker.rb:149:in `block (2 levels) in start'
|
59
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/worker.rb:148:in `loop'
|
60
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/worker.rb:148:in `block in start'
|
61
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/plugins/clear_locks.rb:7:in `call'
|
62
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/plugins/clear_locks.rb:7:in `block (2 levels) in '
|
63
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/lifecycle.rb:78:in `call'
|
64
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/lifecycle.rb:78:in `block (2 levels) in add'
|
65
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/lifecycle.rb:60:in `call'
|
66
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/lifecycle.rb:60:in `block in initialize'
|
67
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/lifecycle.rb:78:in `call'
|
68
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/lifecycle.rb:78:in `block in add'
|
69
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/lifecycle.rb:65:in `call'
|
70
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/lifecycle.rb:65:in `execute'
|
71
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/lifecycle.rb:38:in `run_callbacks'
|
72
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/worker.rb:147:in `start'
|
73
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/command.rb:104:in `run'
|
74
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/command.rb:92:in `block in run_process'
|
75
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/daemons-1.1.9/lib/daemons/application.rb:255:in `call'
|
76
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/daemons-1.1.9/lib/daemons/application.rb:255:in `block in start_proc'
|
77
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/daemons-1.1.9/lib/daemons/daemonize.rb:82:in `call'
|
78
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/daemons-1.1.9/lib/daemons/daemonize.rb:82:in `call_as_daemon'
|
79
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/daemons-1.1.9/lib/daemons/application.rb:259:in `start_proc'
|
80
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/daemons-1.1.9/lib/daemons/application.rb:296:in `start'
|
81
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/daemons-1.1.9/lib/daemons/controller.rb:70:in `run'
|
82
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/daemons-1.1.9/lib/daemons.rb:197:in `block in run_proc'
|
83
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/daemons-1.1.9/lib/daemons/cmdline.rb:109:in `call'
|
84
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/daemons-1.1.9/lib/daemons/cmdline.rb:109:in `catch_exceptions'
|
85
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/daemons-1.1.9/lib/daemons.rb:196:in `run_proc'
|
86
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delay>ed/command.rb:90:in `run_process'
|
87
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/command.rb:83:in `block in daemonize'
|
88
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/command.rb:81:in `times'
|
89
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/delayed_job-3.0.5/lib/delayed/command.rb:81:in `daemonize'
|
90
|
+
script/delayed_job:5:in `'
|
91
|
+
LINES
|
92
|
+
|
93
|
+
expect(CopperEgg::APM.trim_stacktrace(stacktrace.split("\n"))).to eq [stacktrace.lines.to_a.last.strip]
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should only include lines in app root" do
|
97
|
+
CopperEgg::APM::Configuration.app_root = "/home/copperegg/rails/"
|
98
|
+
|
99
|
+
stacktrace = <<-LINES
|
100
|
+
#{File.dirname(File.dirname(__FILE__))}/lib/copperegg/apm/mysql2/client.rb:10:in `query'
|
101
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/mysql2-0.2.18/lib/active_record/connection_adapters/mysql2_adapter.rb:265:in `block in execute'
|
102
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract_adapter.rb:202:in `block in log'
|
103
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activesupport-3.0.20/lib/active_support/notifications/instrumenter.rb:21:in `instrument'
|
104
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract_adapter.rb:200:in `log'
|
105
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/mysql2-0.2.18/lib/active_record/connection_adapters/mysql2_adapter.rb:265:in `execute'
|
106
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/mysql2-0.2.18/lib/active_record/connection_adapters/mysql2_adapter.rb:586:in `select'
|
107
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract/database_statements.rb:7:in `select_all'
|
108
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract/query_cache.rb:56:in `select_all'
|
109
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/base.rb:473:in `find_by_sql'
|
110
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/relation.rb:64:in `to_a'
|
111
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/relation/finder_methods.rb:143:in `all'
|
112
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/base.rb:444:in `all'
|
113
|
+
/home/copperegg/rails/app/models/cluster.rb:60:in `populate_cache!'
|
114
|
+
/home/copperegg/rails/app/models/cluster.rb:48:in `get_nodes'
|
115
|
+
/home/copperegg/rails/lib/store.rb:48:in `io'
|
116
|
+
/home/copperegg/rails/lib/store.rb:218:in `save'
|
117
|
+
/home/copperegg/rails/app/models/sample.rb:74:in `stor'
|
118
|
+
/home/copperegg/rails/app/models/sample.rb:284:in `block (2 levels) in save'
|
119
|
+
/home/copperegg/rails/app/models/sample.rb:204:in `each'
|
120
|
+
/home/copperegg/rails/app/models/sample.rb:204:in `block in save'
|
121
|
+
/home/copperegg/rails/app/models/sample.rb:199:in `each'
|
122
|
+
/home/copperegg/rails/app/models/sample.rb:199:in `save'
|
123
|
+
/home/copperegg/rails/lib/worker.rb:401:in `save_sample'
|
124
|
+
/home/copperegg/rails/lib/worker.rb:256:in `worker_run'
|
125
|
+
/home/copperegg/rails/lib/worker.rb:170:in `block in start_worker'
|
126
|
+
/home/copperegg/rails/lib/worker.rb:164:in `fork'
|
127
|
+
/home/copperegg/rails/lib/worker.rb:164:in `start_worker'
|
128
|
+
/home/copperegg/rails/lib/worker.rb:209:in `block (2 levels) in spawn_workers'
|
129
|
+
/home/copperegg/rails/lib/worker.rb:206:in `times'
|
130
|
+
/home/copperegg/rails/lib/worker.rb:206:in `block in spawn_workers'
|
131
|
+
/home/copperegg/rails/lib/worker.rb:202:in `times'
|
132
|
+
/home/copperegg/rails/lib/worker.rb:202:in `spawn_workers'
|
133
|
+
/home/copperegg/rails/lib/worker.rb:153:in `run'
|
134
|
+
/home/copperegg/rails/script/worker_daemon.rb:10:in `'
|
135
|
+
LINES
|
136
|
+
|
137
|
+
trimmed_lines = CopperEgg::APM.trim_stacktrace(stacktrace.split("\n")).map(&:strip)
|
138
|
+
|
139
|
+
trimmed_stacktrace = <<-LINES
|
140
|
+
/home/copperegg/rails/app/models/cluster.rb:60:in `populate_cache!'
|
141
|
+
.../cluster.rb:48:in `get_nodes'
|
142
|
+
/home/copperegg/rails/lib/store.rb:48:in `io'
|
143
|
+
.../store.rb:218:in `save'
|
144
|
+
/home/copperegg/rails/app/models/sample.rb:74:in `stor'
|
145
|
+
.../sample.rb:284:in `block (2 levels) in save'
|
146
|
+
.../sample.rb:204:in `each'
|
147
|
+
.../sample.rb:204:in `block in save'
|
148
|
+
.../sample.rb:199:in `each'
|
149
|
+
.../sample.rb:199:in `save'
|
150
|
+
/home/copperegg/rails/lib/worker.rb:401:in `save_sample'
|
151
|
+
.../worker.rb:256:in `worker_run'
|
152
|
+
.../worker.rb:170:in `block in start_worker'
|
153
|
+
.../worker.rb:164:in `fork'
|
154
|
+
.../worker.rb:164:in `start_worker'
|
155
|
+
.../worker.rb:209:in `block (2 levels) in spawn_workers'
|
156
|
+
.../worker.rb:206:in `times'
|
157
|
+
.../worker.rb:206:in `block in spawn_workers'
|
158
|
+
.../worker.rb:202:in `times'
|
159
|
+
.../worker.rb:202:in `spawn_workers'
|
160
|
+
.../worker.rb:153:in `run'
|
161
|
+
/home/copperegg/rails/script/worker_daemon.rb:10:in `'
|
162
|
+
LINES
|
163
|
+
|
164
|
+
expect(trimmed_lines).to eq trimmed_stacktrace.split("\n").map(&:strip)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should include all lines if app root is not set" do
|
168
|
+
CopperEgg::APM::Configuration.app_root = nil
|
169
|
+
|
170
|
+
stacktrace = <<-LINES
|
171
|
+
#{File.dirname(File.dirname(__FILE__))}/lib/copperegg/apm/mysql2/client.rb:10:in `query'
|
172
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/mysql2-0.2.18/lib/active_record/connection_adapters/mysql2_adapter.rb:265:in `block in execute'
|
173
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract_adapter.rb:202:in `block in log'
|
174
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activesupport-3.0.20/lib/active_support/notifications/instrumenter.rb:21:in `instrument'
|
175
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract_adapter.rb:200:in `log'
|
176
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/mysql2-0.2.18/lib/active_record/connection_adapters/mysql2_adapter.rb:265:in `execute'
|
177
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/mysql2-0.2.18/lib/active_record/connection_adapters/mysql2_adapter.rb:586:in `select'
|
178
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract/database_statements.rb:7:in `select_all'
|
179
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract/query_cache.rb:56:in `select_all'
|
180
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/base.rb:473:in `find_by_sql'
|
181
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/relation.rb:64:in `to_a'
|
182
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/relation/finder_methods.rb:143:in `all'
|
183
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/base.rb:444:in `all'
|
184
|
+
/home/copperegg/rails/app/models/cluster.rb:60:in `populate_cache!'
|
185
|
+
/home/copperegg/rails/app/models/cluster.rb:48:in `get_nodes'
|
186
|
+
/home/copperegg/rails/lib/store.rb:48:in `io'
|
187
|
+
/home/copperegg/rails/lib/store.rb:218:in `save'
|
188
|
+
/home/copperegg/rails/app/models/sample.rb:74:in `stor'
|
189
|
+
/home/copperegg/rails/app/models/sample.rb:284:in `block (2 levels) in save'
|
190
|
+
/home/copperegg/rails/app/models/sample.rb:204:in `each'
|
191
|
+
/home/copperegg/rails/app/models/sample.rb:204:in `block in save'
|
192
|
+
/home/copperegg/rails/app/models/sample.rb:199:in `each'
|
193
|
+
/home/copperegg/rails/app/models/sample.rb:199:in `save'
|
194
|
+
/home/copperegg/rails/lib/worker.rb:401:in `save_sample'
|
195
|
+
/home/copperegg/rails/lib/worker.rb:256:in `worker_run'
|
196
|
+
/home/copperegg/rails/lib/worker.rb:170:in `block in start_worker'
|
197
|
+
/home/copperegg/rails/lib/worker.rb:164:in `fork'
|
198
|
+
/home/copperegg/rails/lib/worker.rb:164:in `start_worker'
|
199
|
+
/home/copperegg/rails/lib/worker.rb:209:in `block (2 levels) in spawn_workers'
|
200
|
+
/home/copperegg/rails/lib/worker.rb:206:in `times'
|
201
|
+
/home/copperegg/rails/lib/worker.rb:206:in `block in spawn_workers'
|
202
|
+
/home/copperegg/rails/lib/worker.rb:202:in `times'
|
203
|
+
/home/copperegg/rails/lib/worker.rb:202:in `spawn_workers'
|
204
|
+
/home/copperegg/rails/lib/worker.rb:153:in `run'
|
205
|
+
/home/copperegg/rails/script/worker_daemon.rb:10:in `'
|
206
|
+
LINES
|
207
|
+
|
208
|
+
trimmed_lines = CopperEgg::APM.trim_stacktrace(stacktrace.split("\n")).map(&:strip)
|
209
|
+
|
210
|
+
trimmed_stacktrace = <<-LINES
|
211
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/mysql2-0.2.18/lib/active_record/connection_adapters/mysql2_adapter.rb:265:in `block in execute'
|
212
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract_adapter.rb:202:in `block in log'
|
213
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activesupport-3.0.20/lib/active_support/notifications/instrumenter.rb:21:in `instrument'
|
214
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract_adapter.rb:200:in `log'
|
215
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/mysql2-0.2.18/lib/active_record/connection_adapters/mysql2_adapter.rb:265:in `execute'
|
216
|
+
.../mysql2_adapter.rb:586:in `select'
|
217
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract/database_statements.rb:7:in `select_all'
|
218
|
+
.../query_cache.rb:56:in `select_all'
|
219
|
+
.../base.rb:473:in `find_by_sql'
|
220
|
+
.../relation.rb:64:in `to_a'
|
221
|
+
/home/copperegg/.rvm/gems/ruby-1.9.2-p290@gems/activerecord-3.0.20/lib/active_record/relation/finder_methods.rb:143:in `all'
|
222
|
+
.../base.rb:444:in `all'
|
223
|
+
/home/copperegg/rails/app/models/cluster.rb:60:in `populate_cache!'
|
224
|
+
.../cluster.rb:48:in `get_nodes'
|
225
|
+
/home/copperegg/rails/lib/store.rb:48:in `io'
|
226
|
+
.../store.rb:218:in `save'
|
227
|
+
/home/copperegg/rails/app/models/sample.rb:74:in `stor'
|
228
|
+
.../sample.rb:284:in `block (2 levels) in save'
|
229
|
+
.../sample.rb:204:in `each'
|
230
|
+
.../sample.rb:204:in `block in save'
|
231
|
+
.../sample.rb:199:in `each'
|
232
|
+
.../sample.rb:199:in `save'
|
233
|
+
/home/copperegg/rails/lib/worker.rb:401:in `save_sample'
|
234
|
+
.../worker.rb:256:in `worker_run'
|
235
|
+
.../worker.rb:170:in `block in start_worker'
|
236
|
+
.../worker.rb:164:in `fork'
|
237
|
+
.../worker.rb:164:in `start_worker'
|
238
|
+
.../worker.rb:209:in `block (2 levels) in spawn_workers'
|
239
|
+
.../worker.rb:206:in `times'
|
240
|
+
.../worker.rb:206:in `block in spawn_workers'
|
241
|
+
.../worker.rb:202:in `times'
|
242
|
+
.../worker.rb:202:in `spawn_workers'
|
243
|
+
.../worker.rb:153:in `run'
|
244
|
+
/home/copperegg/rails/script/worker_daemon.rb:10:in `'
|
245
|
+
LINES
|
246
|
+
|
247
|
+
expect(trimmed_lines).to eq trimmed_stacktrace.split("\n").map(&:strip)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
describe ".benchmark" do
|
252
|
+
it "should measure class method execution time" do
|
253
|
+
expect(Foo.bar).to eq 4950
|
254
|
+
|
255
|
+
last_payload = CopperEgg::APM.send(:class_variable_get, :@@payload_cache).split("\x00").select {|i| i.size > 2}.map {|i| i.sub(/^[^\{]+/,'')}.last
|
256
|
+
hash = JSON.parse last_payload
|
257
|
+
|
258
|
+
expect(hash.keys.sort).to eq ["id", "inst"]
|
259
|
+
expect(hash["id"]).to match(/\A[0-1a-z]{16}\z/i)
|
260
|
+
expect(hash["inst"].keys.sort).to eq ["method", "time"]
|
261
|
+
expect(hash["inst"]["method"]).to eq "Foo.bar {Ruby}"
|
262
|
+
expect(hash["inst"]["time"].to_s).to match(/\A\d+\Z/)
|
263
|
+
end
|
264
|
+
|
265
|
+
it "should measure instance method execution time" do
|
266
|
+
expect(Foo.new.bar).to eq 4950
|
267
|
+
|
268
|
+
last_payload = CopperEgg::APM.send(:class_variable_get, :@@payload_cache).split("\x00").select {|i| i.size > 2}.map {|i| i.sub(/^[^\{]+/,'')}.last
|
269
|
+
hash = JSON.parse last_payload
|
270
|
+
|
271
|
+
expect(hash.keys.sort).to eq ["id", "inst"]
|
272
|
+
expect(hash["id"]).to match(/\A[0-1a-z]{16}\z/i)
|
273
|
+
expect(hash["inst"].keys.sort).to eq ["method", "time"]
|
274
|
+
expect(hash["inst"]["method"]).to eq "Foo#bar {Ruby}"
|
275
|
+
expect(hash["inst"]["time"].to_s).to match(/\A\d+\Z/)
|
276
|
+
end
|
277
|
+
|
278
|
+
it "should measure module method execution time" do
|
279
|
+
expect(Baz.bar).to eq 4950
|
280
|
+
|
281
|
+
last_payload = CopperEgg::APM.send(:class_variable_get, :@@payload_cache).split("\x00").select {|i| i.size > 2}.map {|i| i.sub(/^[^\{]+/,'')}.last
|
282
|
+
hash = JSON.parse last_payload
|
283
|
+
|
284
|
+
expect(hash.keys.sort).to eq ["id", "inst"]
|
285
|
+
expect(hash["id"]).to match(/\A[0-1a-z]{16}\z/i)
|
286
|
+
expect(hash["inst"].keys.sort).to eq ["method", "time"]
|
287
|
+
expect(hash["inst"]["method"]).to eq "Baz.bar {Ruby}"
|
288
|
+
expect(hash["inst"]["time"].to_s).to match(/\A\d+\Z/)
|
289
|
+
end
|
290
|
+
|
291
|
+
it "should not label the method based on the argument passed" do
|
292
|
+
expect(Foo.new.baz).to eq 4950
|
293
|
+
|
294
|
+
last_payload = CopperEgg::APM.send(:class_variable_get, :@@payload_cache).split("\x00").select {|i| i.size > 2}.map {|i| i.sub(/^[^\{]+/,'')}.last
|
295
|
+
hash = JSON.parse last_payload
|
296
|
+
|
297
|
+
expect(hash.keys.sort).to eq ["id", "inst"]
|
298
|
+
expect(hash["id"]).to match(/\A[0-1a-z]{16}\z/i)
|
299
|
+
expect(hash["inst"].keys.sort).to eq ["method", "time"]
|
300
|
+
expect(hash["inst"]["method"]).to eq "NilClass#baz {Ruby}"
|
301
|
+
expect(hash["inst"]["time"].to_s).to match(/\A\d+\Z/)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
describe ".obfuscate_sql" do
|
306
|
+
it "shoudl obfuscate select statement" do
|
307
|
+
sql = "SELECT `annotations`.* FROM `annotations` WHERE (`annotations`.id = 2) AND (updated_at > '#{Time.now.strftime('%Y-%m-%d %H:%M%S')}')"
|
308
|
+
|
309
|
+
expect(CopperEgg::APM.obfuscate_sql(sql)).to eq "SELECT annotations.* FROM annotations WHERE (annotations.id = ?) AND (updated_at > ?)"
|
310
|
+
end
|
311
|
+
|
312
|
+
it "should obfuscate items in a list" do
|
313
|
+
sql = 'SELECT COUNT(`items`.`id`) FROM `items` WHERE (`items`.id = 2) AND (state in ("enabled","expired"))'
|
314
|
+
|
315
|
+
expect(CopperEgg::APM.obfuscate_sql(sql)).to eq "SELECT COUNT(items.id) FROM items WHERE (items.id = ?) AND (state in (?,?))"
|
316
|
+
end
|
317
|
+
|
318
|
+
it "should obfuscate update statement" do
|
319
|
+
sql = "UPDATE `users` SET `phone` = '512.777.9311', `updated_at` = '#{Time.now.strftime('%Y-%m-%d %H:%M%S')}' WHERE `users`.`id` = 1"
|
320
|
+
|
321
|
+
expect(CopperEgg::APM.obfuscate_sql(sql)).to eq "UPDATE users SET phone = ?, updated_at = ? WHERE users.id = ?"
|
322
|
+
end
|
323
|
+
|
324
|
+
it "should obfuscate delete statement" do
|
325
|
+
sql = "DELETE FROM `reports` WHERE `reports`.`id` = 99"
|
326
|
+
|
327
|
+
expect(CopperEgg::APM.obfuscate_sql(sql)).to eq "DELETE FROM reports WHERE reports.id = ?"
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|