traceview 3.0.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 (137) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rubocop.yml +5 -0
  4. data/.travis.yml +58 -0
  5. data/Appraisals +10 -0
  6. data/CHANGELOG.md +490 -0
  7. data/CONFIG.md +16 -0
  8. data/Gemfile +95 -0
  9. data/LICENSE +199 -0
  10. data/README.md +380 -0
  11. data/Rakefile +109 -0
  12. data/examples/DNT.md +35 -0
  13. data/examples/carrying_context.rb +225 -0
  14. data/examples/instrumenting_metal_controller.rb +8 -0
  15. data/examples/puma_on_heroku_config.rb +17 -0
  16. data/examples/tracing_async_threads.rb +125 -0
  17. data/examples/tracing_background_jobs.rb +52 -0
  18. data/examples/tracing_forked_processes.rb +100 -0
  19. data/examples/unicorn_on_heroku_config.rb +28 -0
  20. data/ext/oboe_metal/extconf.rb +61 -0
  21. data/ext/oboe_metal/noop/noop.c +7 -0
  22. data/ext/oboe_metal/src/bson/bson.h +221 -0
  23. data/ext/oboe_metal/src/bson/platform_hacks.h +91 -0
  24. data/ext/oboe_metal/src/oboe.h +275 -0
  25. data/ext/oboe_metal/src/oboe.hpp +352 -0
  26. data/ext/oboe_metal/src/oboe_wrap.cxx +3886 -0
  27. data/ext/oboe_metal/tests/test.rb +11 -0
  28. data/gemfiles/mongo.gemfile +33 -0
  29. data/gemfiles/moped.gemfile +33 -0
  30. data/get_version.rb +5 -0
  31. data/init.rb +4 -0
  32. data/lib/joboe_metal.rb +206 -0
  33. data/lib/oboe.rb +7 -0
  34. data/lib/oboe/README +2 -0
  35. data/lib/oboe/backward_compatibility.rb +59 -0
  36. data/lib/oboe/inst/rack.rb +11 -0
  37. data/lib/oboe_metal.rb +151 -0
  38. data/lib/rails/generators/traceview/install_generator.rb +76 -0
  39. data/lib/rails/generators/traceview/templates/traceview_initializer.rb +159 -0
  40. data/lib/traceview.rb +62 -0
  41. data/lib/traceview/api.rb +18 -0
  42. data/lib/traceview/api/layerinit.rb +51 -0
  43. data/lib/traceview/api/logging.rb +209 -0
  44. data/lib/traceview/api/memcache.rb +31 -0
  45. data/lib/traceview/api/profiling.rb +50 -0
  46. data/lib/traceview/api/tracing.rb +135 -0
  47. data/lib/traceview/api/util.rb +121 -0
  48. data/lib/traceview/base.rb +225 -0
  49. data/lib/traceview/config.rb +238 -0
  50. data/lib/traceview/frameworks/grape.rb +97 -0
  51. data/lib/traceview/frameworks/padrino.rb +64 -0
  52. data/lib/traceview/frameworks/padrino/templates.rb +58 -0
  53. data/lib/traceview/frameworks/rails.rb +145 -0
  54. data/lib/traceview/frameworks/rails/helpers/rum/rum_ajax_header.js.erb +5 -0
  55. data/lib/traceview/frameworks/rails/helpers/rum/rum_footer.js.erb +1 -0
  56. data/lib/traceview/frameworks/rails/helpers/rum/rum_header.js.erb +3 -0
  57. data/lib/traceview/frameworks/rails/inst/action_controller.rb +216 -0
  58. data/lib/traceview/frameworks/rails/inst/action_view.rb +56 -0
  59. data/lib/traceview/frameworks/rails/inst/action_view_2x.rb +54 -0
  60. data/lib/traceview/frameworks/rails/inst/action_view_30.rb +48 -0
  61. data/lib/traceview/frameworks/rails/inst/active_record.rb +24 -0
  62. data/lib/traceview/frameworks/rails/inst/connection_adapters/mysql.rb +43 -0
  63. data/lib/traceview/frameworks/rails/inst/connection_adapters/mysql2.rb +28 -0
  64. data/lib/traceview/frameworks/rails/inst/connection_adapters/oracle.rb +18 -0
  65. data/lib/traceview/frameworks/rails/inst/connection_adapters/postgresql.rb +30 -0
  66. data/lib/traceview/frameworks/rails/inst/connection_adapters/utils.rb +117 -0
  67. data/lib/traceview/frameworks/sinatra.rb +95 -0
  68. data/lib/traceview/frameworks/sinatra/templates.rb +56 -0
  69. data/lib/traceview/inst/cassandra.rb +279 -0
  70. data/lib/traceview/inst/dalli.rb +86 -0
  71. data/lib/traceview/inst/em-http-request.rb +99 -0
  72. data/lib/traceview/inst/excon.rb +111 -0
  73. data/lib/traceview/inst/faraday.rb +73 -0
  74. data/lib/traceview/inst/http.rb +87 -0
  75. data/lib/traceview/inst/httpclient.rb +173 -0
  76. data/lib/traceview/inst/memcache.rb +102 -0
  77. data/lib/traceview/inst/memcached.rb +94 -0
  78. data/lib/traceview/inst/mongo.rb +238 -0
  79. data/lib/traceview/inst/moped.rb +474 -0
  80. data/lib/traceview/inst/rack.rb +122 -0
  81. data/lib/traceview/inst/redis.rb +271 -0
  82. data/lib/traceview/inst/resque.rb +192 -0
  83. data/lib/traceview/inst/rest-client.rb +38 -0
  84. data/lib/traceview/inst/sequel.rb +162 -0
  85. data/lib/traceview/inst/typhoeus.rb +102 -0
  86. data/lib/traceview/instrumentation.rb +21 -0
  87. data/lib/traceview/loading.rb +94 -0
  88. data/lib/traceview/logger.rb +41 -0
  89. data/lib/traceview/method_profiling.rb +84 -0
  90. data/lib/traceview/ruby.rb +36 -0
  91. data/lib/traceview/support.rb +113 -0
  92. data/lib/traceview/thread_local.rb +26 -0
  93. data/lib/traceview/util.rb +250 -0
  94. data/lib/traceview/version.rb +16 -0
  95. data/lib/traceview/xtrace.rb +90 -0
  96. data/test/frameworks/apps/grape_nested.rb +30 -0
  97. data/test/frameworks/apps/grape_simple.rb +24 -0
  98. data/test/frameworks/apps/padrino_simple.rb +45 -0
  99. data/test/frameworks/apps/sinatra_simple.rb +24 -0
  100. data/test/frameworks/grape_test.rb +142 -0
  101. data/test/frameworks/padrino_test.rb +30 -0
  102. data/test/frameworks/sinatra_test.rb +30 -0
  103. data/test/instrumentation/cassandra_test.rb +380 -0
  104. data/test/instrumentation/dalli_test.rb +171 -0
  105. data/test/instrumentation/em_http_request_test.rb +86 -0
  106. data/test/instrumentation/excon_test.rb +207 -0
  107. data/test/instrumentation/faraday_test.rb +235 -0
  108. data/test/instrumentation/http_test.rb +140 -0
  109. data/test/instrumentation/httpclient_test.rb +296 -0
  110. data/test/instrumentation/memcache_test.rb +251 -0
  111. data/test/instrumentation/memcached_test.rb +226 -0
  112. data/test/instrumentation/mongo_test.rb +462 -0
  113. data/test/instrumentation/moped_test.rb +496 -0
  114. data/test/instrumentation/rack_test.rb +116 -0
  115. data/test/instrumentation/redis_hashes_test.rb +265 -0
  116. data/test/instrumentation/redis_keys_test.rb +318 -0
  117. data/test/instrumentation/redis_lists_test.rb +310 -0
  118. data/test/instrumentation/redis_misc_test.rb +160 -0
  119. data/test/instrumentation/redis_sets_test.rb +293 -0
  120. data/test/instrumentation/redis_sortedsets_test.rb +325 -0
  121. data/test/instrumentation/redis_strings_test.rb +333 -0
  122. data/test/instrumentation/resque_test.rb +62 -0
  123. data/test/instrumentation/rest-client_test.rb +294 -0
  124. data/test/instrumentation/sequel_mysql2_test.rb +326 -0
  125. data/test/instrumentation/sequel_mysql_test.rb +326 -0
  126. data/test/instrumentation/sequel_pg_test.rb +330 -0
  127. data/test/instrumentation/typhoeus_test.rb +285 -0
  128. data/test/minitest_helper.rb +187 -0
  129. data/test/profiling/method_test.rb +198 -0
  130. data/test/servers/rackapp_8101.rb +22 -0
  131. data/test/support/backcompat_test.rb +269 -0
  132. data/test/support/config_test.rb +128 -0
  133. data/test/support/dnt_test.rb +73 -0
  134. data/test/support/liboboe_settings_test.rb +104 -0
  135. data/test/support/xtrace_test.rb +35 -0
  136. data/traceview.gemspec +29 -0
  137. metadata +250 -0
