traceview 3.6.0 → 3.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +12 -1
  3. data/CHANGELOG.md +11 -0
  4. data/CONFIG.md +22 -5
  5. data/Rakefile +2 -2
  6. data/gemfiles/delayed_job.gemfile +1 -1
  7. data/gemfiles/frameworks.gemfile +1 -1
  8. data/gemfiles/libraries.gemfile +4 -3
  9. data/gemfiles/rails31.gemfile +2 -0
  10. data/gemfiles/rails32.gemfile +5 -2
  11. data/gemfiles/rails40.gemfile +5 -3
  12. data/gemfiles/rails41.gemfile +6 -4
  13. data/gemfiles/rails42.gemfile +3 -1
  14. data/gemfiles/rails50.gemfile +43 -0
  15. data/lib/rails/generators/traceview/templates/traceview_initializer.rb +56 -32
  16. data/lib/traceview/base.rb +1 -1
  17. data/lib/traceview/frameworks/rails.rb +6 -9
  18. data/lib/traceview/frameworks/rails/inst/action_controller.rb +2 -135
  19. data/lib/traceview/frameworks/rails/inst/action_controller2.rb +59 -0
  20. data/lib/traceview/frameworks/rails/inst/action_controller3.rb +49 -0
  21. data/lib/traceview/frameworks/rails/inst/action_controller4.rb +40 -0
  22. data/lib/traceview/frameworks/rails/inst/action_controller5.rb +39 -0
  23. data/lib/traceview/frameworks/rails/inst/action_view.rb +1 -1
  24. data/lib/traceview/frameworks/rails/inst/active_record.rb +6 -3
  25. data/lib/traceview/frameworks/rails/inst/connection_adapters/postgresql.rb +1 -1
  26. data/lib/traceview/frameworks/rails/inst/connection_adapters/utils.rb +30 -36
  27. data/lib/traceview/frameworks/rails/inst/connection_adapters/utils5x.rb +100 -0
  28. data/lib/traceview/test.rb +39 -0
  29. data/lib/traceview/version.rb +1 -1
  30. data/test/frameworks/rails3x_test.rb +163 -7
  31. data/test/frameworks/rails4x_test.rb +162 -13
  32. data/test/frameworks/rails5x_test.rb +213 -0
  33. data/test/instrumentation/excon_test.rb +3 -0
  34. data/test/instrumentation/sequel_mysql2_test.rb +2 -5
  35. data/test/instrumentation/sequel_mysql_test.rb +2 -5
  36. data/test/instrumentation/sequel_pg_test.rb +2 -5
  37. data/test/minitest_helper.rb +25 -21
  38. data/test/servers/delayed_job.rb +2 -6
  39. data/test/servers/rails3x_8140.rb +16 -6
  40. data/test/servers/rails4x_8140.rb +20 -9
  41. data/test/servers/rails5x_8140.rb +112 -0
  42. metadata +13 -4
  43. data/lib/traceview/frameworks/rails/inst/connection_adapters/oracle.rb +0 -18
