traceview 3.6.0 → 3.7.0

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 (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)