@@ -0,0 +1,16 @@
1
+ # Copyright (c) 2013 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ module TraceView
5
+ ##
6
+ # The current version of the gem. Used mainly by
7
+ # traceview.gemspec during gem build process
8
+ module Version
9
+ MAJOR = 3
10
+ MINOR = 0
11
+ PATCH = 0
12
+ BUILD = nil
13
+
14
+ STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
15
+ end
16
+ end
@@ -0,0 +1,90 @@
1
+ # Copyright (c) 2013 AppNeta, Inc.
2
+ # All rights reserved.
3
+
4
+ module TraceView
5
+ ##
6
+ # Methods to act on, manipulate or investigate an X-Trace
7
+ # value
8
+ module XTrace
9
+ class << self
10
+ ##
11
+ # TraceView::XTrace.valid?
12
+ #
13
+ # Perform basic validation on a potential X-Trace ID
14
+ #
15
+ def valid?(xtrace)
16
+ # Shouldn't be nil
17
+ return false unless xtrace
18
+
19
+ # The X-Trace ID shouldn't be an initialized empty ID
20
+ return false if (xtrace =~ /^1b0000000/i) == 0
21
+
22
+ # Valid X-Trace IDs have a length of 58 bytes and start with '1b'
23
+ return false unless xtrace.length == 58 && (xtrace =~ /^1b/i) == 0
24
+
25
+ true
26
+ rescue StandardError => e
27
+ TraceView.logger.debug e.message
28
+ TraceView.logger.debug e.backtrace
29
+ false
30
+ end
31
+
32
+ ##
33
+ # TraceView::XTrace.task_id
34
+ #
35
+ # Extract and return the task_id portion of an X-Trace ID
36
+ #
37
+ def task_id(xtrace)
38
+ return nil unless TraceView::XTrace.valid?(xtrace)
39
+
40
+ xtrace[2..41]
41
+ rescue StandardError => e
42
+ TraceView.logger.debug e.message
43
+ TraceView.logger.debug e.backtrace
44
+ return nil
45
+ end
46
+
47
+ ##
48
+ # TraceView::XTrace.edge_id
49
+ #
50
+ # Extract and return the edge_id portion of an X-Trace ID
51
+ #
52
+ def edge_id(xtrace)
53
+ return nil unless TraceView::XTrace.valid?(xtrace)
54
+
55
+ xtrace[42..57]
56
+ rescue StandardError => e
57
+ TraceView.logger.debug e.message
58
+ TraceView.logger.debug e.backtrace
59
+ return nil
60
+ end
61
+
62
+ ##
63
+ # continue_service_context
64
+ #
65
+ # In the case of service calls such as external HTTP requests, we
66
+ # pass along X-Trace headers so that request context can be maintained
67
+ # across servers and applications.
68
+ #
69
+ # Remote requests can return a X-Trace header in which case we want
70
+ # to pickup on and continue the context in most cases.
71
+ #
72
+ # @start is the context just before the outgoing request
73
+ #
74
+ # @finish is the context returned to us (as an HTTP response header
75
+ # if that be the case)
76
+ #
77
+ def continue_service_context(start, finish)
78
+ if TraceView::XTrace.valid?(finish) && TraceView.tracing?
79
+
80
+ # Assure that we received back a valid X-Trace with the same task_id
81
+ if TraceView::XTrace.task_id(start) == TraceView::XTrace.task_id(finish)
82
+ TraceView::Context.fromString(finish)
83
+ else
84
+ TraceView.logger.debug "Mismatched returned X-Trace ID: #{finish}"
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,30 @@
1
+ require 'grape'
2
+
3
+ class Wrapper < Grape::API
4
+ class GrapeSimple < Grape::API
5
+ rescue_from :all do |e|
6
+ error_response({ message: "rescued from #{e.class.name}" })
7
+ end
8
+
9
+ get '/json_endpoint' do
10
+ present({ :test => true })
11
+ end
12
+
13
+ get "/break" do
14
+ raise Exception.new("This should have http status code 500!")
15
+ end
16
+
17
+ get "/error" do
18
+ error!("This is a error with 'error'!")
19
+ end
20
+
21
+ get "/breakstring" do
22
+ raise "This should have http status code 500!"
23
+ end
24
+ end
25
+ end
26
+
27
+ class GrapeNested < Grape::API
28
+ mount Wrapper::GrapeSimple
29
+ end
30
+
@@ -0,0 +1,24 @@
1
+ require 'grape'
2
+
3
+ class GrapeSimple < Grape::API
4
+ rescue_from :all do |e|
5
+ error_response({ message: "rescued from #{e.class.name}" })
6
+ end
7
+
8
+ get '/json_endpoint' do
9
+ present({ :test => true })
10
+ end
11
+
12
+ get "/break" do
13
+ raise Exception.new("This should have http status code 500!")
14
+ end
15
+
16
+ get "/error" do
17
+ error!("This is a error with 'error'!")
18
+ end
19
+
20
+ get "/breakstring" do
21
+ raise "This should have http status code 500!"
22
+ end
23
+ end
24
+
@@ -0,0 +1,45 @@
1
+ # This test Padrino stack file was taken from the padrino-core gem.
2
+ #
3
+ PADRINO_ROOT = File.dirname(__FILE__) unless defined? PADRINO_ROOT
4
+ # Remove this comment if you want do some like this: ruby PADRINO_ENV=test app.rb
5
+ #
6
+ # require 'rubygems'
7
+ # require 'padrino-core'
8
+ #
9
+
10
+ class SimpleDemo < Padrino::Application
11
+ set :public_folder, File.dirname(__FILE__)
12
+ set :reload, true
13
+ before { true }
14
+ after { true }
15
+ error(404) { "404" }
16
+ end
17
+
18
+ SimpleDemo.controllers do
19
+ get "/" do
20
+ 'The magick number is: 2767356926488785838763860464013972991031534522105386787489885890443740254365!' # Change only the number!!!
21
+ end
22
+
23
+ get "/rand" do
24
+ rand(2 ** 256).to_s
25
+ end
26
+
27
+ get "/render" do
28
+ render :erb, "This is an erb render"
29
+ end
30
+
31
+ get "/break" do
32
+ raise "This is a controller exception!"
33
+ end
34
+ end
35
+
36
+ ## If you want use this as a standalone app uncomment:
37
+ #
38
+ # Padrino.mount("SimpleDemo").to("/")
39
+ # Padrino.run! unless Padrino.loaded? # If you enable reloader prevent to re-run the app
40
+ #
41
+ # Then run it from your console: ruby -I"lib" test/fixtures/apps/simple.rb
42
+ #
43
+
44
+ Padrino.load!
45
+
@@ -0,0 +1,24 @@
1
+ require 'sinatra'
2
+
3
+ class SinatraSimple < Sinatra::Base
4
+ set :reload, true
5
+
6
+ get "/" do
7
+ 'The magick number is: 2767356926488785838763860464013972991031534522105386787489885890443740254365!' # Change only the number!!!
8
+ end
9
+
10
+ get "/rand" do
11
+ rand(2 ** 256).to_s
12
+ end
13
+
14
+ get "/render" do
15
+ render :erb, "This is an erb render"
16
+ end
17
+
18
+ get "/break" do
19
+ raise "This is a controller exception!"
20
+ end
21
+ end
22
+
23
+ use SinatraSimple
24
+
@@ -0,0 +1,142 @@
1
+ if RUBY_VERSION >= '1.9.3'
2
+ require 'minitest_helper'
3
+ require File.expand_path(File.dirname(__FILE__) + '/apps/grape_simple')
4
+ require File.expand_path(File.dirname(__FILE__) + '/apps/grape_nested')
5
+
6
+ describe Grape do
7
+ before do
8
+ clear_all_traces
9
+ end
10
+
11
+ it "should trace a request to a simple grape stack" do
12
+ @app = GrapeSimple
13
+
14
+ r = get "/json_endpoint"
15
+
16
+ r.status.must_equal 200
17
+ r.headers.key?('X-Trace').must_equal true
18
+
19
+ traces = get_all_traces
20
+ traces.count.must_equal 5
21
+
22
+ validate_outer_layers(traces, 'rack')
23
+
24
+ traces[2]['Layer'].must_equal "grape"
25
+ traces[3]['Layer'].must_equal "grape"
26
+ traces[3].has_key?('Controller').must_equal true
27
+ traces[3].has_key?('Action').must_equal true
28
+ traces[4]['Label'].must_equal "exit"
29
+
30
+ # Validate the existence of the response header
31
+ r.headers.key?('X-Trace').must_equal true
32
+ r.headers['X-Trace'].must_equal traces[4]['X-Trace']
33
+ end
34
+
35
+ it "should trace a request to a nested grape stack" do
36
+ @app = GrapeNested
37
+
38
+ r = get "/json_endpoint"
39
+
40
+ r.status.must_equal 200
41
+ r.headers.key?('X-Trace').must_equal true
42
+
43
+ traces = get_all_traces
44
+ traces.count.must_equal 5
45
+
46
+ validate_outer_layers(traces, 'rack')
47
+
48
+ traces[2]['Layer'].must_equal "grape"
49
+ traces[3]['Layer'].must_equal "grape"
50
+ traces[3].has_key?('Controller').must_equal true
51
+ traces[3].has_key?('Action').must_equal true
52
+ traces[4]['Label'].must_equal "exit"
53
+
54
+ # Validate the existence of the response header
55
+ r.headers.key?('X-Trace').must_equal true
56
+ r.headers['X-Trace'].must_equal traces[4]['X-Trace']
57
+ end
58
+
59
+ it "should trace a an error in a nested grape stack" do
60
+ @app = GrapeNested
61
+
62
+ r = get "/error"
63
+
64
+ r.status.must_equal 500
65
+ r.headers.key?('X-Trace').must_equal true
66
+
67
+ traces = get_all_traces
68
+ traces.count.must_equal 6
69
+
70
+ validate_outer_layers(traces, 'rack')
71
+
72
+ traces[2]['Layer'].must_equal "grape"
73
+ traces[2]['Label'].must_equal "entry"
74
+ traces[3]['Layer'].must_equal "grape"
75
+ traces[3]['Label'].must_equal "exit"
76
+ traces[3].has_key?('Controller').must_equal true
77
+ traces[3].has_key?('Action').must_equal true
78
+ traces[4]['Label'].must_equal "error"
79
+ traces[4]['ErrorClass'].must_equal "GrapeError"
80
+ traces[4]['ErrorMsg'].must_equal "This is a error with 'error'!"
81
+ traces[4].has_key?('Backtrace').must_equal true
82
+ traces[5]['Layer'].must_equal "rack"
83
+ traces[5]['Label'].must_equal "exit"
84
+
85
+ # Validate the existence of the response header
86
+ r.headers.key?('X-Trace').must_equal true
87
+ r.headers['X-Trace'].must_equal traces[5]['X-Trace']
88
+ end
89
+
90
+
91
+ it "should trace a request with an exception" do
92
+ @app = GrapeSimple
93
+
94
+ begin
95
+ r = get "/break"
96
+ rescue Exception => e
97
+ # Do not handle/raise this error so
98
+ # we can continue to test
99
+ end
100
+
101
+ traces = get_all_traces
102
+ traces.count.must_equal 6
103
+
104
+ validate_outer_layers(traces, 'rack')
105
+
106
+ traces[2]['Layer'].must_equal "grape"
107
+ traces[3]['Layer'].must_equal "grape"
108
+ traces[3].has_key?('Controller').must_equal true
109
+ traces[3].has_key?('Action').must_equal true
110
+ traces[4]['Label'].must_equal "error"
111
+ traces[4]['ErrorClass'].must_equal "Exception"
112
+ traces[4]['ErrorMsg'].must_equal "This should have http status code 500!"
113
+ traces[5]['Label'].must_equal "exit"
114
+ end
115
+
116
+ it "should trace a request with an error" do
117
+ @app = GrapeSimple
118
+
119
+ r = get "/error"
120
+
121
+ traces = get_all_traces
122
+ traces.count.must_equal 6
123
+
124
+ r.status.must_equal 500
125
+ r.headers.key?('X-Trace').must_equal true
126
+
127
+ validate_outer_layers(traces, 'rack')
128
+
129
+ traces[0]['Layer'].must_equal "rack"
130
+ traces[2]['Layer'].must_equal "grape"
131
+ traces[3]['Layer'].must_equal "grape"
132
+ traces[3].has_key?('Controller').must_equal true
133
+ traces[3].has_key?('Action').must_equal true
134
+ traces[4]['Label'].must_equal "error"
135
+ traces[4]['ErrorClass'].must_equal "GrapeError"
136
+ traces[4]['ErrorMsg'].must_equal "This is a error with 'error'!"
137
+ traces[5]['Layer'].must_equal "rack"
138
+ traces[5]['Label'].must_equal "exit"
139
+ traces[5]['Status'].must_equal 500
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,30 @@
1
+ if RUBY_VERSION >= '1.9.3'
2
+ require "minitest_helper"
3
+ require File.expand_path(File.dirname(__FILE__) + '/apps/padrino_simple')
4
+
5
+ describe Padrino do
6
+ before do
7
+ clear_all_traces
8
+ end
9
+
10
+ it "should trace a request to a simple padrino stack" do
11
+ @app = SimpleDemo
12
+
13
+ r = get "/render"
14
+
15
+ traces = get_all_traces
16
+
17
+ traces.count.must_equal 9
18
+ valid_edges?(traces).must_equal true
19
+ validate_outer_layers(traces, 'rack')
20
+
21
+ traces[2]['Layer'].must_equal "padrino"
22
+ traces[7]['Controller'].must_equal "SimpleDemo"
23
+ traces[8]['Label'].must_equal "exit"
24
+
25
+ # Validate the existence of the response header
26
+ r.headers.key?('X-Trace').must_equal true
27
+ r.headers['X-Trace'].must_equal traces[8]['X-Trace']
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ require "minitest_helper"
2
+ require File.expand_path(File.dirname(__FILE__) + '/apps/sinatra_simple')
3
+
4
+ describe Sinatra do
5
+ before do
6
+ clear_all_traces
7
+ end
8
+
9
+ it "should trace a request to a simple sinatra stack" do
10
+ @app = SinatraSimple
11
+
12
+ r = get "/render"
13
+
14
+ traces = get_all_traces
15
+
16
+ traces.count.must_equal 9
17
+ valid_edges?(traces).must_equal true
18
+ validate_outer_layers(traces, 'rack')
19
+
20
+ traces[2]['Layer'].must_equal "sinatra"
21
+ traces[4]['Label'].must_equal "profile_entry"
22
+ traces[7]['Controller'].must_equal "SinatraSimple"
23
+ traces[8]['Label'].must_equal "exit"
24
+
25
+ # Validate the existence of the response header
26
+ r.headers.key?('X-Trace').must_equal true
27
+ r.headers['X-Trace'].must_equal traces[8]['X-Trace']
28
+ end
29
+ end
30
+
@@ -0,0 +1,380 @@
1
+ require 'minitest_helper'
2
+
3
+ # The cassandra-rb client doesn't support JRuby
4
+ # https://github.com/cassandra-rb/cassandra
5
+ unless defined?(JRUBY_VERSION)
6
+ describe "Cassandra" do
7
+ before do
8
+ clear_all_traces
9
+
10
+ @client = Cassandra.new("system", "127.0.0.1:9160", { :timeout => 10 })
11
+ @client.disable_node_auto_discovery!
12
+
13
+ @ks_name = "AppNetaCassandraTest"
14
+
15
+ ks_def = CassandraThrift::KsDef.new(:name => @ks_name,
16
+ :strategy_class => "SimpleStrategy",
17
+ :strategy_options => { 'replication_factor' => '2' },
18
+ :cf_defs => [])
19
+
20
+ @client.add_keyspace(ks_def) unless @client.keyspaces.include? @ks_name
21
+ @client.keyspace = @ks_name
22
+
23
+ unless @client.column_families.include? "Users"
24
+ cf_def = CassandraThrift::CfDef.new(:keyspace => @ks_name, :name => "Users")
25
+ @client.add_column_family(cf_def)
26
+ end
27
+
28
+ unless @client.column_families.include? "Statuses"
29
+ cf_def = CassandraThrift::CfDef.new(:keyspace => @ks_name, :name => "Statuses")
30
+ @client.add_column_family(cf_def)
31
+ end
32
+
33
+ # These are standard entry/exit KVs that are passed up with all mongo operations
34
+ @entry_kvs = {
35
+ 'Layer' => 'cassandra',
36
+ 'Label' => 'entry',
37
+ 'RemoteHost' => '127.0.0.1',
38
+ 'RemotePort' => '9160' }
39
+
40
+ @exit_kvs = { 'Layer' => 'cassandra', 'Label' => 'exit' }
41
+ @collect_backtraces = TraceView::Config[:cassandra][:collect_backtraces]
42
+ end
43
+
44
+ after do
45
+ TraceView::Config[:cassandra][:collect_backtraces] = @collect_backtraces
46
+ @client.disconnect!
47
+ end
48
+
49
+ it 'Stock Cassandra should be loaded, defined and ready' do
50
+ defined?(::Cassandra).wont_match nil
51
+ end
52
+
53
+ it 'Cassandra should have traceview methods defined' do
54
+ [ :insert, :remove, :count_columns, :get_columns, :multi_get_columns, :get,
55
+ :multi_get, :get_range_single, :get_range_batch, :get_indexed_slices,
56
+ :create_index, :drop_index, :add_column_family, :drop_column_family,
57
+ :add_keyspace, :drop_keyspace ].each do |m|
58
+ ::Cassandra.method_defined?("#{m}_with_traceview").must_equal true
59
+ end
60
+ # Special 'exists?' case
61
+ ::Cassandra.method_defined?("exists_with_traceview?").must_equal true
62
+ end
63
+
64
+ it 'should trace insert' do
65
+ TraceView::API.start_trace('cassandra_test', '', {}) do
66
+ user = {'screen_name' => 'larry', "blah" => "ok"}
67
+ @client.insert(:Users, '5', user, { :ttl => 600, :consistency => 1})
68
+ end
69
+
70
+ traces = get_all_traces
71
+
72
+ traces.count.must_equal 4
73
+ validate_outer_layers(traces, 'cassandra_test')
74
+
75
+ validate_event_keys(traces[1], @entry_kvs)
76
+ traces[1]['Op'].must_equal "insert"
77
+ traces[1]['Cf'].must_equal "Users"
78
+ traces[1]['Key'].must_equal "\"5\""
79
+ traces[1]['Consistency'].must_equal 1
80
+ traces[1]['Ttl'].must_equal 600
81
+ traces[1].has_key?('Backtrace').must_equal TraceView::Config[:cassandra][:collect_backtraces]
82
+ validate_event_keys(traces[2], @exit_kvs)
83
+ end
84
+
85
+ it 'should trace remove' do
86
+ TraceView::API.start_trace('cassandra_test', '', {}) do
87
+ @client.remove(:Users, '5', 'blah')
88
+ end
89
+
90
+ traces = get_all_traces
91
+
92
+ traces.count.must_equal 4
93
+ validate_outer_layers(traces, 'cassandra_test')
94
+
95
+ validate_event_keys(traces[1], @entry_kvs)
96
+ traces[1]['Op'].must_equal "remove"
97
+ traces[1]['Cf'].must_equal "Users"
98
+ traces[1]['Key'].must_equal "\"5\""
99
+ traces[1].has_key?('Backtrace').must_equal TraceView::Config[:cassandra][:collect_backtraces]
100
+ validate_event_keys(traces[2], @exit_kvs)
101
+ end
102
+
103
+ it 'should trace count_columns' do
104
+ @client.insert(:Statuses, '12', {'body' => 'v1', 'user' => 'v2'})
105
+
106
+ TraceView::API.start_trace('cassandra_test', '', {}) do
107
+ @client.count_columns(:Statuses, '12', :count => 50)
108
+ end
109
+
110
+ traces = get_all_traces
111
+
112
+ traces.count.must_equal 4
113
+ validate_outer_layers(traces, 'cassandra_test')
114
+
115
+ validate_event_keys(traces[1], @entry_kvs)
116
+ traces[1]['Op'].must_equal "count_columns"
117
+ traces[1]['Cf'].must_equal "Statuses"
118
+ traces[1]['Key'].must_equal "\"12\""
119
+ traces[1]['Count'].must_equal 50
120
+ traces[1].has_key?('Backtrace').must_equal TraceView::Config[:cassandra][:collect_backtraces]
121
+ validate_event_keys(traces[2], @exit_kvs)
122
+ end
123
+
124
+ it 'should trace get_columns' do
125
+ TraceView::API.start_trace('cassandra_test', '', {}) do
126
+ @client.get_columns(:Statuses, '12', ['body'])
127
+ end
128
+
129
+ traces = get_all_traces
130
+
131
+ traces.count.must_equal 4
132
+ validate_outer_layers(traces, 'cassandra_test')
133
+
134
+ validate_event_keys(traces[1], @entry_kvs)
135
+ traces[1]['Op'].must_equal "get_columns"
136
+ traces[1]['Cf'].must_equal "Statuses"
137
+ traces[1]['Key'].must_equal "\"12\""
138
+ traces[1].has_key?('Backtrace').must_equal TraceView::Config[:cassandra][:collect_backtraces]
139
+ validate_event_keys(traces[2], @exit_kvs)
140
+ end
141
+
142
+ it 'should trace multi_get_columns' do
143
+ TraceView::API.start_trace('cassandra_test', '', {}) do
144
+ @client.multi_get_columns(:Users, ['12', '5'], ['body'])
145
+ end
146
+
147
+ traces = get_all_traces
148
+
149
+ traces.count.must_equal 4
150
+ validate_outer_layers(traces, 'cassandra_test')
151
+
152
+ validate_event_keys(traces[1], @entry_kvs)
153
+ traces[1]['Op'].must_equal "multi_get_columns"
154
+ traces[1]['Cf'].must_equal "Users"
155
+ traces[1]['Key'].must_equal "[\"12\", \"5\"]"
156
+ traces[1].has_key?('Backtrace').must_equal TraceView::Config[:cassandra][:collect_backtraces]
157
+ validate_event_keys(traces[2], @exit_kvs)
158
+ end
159
+
160
+ it 'should trace get' do
161
+ TraceView::API.start_trace('cassandra_test', '', {}) do
162
+ @client.get(:Statuses, '12', :reversed => true)
163
+ end
164
+
165
+ traces = get_all_traces
166
+
167
+ traces.count.must_equal 4
168
+ validate_outer_layers(traces, 'cassandra_test')
169
+
170
+ validate_event_keys(traces[1], @entry_kvs)
171
+ traces[1]['Op'].must_equal "get"
172
+ traces[1]['Cf'].must_equal "Statuses"
173
+ traces[1]['Key'].must_equal "\"12\""
174
+ traces[1]['Reversed'].must_equal "true"
175
+ traces[1].has_key?('Backtrace').must_equal TraceView::Config[:cassandra][:collect_backtraces]
176
+ validate_event_keys(traces[2], @exit_kvs)
177
+ end
178
+
179
+ it 'should trace exists?' do
180
+ TraceView::API.start_trace('cassandra_test', '', {}) do
181
+ @client.exists?(:Statuses, '12')
182
+ @client.exists?(:Statuses, '12', 'body')
183
+ end
184
+
185
+ traces = get_all_traces
186
+
187
+ traces.count.must_equal 6
188
+ validate_outer_layers(traces, 'cassandra_test')
189
+
190
+ validate_event_keys(traces[1], @entry_kvs)
191
+ traces[1]['Op'].must_equal "exists?"
192
+ traces[1]['Cf'].must_equal "Statuses"
193
+ traces[1]['Key'].must_equal "\"12\""
194
+ traces[1].has_key?('Backtrace').must_equal TraceView::Config[:cassandra][:collect_backtraces]
195
+ validate_event_keys(traces[2], @exit_kvs)
196
+
197
+ traces[3]['Op'].must_equal "exists?"
198
+ traces[3]['Cf'].must_equal "Statuses"
199
+ traces[3]['Key'].must_equal "\"12\""
200
+ traces[3].has_key?('Backtrace').must_equal TraceView::Config[:cassandra][:collect_backtraces]
201
+ end
202
+
203
+ it 'should trace get_range_keys' do
204
+ TraceView::API.start_trace('cassandra_test', '', {}) do
205
+ @client.get_range_keys(:Statuses, :key_count => 4)
206
+ end
207
+
208
+ traces = get_all_traces
209
+
210
+ traces.count.must_equal 4
211
+ validate_outer_layers(traces, 'cassandra_test')
212
+
213
+ validate_event_keys(traces[1], @entry_kvs)
214
+ traces[1]['Op'].must_equal "get_range_batch"
215
+ traces[1]['Cf'].must_equal "Statuses"
216
+ traces[1].has_key?('Backtrace').must_equal TraceView::Config[:cassandra][:collect_backtraces]
217
+ validate_event_keys(traces[2], @exit_kvs)
218
+ end
219
+
220
+ it 'should trace create_index' do
221
+ TraceView::API.start_trace('cassandra_test', '', {}) do
222
+ @client.create_index(@ks_name, 'Statuses', 'column_name', 'LongType')
223
+ end
224
+
225
+ traces = get_all_traces
226
+
227
+ traces.count.must_equal 4
228
+ validate_outer_layers(traces, 'cassandra_test')
229
+
230
+ validate_event_keys(traces[1], @entry_kvs)
231
+ traces[1]['Op'].must_equal "create_index"
232
+ traces[1]['Cf'].must_equal "Statuses"
233
+ traces[1]['Keyspace'].must_equal @ks_name
234
+ traces[1]['Column_name'].must_equal "column_name"
235
+ traces[1]['Validation_class'].must_equal "LongType"
236
+ traces[1].has_key?('Backtrace').must_equal TraceView::Config[:cassandra][:collect_backtraces]
237
+ validate_event_keys(traces[2], @exit_kvs)
238
+
239
+ # Clean up
240
+ @client.drop_index(@ks_name, 'Statuses', 'column_name')
241
+ end
242
+
243
+ it 'should trace drop_index' do
244
+ # Prep
245
+ @client.create_index(@ks_name, 'Statuses', 'column_name', 'LongType')
246
+
247
+ TraceView::API.start_trace('cassandra_test', '', {}) do
248
+ @client.drop_index(@ks_name, 'Statuses', 'column_name')
249
+ end
250
+
251
+ traces = get_all_traces
252
+
253
+ traces.count.must_equal 4
254
+ validate_outer_layers(traces, 'cassandra_test')
255
+
256
+ validate_event_keys(traces[1], @entry_kvs)
257
+ traces[1]['Op'].must_equal "drop_index"
258
+ traces[1]['Cf'].must_equal "Statuses"
259
+ traces[1]['Keyspace'].must_equal @ks_name
260
+ traces[1]['Column_name'].must_equal "column_name"
261
+ traces[1].has_key?('Backtrace').must_equal TraceView::Config[:cassandra][:collect_backtraces]
262
+ validate_event_keys(traces[2], @exit_kvs)
263
+ end
264
+
265
+ it 'should trace get_indexed_slices' do
266
+ @client.create_index(@ks_name, 'Statuses', 'x', 'LongType')
267
+ TraceView::API.start_trace('cassandra_test', '', {}) do
268
+ expressions = [
269
+ { :column_name => 'x',
270
+ :value => [0,20].pack("NN"),
271
+ :comparison => "=="},
272
+ { :column_name => 'non_indexed',
273
+ :value => [5].pack("N*"),
274
+ :comparison => ">"} ]
275
+ @client.get_indexed_slices(:Statuses, expressions).length
276
+ end
277
+
278
+ traces = get_all_traces
279
+
280
+ traces.count.must_equal 4
281
+ validate_outer_layers(traces, 'cassandra_test')
282
+
283
+ validate_event_keys(traces[1], @entry_kvs)
284
+ traces[1]['Op'].must_equal "get_indexed_slices"
285
+ traces[1]['Cf'].must_equal "Statuses"
286
+ traces[1].has_key?('Backtrace').must_equal TraceView::Config[:cassandra][:collect_backtraces]
287
+ validate_event_keys(traces[2], @exit_kvs)
288
+ end
289
+
290
+ it 'should trace add and remove of column family' do
291
+ cf_name = (0...10).map{ ('a'..'z').to_a[rand(26)] }.join
292
+ cf_def = CassandraThrift::CfDef.new(:keyspace => @ks_name, :name => cf_name)
293
+
294
+ TraceView::API.start_trace('cassandra_test', '', {}) do
295
+ @client.add_column_family(cf_def)
296
+ @client.drop_column_family(cf_name)
297
+ end
298
+
299
+ traces = get_all_traces
300
+
301
+ traces.count.must_equal 6
302
+ validate_outer_layers(traces, 'cassandra_test')
303
+
304
+ validate_event_keys(traces[1], @entry_kvs)
305
+ traces[1]['Op'].must_equal "add_column_family"
306
+ traces[1].has_key?('Backtrace').must_equal TraceView::Config[:cassandra][:collect_backtraces]
307
+ validate_event_keys(traces[2], @exit_kvs)
308
+
309
+ traces[3]['Op'].must_equal "drop_column_family"
310
+ traces[3]['Cf'].must_equal cf_name
311
+ traces[3].has_key?('Backtrace').must_equal TraceView::Config[:cassandra][:collect_backtraces]
312
+ end
313
+
314
+ it 'should trace adding a keyspace' do
315
+ ks_name = (0...10).map{ ('a'..'z').to_a[rand(26)] }.join
316
+ ks_def = CassandraThrift::KsDef.new(:name => ks_name,
317
+ :strategy_class => "org.apache.cassandra.locator.SimpleStrategy",
318
+ :strategy_options => { 'replication_factor' => '2' },
319
+ :cf_defs => [])
320
+
321
+ TraceView::API.start_trace('cassandra_test', '', {}) do
322
+ @client.add_keyspace(ks_def)
323
+ @client.keyspace = ks_name
324
+ end
325
+
326
+ traces = get_all_traces
327
+
328
+ traces.count.must_equal 4
329
+ validate_outer_layers(traces, 'cassandra_test')
330
+
331
+ validate_event_keys(traces[1], @entry_kvs)
332
+ traces[1]['Op'].must_equal "add_keyspace"
333
+ traces[1]['Name'].must_equal ks_name
334
+ traces[1].has_key?('Backtrace').must_equal TraceView::Config[:cassandra][:collect_backtraces]
335
+ validate_event_keys(traces[2], @exit_kvs)
336
+ end
337
+
338
+ it 'should trace the removal of a keyspace' do
339
+ TraceView::API.start_trace('cassandra_test', '', {}) do
340
+ @client.drop_keyspace(@ks_name)
341
+ end
342
+
343
+ traces = get_all_traces
344
+
345
+ traces.count.must_equal 4
346
+ validate_outer_layers(traces, 'cassandra_test')
347
+
348
+ validate_event_keys(traces[1], @entry_kvs)
349
+ traces[1]['Op'].must_equal "drop_keyspace"
350
+ traces[1]['Name'].must_equal @ks_name
351
+ traces[1].has_key?('Backtrace').must_equal TraceView::Config[:cassandra][:collect_backtraces]
352
+ validate_event_keys(traces[2], @exit_kvs)
353
+ end
354
+
355
+ it "should obey :collect_backtraces setting when true" do
356
+ TraceView::Config[:cassandra][:collect_backtraces] = true
357
+
358
+ TraceView::API.start_trace('cassandra_test', '', {}) do
359
+ user = {'screen_name' => 'larry', "blah" => "ok"}
360
+ @client.insert(:Users, '5', user, { :ttl => 600, :consistency => 1})
361
+ end
362
+
363
+ traces = get_all_traces
364
+ layer_has_key(traces, 'cassandra', 'Backtrace')
365
+ end
366
+
367
+ it "should obey :collect_backtraces setting when false" do
368
+ TraceView::Config[:cassandra][:collect_backtraces] = false
369
+
370
+ TraceView::API.start_trace('cassandra_test', '', {}) do
371
+ user = {'screen_name' => 'larry', "blah" => "ok"}
372
+ @client.insert(:Users, '5', user, { :ttl => 600, :consistency => 1})
373
+ end
374
+
375
+ traces = get_all_traces
376
+ layer_doesnt_have_key(traces, 'cassandra', 'Backtrace')
377
+ end
378
+
379
+ end
380
+ end