@@ -0,0 +1,213 @@
1
+ # Copyright (c) 2015 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ require "minitest_helper"
5
+
6
+ if defined?(::Rails)
7
+
8
+ describe "Rails5x" do
9
+ before do
10
+ clear_all_traces
11
+ ENV['DBTYPE'] = "postgresql" unless ENV['DBTYPE']
12
+ end
13
+
14
+ it "should trace a request to a rails stack" do
15
+
16
+ uri = URI.parse('http://127.0.0.1:8140/hello/world')
17
+ r = Net::HTTP.get_response(uri)
18
+
19
+ traces = get_all_traces
20
+
21
+
22
+ traces.count.must_equal 7
23
+ unless defined?(JRUBY_VERSION)
24
+ # We don't test this under JRuby because the Java instrumentation
25
+ # for the DB drivers doesn't use our test reporter hence we won't
26
+ # see all trace events. :-( To be improved.
27
+ valid_edges?(traces).must_equal true
28
+ end
29
+ validate_outer_layers(traces, 'rack')
30
+
31
+ traces[0]['Layer'].must_equal "rack"
32
+ traces[0]['Label'].must_equal "entry"
33
+ traces[0]['URL'].must_equal "/hello/world"
34
+
35
+ traces[1]['Layer'].must_equal "rack"
36
+ traces[1]['Label'].must_equal "info"
37
+
38
+ traces[2]['Layer'].must_equal "rails"
39
+ traces[2]['Label'].must_equal "entry"
40
+ traces[2]['Controller'].must_equal "HelloController"
41
+ traces[2]['Action'].must_equal "world"
42
+
43
+ traces[3]['Layer'].must_equal "actionview"
44
+ traces[3]['Label'].must_equal "entry"
45
+
46
+ traces[4]['Layer'].must_equal "actionview"
47
+ traces[4]['Label'].must_equal "exit"
48
+
49
+ traces[5]['Layer'].must_equal "rails"
50
+ traces[5]['Label'].must_equal "exit"
51
+
52
+ traces[6]['Layer'].must_equal "rack"
53
+ traces[6]['Label'].must_equal "exit"
54
+
55
+ # Validate the existence of the response header
56
+ r.header.key?('X-Trace').must_equal true
57
+ r.header['X-Trace'].must_equal traces[6]['X-Trace']
58
+ end
59
+
60
+ it "should trace rails postgres db calls" do
61
+ # Skip for JRuby since the java instrumentation
62
+ # handles DB instrumentation for JRuby
63
+ skip if defined?(JRUBY_VERSION) || ENV['DBTYPE'] != 'postgresql'
64
+
65
+ uri = URI.parse('http://127.0.0.1:8140/hello/db')
66
+ r = Net::HTTP.get_response(uri)
67
+
68
+ traces = get_all_traces
69
+
70
+ traces.count.must_equal 13
71
+ valid_edges?(traces).must_equal true
72
+ validate_outer_layers(traces, 'rack')
73
+
74
+ traces[3]['Layer'].must_equal "activerecord"
75
+ traces[3]['Label'].must_equal "entry"
76
+ traces[3]['Flavor'].must_equal "postgresql"
77
+ traces[3]['Query'].must_equal "INSERT INTO \"widgets\" (\"name\", \"description\", \"created_at\", \"updated_at\") VALUES ($1, $2, $3, $4) RETURNING \"id\""
78
+ traces[3]['Name'].must_equal "SQL"
79
+ traces[3].key?('Backtrace').must_equal true
80
+
81
+ traces[4]['Layer'].must_equal "activerecord"
82
+ traces[4]['Label'].must_equal "exit"
83
+
84
+ traces[5]['Layer'].must_equal "activerecord"
85
+ traces[5]['Label'].must_equal "entry"
86
+ traces[5]['Flavor'].must_equal "postgresql"
87
+ traces[5]['Query'].must_equal "SELECT \"widgets\".* FROM \"widgets\" WHERE \"widgets\".\"name\" = $1 ORDER BY \"widgets\".\"id\" ASC LIMIT $2"
88
+ traces[5]['Name'].must_equal "Widget Load"
89
+ traces[5].key?('Backtrace').must_equal true
90
+ traces[5].key?('QueryArgs').must_equal true
91
+
92
+ traces[6]['Layer'].must_equal "activerecord"
93
+ traces[6]['Label'].must_equal "exit"
94
+
95
+ traces[7]['Layer'].must_equal "activerecord"
96
+ traces[7]['Label'].must_equal "entry"
97
+ traces[7]['Flavor'].must_equal "postgresql"
98
+ traces[7]['Query'].must_equal "DELETE FROM \"widgets\" WHERE \"widgets\".\"id\" = $1"
99
+ traces[7]['Name'].must_equal "SQL"
100
+ traces[7].key?('Backtrace').must_equal true
101
+ traces[7].key?('QueryArgs').must_equal true
102
+
103
+ traces[8]['Layer'].must_equal "activerecord"
104
+ traces[8]['Label'].must_equal "exit"
105
+
106
+ # Validate the existence of the response header
107
+ r.header.key?('X-Trace').must_equal true
108
+ r.header['X-Trace'].must_equal traces[12]['X-Trace']
109
+ end
110
+
111
+ it "should trace rails mysql2 db calls" do
112
+ # Skip for JRuby since the java instrumentation
113
+ # handles DB instrumentation for JRuby
114
+ skip if defined?(JRUBY_VERSION) || ENV['DBTYPE'] != 'mysql2'
115
+
116
+ uri = URI.parse('http://127.0.0.1:8140/hello/db')
117
+ r = Net::HTTP.get_response(uri)
118
+
119
+ traces = get_all_traces
120
+
121
+ traces.count.must_equal 13
122
+ valid_edges?(traces).must_equal true
123
+ validate_outer_layers(traces, 'rack')
124
+
125
+ traces[3]['Layer'].must_equal "activerecord"
126
+ traces[3]['Label'].must_equal "entry"
127
+ traces[3]['Flavor'].must_equal "mysql"
128
+
129
+ # Replace the datestamps with xxx to make testing easier
130
+ sql = traces[3]['Query'].gsub(/\d\d\d\d-\d\d-\d\d\s\d\d:\d\d:\d\d/, 'xxx')
131
+ sql.must_equal "INSERT INTO `widgets` (`name`, `description`, `created_at`, `updated_at`) VALUES ('blah', 'This is an amazing widget.', 'xxx', 'xxx')"
132
+
133
+ traces[3]['Name'].must_equal "SQL"
134
+ traces[3].key?('Backtrace').must_equal true
135
+
136
+ traces[4]['Layer'].must_equal "activerecord"
137
+ traces[4]['Label'].must_equal "exit"
138
+
139
+ traces[5]['Layer'].must_equal "activerecord"
140
+ traces[5]['Label'].must_equal "entry"
141
+ traces[5]['Flavor'].must_equal "mysql"
142
+ traces[5]['Query'].must_equal "SELECT `widgets`.* FROM `widgets` WHERE `widgets`.`name` = 'blah' ORDER BY `widgets`.`id` ASC LIMIT 1"
143
+ traces[5]['Name'].must_equal "Widget Load"
144
+ traces[5].key?('Backtrace').must_equal true
145
+ traces[5].key?('QueryArgs').must_equal true
146
+
147
+ traces[6]['Layer'].must_equal "activerecord"
148
+ traces[6]['Label'].must_equal "exit"
149
+
150
+ traces[7]['Layer'].must_equal "activerecord"
151
+ traces[7]['Label'].must_equal "entry"
152
+ traces[7]['Flavor'].must_equal "mysql"
153
+
154
+ # Replace the datestamps with xxx to make testing easier
155
+ sql = traces[7]['Query'].gsub /\d+/, 'xxx'
156
+ sql.must_equal "DELETE FROM `widgets` WHERE `widgets`.`id` = xxx"
157
+
158
+ traces[7]['Name'].must_equal "SQL"
159
+ traces[7].key?('Backtrace').must_equal true
160
+ traces[7].key?('QueryArgs').must_equal true
161
+
162
+ traces[8]['Layer'].must_equal "activerecord"
163
+ traces[8]['Label'].must_equal "exit"
164
+
165
+ # Validate the existence of the response header
166
+ r.header.key?('X-Trace').must_equal true
167
+ r.header['X-Trace'].must_equal traces[12]['X-Trace']
168
+ end
169
+
170
+ it "should trace a request to a rails metal stack" do
171
+
172
+ uri = URI.parse('http://127.0.0.1:8140/hello/metal')
173
+ r = Net::HTTP.get_response(uri)
174
+
175
+ traces = get_all_traces
176
+
177
+ traces.count.must_equal 5
178
+ unless defined?(JRUBY_VERSION)
179
+ # We don't test this under JRuby because the Java instrumentation
180
+ # for the DB drivers doesn't use our test reporter hence we won't
181
+ # see all trace events. :-( To be improved.
182
+ valid_edges?(traces).must_equal true
183
+ end
184
+ validate_outer_layers(traces, 'rack')
185
+
186
+ traces[0]['Layer'].must_equal "rack"
187
+ traces[0]['Label'].must_equal "entry"
188
+ traces[0]['URL'].must_equal "/hello/metal"
189
+
190
+ traces[1]['Layer'].must_equal "rack"
191
+ traces[1]['Label'].must_equal "info"
192
+
193
+ traces[2]['Label'].must_equal "profile_entry"
194
+ traces[2]['Language'].must_equal "ruby"
195
+ traces[2]['ProfileName'].must_equal "world"
196
+ traces[2]['MethodName'].must_equal "world"
197
+ traces[2]['Class'].must_equal "FerroController"
198
+ traces[2]['Controller'].must_equal "FerroController"
199
+ traces[2]['Action'].must_equal "world"
200
+
201
+ traces[3]['Label'].must_equal "profile_exit"
202
+ traces[3]['Language'].must_equal "ruby"
203
+ traces[3]['ProfileName'].must_equal "world"
204
+
205
+ traces[4]['Layer'].must_equal "rack"
206
+ traces[4]['Label'].must_equal "exit"
207
+
208
+ # Validate the existence of the response header
209
+ r.header.key?('X-Trace').must_equal true
210
+ r.header['X-Trace'].must_equal traces[4]['X-Trace']
211
+ end
212
+ end
213
+ end
@@ -16,6 +16,9 @@ class ExconTest < Minitest::Test
16
16
  clear_all_traces
17
17
  get "/"
18
18
  xtrace = last_response['X-Trace']
19
+ # FIXME: This test passes inconsistently. Investigate
20
+ # Rack response header management under JRUBY.
21
+ skip if defined?(JRUBY_VERSION)
19
22
  assert xtrace
20
23
  assert TraceView::XTrace.valid?(xtrace)
21
24
  end
@@ -5,11 +5,8 @@ require 'minitest_helper'
5
5
 
6
6
  if defined?(::Sequel) && !defined?(JRUBY_VERSION)
7
7
 
8
- if ENV.key?('TRAVIS_MYSQL_PASS')
9
- MYSQL2_DB = Sequel.connect("mysql2://root:#{ENV['TRAVIS_MYSQL_PASS']}@127.0.0.1:3306/travis_ci_test")
10
- else
11
- MYSQL2_DB = Sequel.connect('mysql2://root@127.0.0.1:3306/travis_ci_test')
12
- end
8
+ TraceView::Test.set_mysql2_env
9
+ MYSQL2_DB = Sequel.connect(ENV['DATABASE_URL'])
13
10
 
14
11
  unless MYSQL2_DB.table_exists?(:items)
15
12
  MYSQL2_DB.create_table :items do
@@ -5,11 +5,8 @@ require 'minitest_helper'
5
5
 
6
6
  if defined?(::Sequel) && !defined?(JRUBY_VERSION)
7
7
 
8
- if ENV.key?('TRAVIS_MYSQL_PASS')
9
- MYSQL_DB = Sequel.connect("mysql://root:#{ENV['TRAVIS_MYSQL_PASS']}@127.0.0.1:3306/travis_ci_test")
10
- else
11
- MYSQL_DB = Sequel.connect('mysql://root@127.0.0.1:3306/travis_ci_test')
12
- end
8
+ TraceView::Test.set_mysql_env
9
+ MYSQL_DB = Sequel.connect(ENV['DATABASE_URL'])
13
10
 
14
11
  unless MYSQL_DB.table_exists?(:items)
15
12
  MYSQL_DB.create_table :items do
@@ -5,11 +5,8 @@ require 'minitest_helper'
5
5
 
6
6
  if defined?(::Sequel) && !defined?(JRUBY_VERSION)
7
7
 
8
- if ENV.key?('TRAVIS_PSQL_PASS')
9
- PG_DB = Sequel.connect("postgres://postgres:#{ENV['TRAVIS_PSQL_PASS']}@127.0.0.1:5432/travis_ci_test")
10
- else
11
- PG_DB = Sequel.connect('postgres://postgres@127.0.0.1:5432/travis_ci_test')
12
- end
8
+ TraceView::Test.set_postgresql_env
9
+ PG_DB = Sequel.connect(ENV['DATABASE_URL'])
13
10
 
14
11
  unless PG_DB.table_exists?(:items)
15
12
  PG_DB.create_table :items do
@@ -7,7 +7,6 @@ require "minitest/spec"
7
7
  require "minitest/autorun"
8
8
  require "minitest/reporters"
9
9
  require "minitest/debugger" if ENV['DEBUG']
10
- require "sinatra"
11
10
 
12
11
  require "minitest/hell"
13
12
  class Minitest::Test
@@ -58,6 +57,9 @@ case File.basename(ENV['BUNDLE_GEMFILE'])
58
57
  when /delayed_job/
59
58
  require './test/servers/delayed_job'
60
59
 
60
+ when /rails5/
61
+ require './test/servers/rails5x_8140'
62
+
61
63
  when /rails4/
62
64
  require './test/servers/rails4x_8140'
63
65
 
@@ -201,29 +203,31 @@ def layer_doesnt_have_key(traces, layer, key)
201
203
  has_key.must_equal false
202
204
  end
203
205
 
204
- ##
205
- # Sinatra and Padrino Related Helpers
206
- #
207
- # Taken from padrino-core gem
208
- #
209
-
210
- class Sinatra::Base
211
- # Allow assertions in request context
212
- include MiniTest::Assertions
213
- end
206
+ if (File.basename(ENV['BUNDLE_GEMFILE']) =~ /^frameworks/) == 0
207
+ require "sinatra"
208
+ ##
209
+ # Sinatra and Padrino Related Helpers
210
+ #
211
+ # Taken from padrino-core gem
212
+ #
213
+ class Sinatra::Base
214
+ # Allow assertions in request context
215
+ include MiniTest::Assertions
216
+ end
214
217
 
215
218
 
216
- class MiniTest::Spec
217
- include Rack::Test::Methods
219
+ class MiniTest::Spec
220
+ include Rack::Test::Methods
218
221
 
219
- # Sets up a Sinatra::Base subclass defined with the block
220
- # given. Used in setup or individual spec methods to establish
221
- # the application.
222
- def mock_app(base=Padrino::Application, &block)
223
- @app = Sinatra.new(base, &block)
224
- end
222
+ # Sets up a Sinatra::Base subclass defined with the block
223
+ # given. Used in setup or individual spec methods to establish
224
+ # the application.
225
+ def mock_app(base=Padrino::Application, &block)
226
+ @app = Sinatra.new(base, &block)
227
+ end
225
228
 
226
- def app
227
- Rack::Lint.new(@app)
229
+ def app
230
+ Rack::Lint.new(@app)
231
+ end
228
232
  end
229
233
  end
@@ -10,13 +10,9 @@ require File.expand_path(File.dirname(__FILE__) + '/../models/widget')
10
10
  TraceView.logger.level = Logger::DEBUG
11
11
  TraceView.logger.info "[traceview/info] Starting background utility rails app on localhost:8140."
12
12
 
13
- if ENV.key?('TRAVIS_PSQL_PASS')
14
- DJ_DB_URL = "postgres://postgres:#{ENV['TRAVIS_PSQL_PASS']}@127.0.0.1:5432/travis_ci_test"
15
- else
16
- DJ_DB_URL = 'postgres://postgres@127.0.0.1:5432/travis_ci_test'
17
- end
13
+ TraceView::Test.set_postgresql_env
18
14
 
19
- ActiveRecord::Base.establish_connection(DJ_DB_URL)
15
+ ActiveRecord::Base.establish_connection(ENV['DATABASE_URL'])
20
16
 
21
17
  unless ActiveRecord::Base.connection.table_exists? :delayed_jobs
22
18
  TraceView.logger.info "[traceview/servers] Creating DelayedJob DB table."
@@ -23,10 +23,15 @@ require File.expand_path(File.dirname(__FILE__) + '/../models/widget')
23
23
 
24
24
  TraceView.logger.info "[traceview/info] Starting background utility rails app on localhost:8140."
25
25
 
26
- if ENV.key?('TRAVIS_PSQL_PASS')
27
- ENV['DATABASE_URL'] = "postgresql://postgres:#{ENV['TRAVIS_PSQL_PASS']}@127.0.0.1:5432/travis_ci_test"
26
+ # Set the database. Default is postgresql.
27
+ if ENV['DBTYPE'] == 'mysql2'
28
+ TraceView::Test.set_mysql2_env
29
+ elsif ENV['DBTYPE'] == 'mysql'
30
+ TraceView::Test.set_mysql_env
28
31
  else
29
- ENV['DATABASE_URL'] = 'postgresql://postgres@127.0.0.1:5432/travis_ci_test'
32
+ TV.logger.warn "Unidentified DBTYPE: #{ENV['DBTYPE']}" unless ENV['DBTYPE'] == "postgresql"
33
+ TV.logger.debug "Defaulting to postgres DB for background Rails server."
34
+ TraceView::Test.set_postgresql_env
30
35
  end
31
36
 
32
37
  ActiveRecord::Base.establish_connection(ENV['DATABASE_URL'])
@@ -75,9 +80,14 @@ class HelloController < ActionController::Base
75
80
  end
76
81
 
77
82
  def db
78
- Widget.all.first
79
- w = Widget.new(:name => 'blah', :description => 'This is an amazing widget.')
80
- w.save
83
+ # Create a widget
84
+ w1 = Widget.new(:name => 'blah', :description => 'This is an amazing widget.')
85
+ w1.save
86
+
87
+ # query for that widget
88
+ w2 = Widget.where(:name => 'blah').first
89
+ w2.delete
90
+
81
91
  render :text => "Hello database!"
82
92
  end
83
93
  end
@@ -17,11 +17,6 @@
17
17
  # existing in any Rails 4 app. Here they are simply in one
18
18
  # file and without the comments.
19
19
  #
20
- if ENV.key?('TRAVIS_PSQL_PASS')
21
- ENV['DATABASE_URL'] = "postgresql://postgres:#{ENV['TRAVIS_PSQL_PASS']}@127.0.0.1:5432/travis_ci_test"
22
- else
23
- ENV['DATABASE_URL'] = 'postgresql://postgres@127.0.0.1:5432/travis_ci_test'
24
- end
25
20
 
26
21
  require "rails/all"
27
22
  require "action_controller/railtie" # require more if needed
@@ -30,6 +25,17 @@ require File.expand_path(File.dirname(__FILE__) + '/../models/widget')
30
25
 
31
26
  TraceView.logger.info "[traceview/info] Starting background utility rails app on localhost:8140."
32
27
 
28
+ # Set the database. Default is postgresql.
29
+ if ENV['DBTYPE'] == 'mysql2'
30
+ TraceView::Test.set_mysql2_env
31
+ elsif ENV['DBTYPE'] == 'mysql'
32
+ TraceView::Test.set_mysql_env
33
+ else
34
+ TV.logger.warn "Unidentified DBTYPE: #{ENV['DBTYPE']}" unless ENV['DBTYPE'] == "postgresql"
35
+ TV.logger.debug "Defaulting to postgres DB for background Rails server."
36
+ TraceView::Test.set_postgresql_env
37
+ end
38
+
33
39
  ActiveRecord::Base.establish_connection(ENV['DATABASE_URL'])
34
40
 
35
41
  unless ActiveRecord::Base.connection.table_exists? 'widgets'
@@ -76,9 +82,14 @@ class HelloController < ActionController::Base
76
82
  end
77
83
 
78
84
  def db
79
- Widget.all.first
80
- w = Widget.new(:name => 'blah', :description => 'This is an amazing widget.')
81
- w.save
85
+ # Create a widget
86
+ w1 = Widget.new(:name => 'blah', :description => 'This is an amazing widget.')
87
+ w1.save
88
+
89
+ # query for that widget
90
+ w2 = Widget.where(:name => 'blah').first
91
+ w2.delete
92
+
82
93
  render :text => "Hello database!"
83
94
  end
84
95
  end
@@ -96,7 +107,7 @@ TraceView::API.profile_method(FerroController, :world)
96
107
  Rails40MetalStack.initialize!
97
108
 
98
109
  Thread.new do
99
- Rack::Handler::Puma.run(Rails40MetalStack.to_app, {:Host => '127.0.0.1', :Port => 8140})
110
+ Rack::Handler::Puma.run(Rails40MetalStack.to_app, {:Host => '127.0.0.1', :Port => 8140, :Threads => "0:1"})
100
111
  end
101
112
 
102
113
  sleep(2)