appsignal 2.5.0.alpha.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (211) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +33 -0
  3. data/.rspec +4 -0
  4. data/.rubocop.yml +66 -0
  5. data/.rubocop_todo.yml +124 -0
  6. data/.travis.yml +72 -0
  7. data/.yardopts +8 -0
  8. data/CHANGELOG.md +639 -0
  9. data/Gemfile +3 -0
  10. data/LICENSE +20 -0
  11. data/README.md +264 -0
  12. data/Rakefile +214 -0
  13. data/appsignal.gemspec +42 -0
  14. data/benchmark.rake +77 -0
  15. data/bin/appsignal +13 -0
  16. data/ext/Rakefile +27 -0
  17. data/ext/agent.yml +64 -0
  18. data/ext/appsignal_extension.c +692 -0
  19. data/ext/base.rb +79 -0
  20. data/ext/extconf.rb +35 -0
  21. data/gemfiles/capistrano2.gemfile +7 -0
  22. data/gemfiles/capistrano3.gemfile +7 -0
  23. data/gemfiles/grape.gemfile +7 -0
  24. data/gemfiles/no_dependencies.gemfile +5 -0
  25. data/gemfiles/padrino.gemfile +7 -0
  26. data/gemfiles/que.gemfile +5 -0
  27. data/gemfiles/rails-3.2.gemfile +6 -0
  28. data/gemfiles/rails-4.0.gemfile +6 -0
  29. data/gemfiles/rails-4.1.gemfile +6 -0
  30. data/gemfiles/rails-4.2.gemfile +10 -0
  31. data/gemfiles/rails-5.0.gemfile +5 -0
  32. data/gemfiles/rails-5.1.gemfile +5 -0
  33. data/gemfiles/resque.gemfile +12 -0
  34. data/gemfiles/sequel-435.gemfile +11 -0
  35. data/gemfiles/sequel.gemfile +11 -0
  36. data/gemfiles/sinatra.gemfile +6 -0
  37. data/gemfiles/webmachine.gemfile +5 -0
  38. data/lib/appsignal.rb +804 -0
  39. data/lib/appsignal/auth_check.rb +65 -0
  40. data/lib/appsignal/capistrano.rb +10 -0
  41. data/lib/appsignal/cli.rb +108 -0
  42. data/lib/appsignal/cli/demo.rb +63 -0
  43. data/lib/appsignal/cli/diagnose.rb +500 -0
  44. data/lib/appsignal/cli/helpers.rb +72 -0
  45. data/lib/appsignal/cli/install.rb +277 -0
  46. data/lib/appsignal/cli/notify_of_deploy.rb +113 -0
  47. data/lib/appsignal/config.rb +287 -0
  48. data/lib/appsignal/demo.rb +107 -0
  49. data/lib/appsignal/event_formatter.rb +74 -0
  50. data/lib/appsignal/event_formatter/action_view/render_formatter.rb +24 -0
  51. data/lib/appsignal/event_formatter/active_record/instantiation_formatter.rb +14 -0
  52. data/lib/appsignal/event_formatter/active_record/sql_formatter.rb +14 -0
  53. data/lib/appsignal/event_formatter/elastic_search/search_formatter.rb +32 -0
  54. data/lib/appsignal/event_formatter/faraday/request_formatter.rb +19 -0
  55. data/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter.rb +89 -0
  56. data/lib/appsignal/event_formatter/moped/query_formatter.rb +80 -0
  57. data/lib/appsignal/extension.rb +63 -0
  58. data/lib/appsignal/extension/jruby.rb +460 -0
  59. data/lib/appsignal/garbage_collection_profiler.rb +48 -0
  60. data/lib/appsignal/hooks.rb +105 -0
  61. data/lib/appsignal/hooks/action_cable.rb +113 -0
  62. data/lib/appsignal/hooks/active_support_notifications.rb +52 -0
  63. data/lib/appsignal/hooks/celluloid.rb +30 -0
  64. data/lib/appsignal/hooks/data_mapper.rb +18 -0
  65. data/lib/appsignal/hooks/delayed_job.rb +19 -0
  66. data/lib/appsignal/hooks/mongo_ruby_driver.rb +21 -0
  67. data/lib/appsignal/hooks/net_http.rb +29 -0
  68. data/lib/appsignal/hooks/passenger.rb +22 -0
  69. data/lib/appsignal/hooks/puma.rb +35 -0
  70. data/lib/appsignal/hooks/que.rb +21 -0
  71. data/lib/appsignal/hooks/rake.rb +39 -0
  72. data/lib/appsignal/hooks/redis.rb +30 -0
  73. data/lib/appsignal/hooks/sequel.rb +60 -0
  74. data/lib/appsignal/hooks/shoryuken.rb +43 -0
  75. data/lib/appsignal/hooks/sidekiq.rb +144 -0
  76. data/lib/appsignal/hooks/unicorn.rb +40 -0
  77. data/lib/appsignal/hooks/webmachine.rb +23 -0
  78. data/lib/appsignal/integrations/capistrano/appsignal.cap +39 -0
  79. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +52 -0
  80. data/lib/appsignal/integrations/data_mapper.rb +33 -0
  81. data/lib/appsignal/integrations/delayed_job_plugin.rb +54 -0
  82. data/lib/appsignal/integrations/grape.rb +53 -0
  83. data/lib/appsignal/integrations/mongo_ruby_driver.rb +55 -0
  84. data/lib/appsignal/integrations/object.rb +35 -0
  85. data/lib/appsignal/integrations/padrino.rb +84 -0
  86. data/lib/appsignal/integrations/que.rb +43 -0
  87. data/lib/appsignal/integrations/railtie.rb +41 -0
  88. data/lib/appsignal/integrations/rake.rb +2 -0
  89. data/lib/appsignal/integrations/resque.rb +20 -0
  90. data/lib/appsignal/integrations/resque_active_job.rb +30 -0
  91. data/lib/appsignal/integrations/sinatra.rb +17 -0
  92. data/lib/appsignal/integrations/webmachine.rb +38 -0
  93. data/lib/appsignal/js_exception_transaction.rb +54 -0
  94. data/lib/appsignal/marker.rb +63 -0
  95. data/lib/appsignal/minutely.rb +42 -0
  96. data/lib/appsignal/rack/generic_instrumentation.rb +49 -0
  97. data/lib/appsignal/rack/js_exception_catcher.rb +70 -0
  98. data/lib/appsignal/rack/rails_instrumentation.rb +51 -0
  99. data/lib/appsignal/rack/sinatra_instrumentation.rb +99 -0
  100. data/lib/appsignal/rack/streaming_listener.rb +73 -0
  101. data/lib/appsignal/system.rb +81 -0
  102. data/lib/appsignal/transaction.rb +498 -0
  103. data/lib/appsignal/transmitter.rb +107 -0
  104. data/lib/appsignal/utils.rb +127 -0
  105. data/lib/appsignal/utils/params_sanitizer.rb +59 -0
  106. data/lib/appsignal/utils/query_params_sanitizer.rb +55 -0
  107. data/lib/appsignal/version.rb +3 -0
  108. data/lib/sequel/extensions/appsignal_integration.rb +3 -0
  109. data/resources/appsignal.yml.erb +39 -0
  110. data/resources/cacert.pem +3866 -0
  111. data/spec/.rubocop.yml +7 -0
  112. data/spec/lib/appsignal/auth_check_spec.rb +80 -0
  113. data/spec/lib/appsignal/capistrano2_spec.rb +224 -0
  114. data/spec/lib/appsignal/capistrano3_spec.rb +237 -0
  115. data/spec/lib/appsignal/cli/demo_spec.rb +67 -0
  116. data/spec/lib/appsignal/cli/diagnose_spec.rb +988 -0
  117. data/spec/lib/appsignal/cli/helpers_spec.rb +171 -0
  118. data/spec/lib/appsignal/cli/install_spec.rb +632 -0
  119. data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +168 -0
  120. data/spec/lib/appsignal/cli_spec.rb +56 -0
  121. data/spec/lib/appsignal/config_spec.rb +637 -0
  122. data/spec/lib/appsignal/demo_spec.rb +87 -0
  123. data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +44 -0
  124. data/spec/lib/appsignal/event_formatter/active_record/instantiation_formatter_spec.rb +21 -0
  125. data/spec/lib/appsignal/event_formatter/active_record/sql_formatter_spec.rb +21 -0
  126. data/spec/lib/appsignal/event_formatter/elastic_search/search_formatter_spec.rb +52 -0
  127. data/spec/lib/appsignal/event_formatter/faraday/request_formatter_spec.rb +21 -0
  128. data/spec/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter_spec.rb +113 -0
  129. data/spec/lib/appsignal/event_formatter/moped/query_formatter_spec.rb +112 -0
  130. data/spec/lib/appsignal/event_formatter_spec.rb +100 -0
  131. data/spec/lib/appsignal/extension/jruby_spec.rb +43 -0
  132. data/spec/lib/appsignal/extension_spec.rb +137 -0
  133. data/spec/lib/appsignal/garbage_collection_profiler_spec.rb +66 -0
  134. data/spec/lib/appsignal/hooks/action_cable_spec.rb +370 -0
  135. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +92 -0
  136. data/spec/lib/appsignal/hooks/celluloid_spec.rb +35 -0
  137. data/spec/lib/appsignal/hooks/data_mapper_spec.rb +39 -0
  138. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +358 -0
  139. data/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb +44 -0
  140. data/spec/lib/appsignal/hooks/net_http_spec.rb +53 -0
  141. data/spec/lib/appsignal/hooks/passenger_spec.rb +30 -0
  142. data/spec/lib/appsignal/hooks/puma_spec.rb +80 -0
  143. data/spec/lib/appsignal/hooks/que_spec.rb +19 -0
  144. data/spec/lib/appsignal/hooks/rake_spec.rb +73 -0
  145. data/spec/lib/appsignal/hooks/redis_spec.rb +55 -0
  146. data/spec/lib/appsignal/hooks/sequel_spec.rb +46 -0
  147. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +192 -0
  148. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +419 -0
  149. data/spec/lib/appsignal/hooks/unicorn_spec.rb +52 -0
  150. data/spec/lib/appsignal/hooks/webmachine_spec.rb +35 -0
  151. data/spec/lib/appsignal/hooks_spec.rb +195 -0
  152. data/spec/lib/appsignal/integrations/data_mapper_spec.rb +65 -0
  153. data/spec/lib/appsignal/integrations/grape_spec.rb +225 -0
  154. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +127 -0
  155. data/spec/lib/appsignal/integrations/object_spec.rb +249 -0
  156. data/spec/lib/appsignal/integrations/padrino_spec.rb +323 -0
  157. data/spec/lib/appsignal/integrations/que_spec.rb +174 -0
  158. data/spec/lib/appsignal/integrations/railtie_spec.rb +129 -0
  159. data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +83 -0
  160. data/spec/lib/appsignal/integrations/resque_spec.rb +92 -0
  161. data/spec/lib/appsignal/integrations/sinatra_spec.rb +73 -0
  162. data/spec/lib/appsignal/integrations/webmachine_spec.rb +69 -0
  163. data/spec/lib/appsignal/js_exception_transaction_spec.rb +128 -0
  164. data/spec/lib/appsignal/marker_spec.rb +51 -0
  165. data/spec/lib/appsignal/minutely_spec.rb +50 -0
  166. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +90 -0
  167. data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +147 -0
  168. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +117 -0
  169. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +213 -0
  170. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +161 -0
  171. data/spec/lib/appsignal/system_spec.rb +131 -0
  172. data/spec/lib/appsignal/transaction_spec.rb +1146 -0
  173. data/spec/lib/appsignal/transmitter_spec.rb +152 -0
  174. data/spec/lib/appsignal/utils/params_sanitizer_spec.rb +136 -0
  175. data/spec/lib/appsignal/utils/query_params_sanitizer_spec.rb +192 -0
  176. data/spec/lib/appsignal/utils_spec.rb +150 -0
  177. data/spec/lib/appsignal_spec.rb +1049 -0
  178. data/spec/spec_helper.rb +116 -0
  179. data/spec/support/fixtures/containers/cgroups/docker +14 -0
  180. data/spec/support/fixtures/containers/cgroups/docker_systemd +8 -0
  181. data/spec/support/fixtures/containers/cgroups/lxc +10 -0
  182. data/spec/support/fixtures/containers/cgroups/no_permission +0 -0
  183. data/spec/support/fixtures/containers/cgroups/none +1 -0
  184. data/spec/support/fixtures/generated_config.yml +24 -0
  185. data/spec/support/fixtures/uploaded_file.txt +0 -0
  186. data/spec/support/helpers/api_request_helper.rb +19 -0
  187. data/spec/support/helpers/cli_helpers.rb +26 -0
  188. data/spec/support/helpers/config_helpers.rb +21 -0
  189. data/spec/support/helpers/dependency_helper.rb +73 -0
  190. data/spec/support/helpers/directory_helper.rb +27 -0
  191. data/spec/support/helpers/env_helpers.rb +33 -0
  192. data/spec/support/helpers/example_exception.rb +13 -0
  193. data/spec/support/helpers/example_standard_error.rb +13 -0
  194. data/spec/support/helpers/log_helpers.rb +22 -0
  195. data/spec/support/helpers/std_streams_helper.rb +66 -0
  196. data/spec/support/helpers/system_helpers.rb +8 -0
  197. data/spec/support/helpers/time_helpers.rb +11 -0
  198. data/spec/support/helpers/transaction_helpers.rb +37 -0
  199. data/spec/support/matchers/contains_log.rb +7 -0
  200. data/spec/support/mocks/fake_gc_profiler.rb +19 -0
  201. data/spec/support/mocks/mock_extension.rb +6 -0
  202. data/spec/support/project_fixture/config/application.rb +0 -0
  203. data/spec/support/project_fixture/config/appsignal.yml +32 -0
  204. data/spec/support/project_fixture/config/environments/development.rb +0 -0
  205. data/spec/support/project_fixture/config/environments/production.rb +0 -0
  206. data/spec/support/project_fixture/config/environments/test.rb +0 -0
  207. data/spec/support/project_fixture/log/.gitkeep +0 -0
  208. data/spec/support/rails/my_app.rb +6 -0
  209. data/spec/support/shared_examples/instrument.rb +43 -0
  210. data/spec/support/stubs/delayed_job.rb +0 -0
  211. metadata +483 -0
@@ -0,0 +1,24 @@
1
+ module Appsignal
2
+ class EventFormatter
3
+ # @api private
4
+ module ActionView
5
+ class RenderFormatter < Appsignal::EventFormatter
6
+ register "render_partial.action_view"
7
+ register "render_template.action_view"
8
+
9
+ BLANK = "".freeze
10
+
11
+ attr_reader :root_path
12
+
13
+ def initialize
14
+ @root_path = "#{Rails.root}/".freeze
15
+ end
16
+
17
+ def format(payload)
18
+ return nil unless payload[:identifier]
19
+ [payload[:identifier].sub(root_path, BLANK), nil]
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,14 @@
1
+ module Appsignal
2
+ class EventFormatter
3
+ # @api private
4
+ module ActiveRecord
5
+ class InstantiationFormatter < Appsignal::EventFormatter
6
+ register "instantiation.active_record"
7
+
8
+ def format(payload)
9
+ [payload[:class_name], nil]
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Appsignal
2
+ class EventFormatter
3
+ # @api private
4
+ module ActiveRecord
5
+ class SqlFormatter < Appsignal::EventFormatter
6
+ register "sql.active_record"
7
+
8
+ def format(payload)
9
+ [payload[:name], payload[:sql], SQL_BODY_FORMAT]
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,32 @@
1
+ module Appsignal
2
+ class EventFormatter
3
+ # @api private
4
+ module ElasticSearch
5
+ class SearchFormatter < Appsignal::EventFormatter
6
+ register "search.elasticsearch"
7
+
8
+ def format(payload)
9
+ [
10
+ "#{payload[:name]}: #{payload[:klass]}",
11
+ sanitized_search(payload[:search]).inspect
12
+ ]
13
+ end
14
+
15
+ def sanitized_search(search)
16
+ return unless search.is_a?(Hash)
17
+
18
+ {}.tap do |hsh|
19
+ search.each do |key, val|
20
+ hsh[key] =
21
+ if [:index, :type].include?(key)
22
+ val
23
+ else
24
+ Appsignal::Utils::QueryParamsSanitizer.sanitize(val)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,19 @@
1
+ module Appsignal
2
+ class EventFormatter
3
+ # @api private
4
+ module Faraday
5
+ class RequestFormatter < Appsignal::EventFormatter
6
+ register "request.faraday"
7
+
8
+ def format(payload)
9
+ http_method = payload[:method].to_s.upcase
10
+ uri = payload[:url]
11
+ [
12
+ "#{http_method} #{uri.scheme}://#{uri.host}",
13
+ "#{http_method} #{uri.scheme}://#{uri.host}#{uri.path}"
14
+ ]
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,89 @@
1
+ module Appsignal
2
+ class EventFormatter
3
+ # @api private
4
+ module MongoRubyDriver
5
+ class QueryFormatter
6
+ ALLOWED = {
7
+ "find" => {
8
+ "find" => :allow,
9
+ "filter" => :sanitize_document
10
+ },
11
+ "count" => {
12
+ "count" => :allow,
13
+ "query" => :sanitize_document
14
+ },
15
+ "distinct" => {
16
+ "distinct" => :allow,
17
+ "key" => :allow,
18
+ "query" => :sanitize_document
19
+ },
20
+ "insert" => {
21
+ "insert" => :allow,
22
+ "documents" => :deny_array,
23
+ "ordered" => :allow
24
+ },
25
+ "update" => {
26
+ "update" => :allow,
27
+ "updates" => :sanitize_bulk,
28
+ "ordered" => :allow
29
+ },
30
+ "findandmodify" => {
31
+ "findandmodify" => :allow,
32
+ "query" => :sanitize_document,
33
+ "update" => :deny_array,
34
+ "new" => :allow
35
+ },
36
+ "delete" => {
37
+ "delete" => :allow,
38
+ "deletes" => :sanitize_bulk,
39
+ "ordered" => :allow
40
+ },
41
+ "bulk" => {
42
+ "q" => :sanitize_document,
43
+ "u" => :deny_array,
44
+ "limit" => :allow,
45
+ "multi" => :allow,
46
+ "upsert" => :allow
47
+ }
48
+ }.freeze
49
+
50
+ # Format command based on given strategy
51
+ def self.format(strategy, command)
52
+ # Stop processing if command is not a hash
53
+ return {} unless command.is_a?(Hash)
54
+
55
+ # Get the strategy and stop if it's not present
56
+ strategies = ALLOWED[strategy.to_s]
57
+ return {} unless strategies
58
+
59
+ {}.tap do |hsh|
60
+ command.each do |key, val|
61
+ hsh[key] = apply_strategy(strategies[key], val)
62
+ end
63
+ end
64
+ end
65
+
66
+ # Applies strategy on hash values based on keys
67
+ def self.apply_strategy(strategy, val)
68
+ case strategy
69
+ when :allow then val
70
+ when :deny then "?"
71
+ when :deny_array then "[?]"
72
+ when :sanitize_document
73
+ Appsignal::Utils::QueryParamsSanitizer.sanitize(val, true, :mongodb)
74
+ when :sanitize_bulk
75
+ if val.length > 1
76
+ [
77
+ format(:bulk, val.first),
78
+ "[...]"
79
+ ]
80
+ else
81
+ val.map { |v| format(:bulk, v) }
82
+ end
83
+ else "?"
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,80 @@
1
+ module Appsignal
2
+ class EventFormatter
3
+ # @api private
4
+ module Moped
5
+ class QueryFormatter < Appsignal::EventFormatter
6
+ register "query.moped"
7
+
8
+ def format(payload)
9
+ if payload[:ops] && !payload[:ops].empty?
10
+ op = payload[:ops].first
11
+ case op.class.to_s
12
+ when "Moped::Protocol::Command"
13
+ [
14
+ "Command", {
15
+ :database => op.full_collection_name,
16
+ :selector => sanitize(op.selector, true, :mongodb)
17
+ }.inspect
18
+ ]
19
+ when "Moped::Protocol::Query"
20
+ [
21
+ "Query", {
22
+ :database => op.full_collection_name,
23
+ :selector => sanitize(op.selector, false, :mongodb),
24
+ :flags => op.flags,
25
+ :limit => op.limit,
26
+ :skip => op.skip,
27
+ :fields => op.fields
28
+ }.inspect
29
+ ]
30
+ when "Moped::Protocol::Delete"
31
+ [
32
+ "Delete", {
33
+ :database => op.full_collection_name,
34
+ :selector => sanitize(op.selector, false, :mongodb),
35
+ :flags => op.flags
36
+ }.inspect
37
+ ]
38
+ when "Moped::Protocol::Insert"
39
+ [
40
+ "Insert", {
41
+ :database => op.full_collection_name,
42
+ :documents => sanitize(op.documents, true, :mongodb),
43
+ :count => op.documents.count,
44
+ :flags => op.flags
45
+ }.inspect
46
+ ]
47
+ when "Moped::Protocol::Update"
48
+ [
49
+ "Update",
50
+ {
51
+ :database => op.full_collection_name,
52
+ :selector => sanitize(op.selector, false, :mongodb),
53
+ :update => sanitize(op.update, true, :mongodb),
54
+ :flags => op.flags
55
+ }.inspect
56
+ ]
57
+ when "Moped::Protocol::KillCursors"
58
+ [
59
+ "KillCursors",
60
+ { :number_of_cursor_ids => op.number_of_cursor_ids }.inspect
61
+ ]
62
+ else
63
+ [
64
+ op.class.to_s.sub("Moped::Protocol::", ""),
65
+ { :database => op.full_collection_name }.inspect
66
+ ]
67
+ end
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ def sanitize(params, only_top_level, key_sanitizer)
74
+ Appsignal::Utils::QueryParamsSanitizer.sanitize \
75
+ params, only_top_level, key_sanitizer
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,63 @@
1
+ require "yaml"
2
+
3
+ begin
4
+ if Appsignal::System.jruby?
5
+ require "appsignal/extension/jruby"
6
+ # {Appsignal.extension_loaded} is set in the jRuby extension file
7
+ else
8
+ require "appsignal_extension"
9
+ Appsignal.extension_loaded = true
10
+ end
11
+ rescue LoadError => err
12
+ Appsignal.logger.error(
13
+ "Failed to load extension (#{err}), please check the install.log file in " \
14
+ "the ext directory of the gem and email us at support@appsignal.com"
15
+ )
16
+ Appsignal.extension_loaded = false
17
+ end
18
+
19
+ module Appsignal
20
+ # @api private
21
+ class Extension
22
+ class << self
23
+ def agent_config
24
+ @agent_config ||= YAML.load(
25
+ File.read(File.join(File.dirname(__FILE__), "../../ext/agent.yml"))
26
+ )
27
+ end
28
+
29
+ def agent_version
30
+ agent_config["version"]
31
+ end
32
+
33
+ # Do nothing if the extension methods are not loaded
34
+ #
35
+ # Disabled in testing so we can make sure that we don't miss a extension
36
+ # function implementation.
37
+ def method_missing(m, *args, &block)
38
+ super if Appsignal.testing?
39
+ end
40
+ end
41
+
42
+ if Appsignal::System.jruby?
43
+ extend Appsignal::Extension::Jruby
44
+
45
+ # Reassign Transaction class for jRuby extension usage.
46
+ #
47
+ # Makes sure the generated docs aren't always overwritten with the jRuby
48
+ # version.
49
+ Transaction = Jruby::Transaction
50
+ # Reassign Data class for jRuby extension usage.
51
+ #
52
+ # Makes sure the generated docs aren't always overwritten with the jRuby
53
+ # version.
54
+ Data = Jruby::Data
55
+ end
56
+
57
+ class Data
58
+ def inspect
59
+ "#<#{self.class.name}:#{object_id} #{self}>"
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,460 @@
1
+ require "ffi"
2
+
3
+ module Appsignal
4
+ class Extension
5
+ # jRuby extension wrapper
6
+ #
7
+ # Only loaded if the system is detected as jRuby.
8
+ #
9
+ # @api private
10
+ module Jruby # rubocop:disable Metrics/ModuleLength
11
+ extend FFI::Library
12
+
13
+ # jRuby extension String helpers.
14
+ #
15
+ # Based on the make_appsignal_string and make_ruby_string helpers from the
16
+ # AppSignal C-extension in `ext/appsignal_extension.c`.
17
+ module StringHelpers
18
+ class AppsignalString < FFI::Struct
19
+ layout :len, :size_t,
20
+ :buf, :pointer
21
+ end
22
+
23
+ def make_appsignal_string(ruby_string)
24
+ unless ruby_string.is_a?(String)
25
+ raise ArgumentError, "argument is not a string"
26
+ end
27
+
28
+ AppsignalString.new.tap do |appsignal_string|
29
+ appsignal_string[:len] = ruby_string.bytesize
30
+ appsignal_string[:buf] = FFI::MemoryPointer.from_string(ruby_string)
31
+ end
32
+ end
33
+
34
+ def make_ruby_string(appsignal_string)
35
+ appsignal_string[:buf].read_string(appsignal_string[:len]).tap do |ruby_string|
36
+ ruby_string.force_encoding(Encoding::UTF_8)
37
+ end
38
+ end
39
+ end
40
+ include StringHelpers
41
+
42
+ def self.lib_extension
43
+ if Appsignal::System.agent_platform.include?("darwin")
44
+ "dylib"
45
+ else
46
+ "so"
47
+ end
48
+ end
49
+
50
+ begin
51
+ ffi_lib File.join(File.dirname(__FILE__), "../../../ext/libappsignal.#{lib_extension}")
52
+ typedef AppsignalString.by_value, :appsignal_string
53
+
54
+ attach_function :appsignal_start, [], :void
55
+ attach_function :appsignal_stop, [], :void
56
+ attach_function :appsignal_diagnose, [], :appsignal_string
57
+ attach_function :appsignal_get_server_state,
58
+ [:appsignal_string],
59
+ :appsignal_string
60
+ attach_function :appsignal_running_in_container, [], :bool
61
+
62
+ # Metrics methods
63
+ attach_function :appsignal_set_gauge,
64
+ [:appsignal_string, :double],
65
+ :void
66
+ attach_function :appsignal_set_host_gauge,
67
+ [:appsignal_string, :double],
68
+ :void
69
+ attach_function :appsignal_set_process_gauge,
70
+ [:appsignal_string, :double],
71
+ :void
72
+ attach_function :appsignal_increment_counter,
73
+ [:appsignal_string, :int64],
74
+ :void
75
+ attach_function :appsignal_add_distribution_value,
76
+ [:appsignal_string, :double],
77
+ :void
78
+
79
+ # Transaction methods
80
+ attach_function :appsignal_free_transaction,
81
+ [],
82
+ :void
83
+ attach_function :appsignal_start_transaction,
84
+ [:appsignal_string, :appsignal_string, :long],
85
+ :pointer
86
+ attach_function :appsignal_start_event,
87
+ [:pointer, :long],
88
+ :void
89
+ attach_function :appsignal_finish_event,
90
+ [:pointer, :appsignal_string, :appsignal_string, :appsignal_string, :int64, :long],
91
+ :void
92
+ attach_function :appsignal_finish_event_data,
93
+ [:pointer, :appsignal_string, :appsignal_string, :pointer, :int64, :long],
94
+ :void
95
+ attach_function :appsignal_record_event,
96
+ [:pointer, :appsignal_string, :appsignal_string, :appsignal_string, :int64, :long, :long],
97
+ :void
98
+ attach_function :appsignal_record_event_data,
99
+ [:pointer, :appsignal_string, :appsignal_string, :pointer, :int64, :long, :long],
100
+ :void
101
+ attach_function :appsignal_set_transaction_error,
102
+ [:pointer, :appsignal_string, :appsignal_string, :pointer],
103
+ :void
104
+ attach_function :appsignal_set_transaction_action,
105
+ [:pointer, :appsignal_string],
106
+ :void
107
+ attach_function :appsignal_set_transaction_namespace,
108
+ [:pointer, :appsignal_string],
109
+ :void
110
+ attach_function :appsignal_set_transaction_sample_data,
111
+ [:pointer, :appsignal_string, :pointer],
112
+ :void
113
+ attach_function :appsignal_set_transaction_queue_start,
114
+ [:pointer, :long],
115
+ :void
116
+ attach_function :appsignal_set_transaction_metadata,
117
+ [:pointer, :appsignal_string, :appsignal_string],
118
+ :void
119
+ attach_function :appsignal_finish_transaction,
120
+ [:pointer, :long],
121
+ :void
122
+ attach_function :appsignal_complete_transaction,
123
+ [:pointer],
124
+ :void
125
+ attach_function :appsignal_transaction_to_json,
126
+ [:pointer],
127
+ :appsignal_string
128
+
129
+ # Data struct methods
130
+ attach_function :appsignal_free_data, [], :void
131
+ attach_function :appsignal_data_map_new, [], :pointer
132
+ attach_function :appsignal_data_array_new, [], :pointer
133
+ attach_function :appsignal_data_map_set_string,
134
+ [:pointer, :appsignal_string, :appsignal_string],
135
+ :void
136
+ attach_function :appsignal_data_map_set_integer,
137
+ [:pointer, :appsignal_string, :int64],
138
+ :void
139
+ attach_function :appsignal_data_map_set_float,
140
+ [:pointer, :appsignal_string, :double],
141
+ :void
142
+ attach_function :appsignal_data_map_set_boolean,
143
+ [:pointer, :appsignal_string, :bool],
144
+ :void
145
+ attach_function :appsignal_data_map_set_null,
146
+ [:pointer, :appsignal_string],
147
+ :void
148
+ attach_function :appsignal_data_map_set_data,
149
+ [:pointer, :appsignal_string, :pointer],
150
+ :void
151
+ attach_function :appsignal_data_array_append_string,
152
+ [:pointer, :appsignal_string],
153
+ :void
154
+ attach_function :appsignal_data_array_append_integer,
155
+ [:pointer, :int64],
156
+ :void
157
+ attach_function :appsignal_data_array_append_float,
158
+ [:pointer, :double],
159
+ :void
160
+ attach_function :appsignal_data_array_append_boolean,
161
+ [:pointer, :bool],
162
+ :void
163
+ attach_function :appsignal_data_array_append_null,
164
+ [:pointer],
165
+ :void
166
+ attach_function :appsignal_data_array_append_data,
167
+ [:pointer, :pointer],
168
+ :void
169
+ attach_function :appsignal_data_equal,
170
+ [:pointer, :pointer],
171
+ :bool
172
+ attach_function :appsignal_data_to_json,
173
+ [:pointer],
174
+ :appsignal_string
175
+
176
+ Appsignal.extension_loaded = true
177
+ rescue LoadError => err
178
+ Appsignal.logger.error(
179
+ "Failed to load extension (#{err}), please email us at " \
180
+ "support@appsignal.com"
181
+ )
182
+ Appsignal.extension_loaded = false
183
+ end
184
+
185
+ def start
186
+ appsignal_start
187
+ end
188
+
189
+ def stop
190
+ appsignal_stop
191
+ end
192
+
193
+ def diagnose
194
+ make_ruby_string(appsignal_diagnose)
195
+ end
196
+
197
+ def get_server_state(key)
198
+ state = appsignal_get_server_state(make_appsignal_string(key))
199
+ make_ruby_string state if state[:len] > 0
200
+ end
201
+
202
+ def start_transaction(transaction_id, namespace, gc_duration_ms)
203
+ transaction = appsignal_start_transaction(
204
+ make_appsignal_string(transaction_id),
205
+ make_appsignal_string(namespace),
206
+ gc_duration_ms
207
+ )
208
+
209
+ return if !transaction || transaction.null?
210
+ Transaction.new(transaction)
211
+ end
212
+
213
+ def data_map_new
214
+ Data.new(appsignal_data_map_new)
215
+ end
216
+
217
+ def data_array_new
218
+ Data.new(appsignal_data_array_new)
219
+ end
220
+
221
+ def running_in_container?
222
+ appsignal_running_in_container
223
+ end
224
+
225
+ def set_gauge(key, value)
226
+ appsignal_set_gauge(make_appsignal_string(key), value)
227
+ end
228
+
229
+ def set_host_gauge(key, value)
230
+ appsignal_set_host_gauge(make_appsignal_string(key), value)
231
+ end
232
+
233
+ def set_process_gauge(key, value)
234
+ appsignal_set_process_gauge(make_appsignal_string(key), value)
235
+ end
236
+
237
+ def increment_counter(key, value)
238
+ appsignal_increment_counter(make_appsignal_string(key), value)
239
+ end
240
+
241
+ def add_distribution_value(key, value)
242
+ appsignal_add_distribution_value(make_appsignal_string(key), value)
243
+ end
244
+
245
+ class Transaction # rubocop:disable Metrics/ClassLength
246
+ include StringHelpers
247
+
248
+ attr_reader :pointer
249
+
250
+ def initialize(pointer)
251
+ @pointer = FFI::AutoPointer.new(
252
+ pointer,
253
+ Extension.method(:appsignal_free_transaction)
254
+ )
255
+ end
256
+
257
+ def start_event(gc_duration_ms)
258
+ Extension.appsignal_start_event(pointer, gc_duration_ms)
259
+ end
260
+
261
+ def finish_event(name, title, body, body_format, gc_duration_ms)
262
+ case body
263
+ when String
264
+ method = :appsignal_finish_event
265
+ body_arg = make_appsignal_string(body)
266
+ when Data
267
+ method = :appsignal_finish_event_data
268
+ body_arg = body.pointer
269
+ else
270
+ raise ArgumentError,
271
+ "body argument should be a String or Appsignal::Extension::Data"
272
+ end
273
+ Extension.public_send(
274
+ method,
275
+ pointer,
276
+ make_appsignal_string(name),
277
+ make_appsignal_string(title),
278
+ body_arg,
279
+ body_format,
280
+ gc_duration_ms
281
+ )
282
+ end
283
+
284
+ def record_event(name, title, body, body_format, duration, gc_duration_ms) # rubocop:disable Metrics/ParameterLists
285
+ case body
286
+ when String
287
+ method = :appsignal_record_event
288
+ body_arg = make_appsignal_string(body)
289
+ when Data
290
+ method = :appsignal_record_event_data
291
+ body_arg = body.pointer
292
+ else
293
+ raise ArgumentError,
294
+ "body argument should be a String or Appsignal::Extension::Data"
295
+ end
296
+ Extension.public_send(
297
+ method,
298
+ pointer,
299
+ make_appsignal_string(name),
300
+ make_appsignal_string(title),
301
+ body_arg,
302
+ body_format,
303
+ duration,
304
+ gc_duration_ms
305
+ )
306
+ end
307
+
308
+ def set_error(name, message, backtrace)
309
+ Extension.appsignal_set_transaction_error(
310
+ pointer,
311
+ make_appsignal_string(name),
312
+ make_appsignal_string(message),
313
+ backtrace.pointer
314
+ )
315
+ end
316
+
317
+ def set_action(action_name) # rubocop:disable Style/AccessorMethodName
318
+ Extension.appsignal_set_transaction_action(
319
+ pointer,
320
+ make_appsignal_string(action_name)
321
+ )
322
+ end
323
+
324
+ def set_namespace(namespace) # rubocop:disable Style/AccessorMethodName
325
+ Extension.appsignal_set_transaction_namespace(
326
+ pointer,
327
+ make_appsignal_string(namespace)
328
+ )
329
+ end
330
+
331
+ def set_sample_data(key, payload)
332
+ Extension.appsignal_set_transaction_sample_data(
333
+ pointer,
334
+ make_appsignal_string(key),
335
+ payload.pointer
336
+ )
337
+ end
338
+
339
+ def set_queue_start(time) # rubocop:disable Style/AccessorMethodName
340
+ Extension.appsignal_set_transaction_queue_start(pointer, time)
341
+ end
342
+
343
+ def set_metadata(key, value)
344
+ Extension.appsignal_set_transaction_metadata(
345
+ pointer,
346
+ make_appsignal_string(key),
347
+ make_appsignal_string(value)
348
+ )
349
+ end
350
+
351
+ def finish(gc_duration_ms)
352
+ Extension.appsignal_finish_transaction(pointer, gc_duration_ms)
353
+ end
354
+
355
+ def complete
356
+ Extension.appsignal_complete_transaction(pointer)
357
+ end
358
+
359
+ def to_json
360
+ json = Extension.appsignal_transaction_to_json(pointer)
361
+ make_ruby_string(json) if json[:len] > 0
362
+ end
363
+ end
364
+
365
+ class Data
366
+ include StringHelpers
367
+ attr_reader :pointer
368
+
369
+ def initialize(pointer)
370
+ @pointer = FFI::AutoPointer.new(
371
+ pointer,
372
+ Extension.method(:appsignal_free_data)
373
+ )
374
+ end
375
+
376
+ def set_string(key, value)
377
+ Extension.appsignal_data_map_set_string(
378
+ pointer,
379
+ make_appsignal_string(key),
380
+ make_appsignal_string(value)
381
+ )
382
+ end
383
+
384
+ def set_integer(key, value)
385
+ Extension.appsignal_data_map_set_integer(
386
+ pointer,
387
+ make_appsignal_string(key),
388
+ value
389
+ )
390
+ end
391
+
392
+ def set_float(key, value)
393
+ Extension.appsignal_data_map_set_float(
394
+ pointer,
395
+ make_appsignal_string(key),
396
+ value
397
+ )
398
+ end
399
+
400
+ def set_boolean(key, value)
401
+ Extension.appsignal_data_map_set_boolean(
402
+ pointer,
403
+ make_appsignal_string(key),
404
+ value
405
+ )
406
+ end
407
+
408
+ def set_nil(key) # rubocop:disable Style/AccessorMethodName
409
+ Extension.appsignal_data_map_set_null(
410
+ pointer,
411
+ make_appsignal_string(key)
412
+ )
413
+ end
414
+
415
+ def set_data(key, value)
416
+ Extension.appsignal_data_map_set_data(
417
+ pointer,
418
+ make_appsignal_string(key),
419
+ value.pointer
420
+ )
421
+ end
422
+
423
+ def append_string(value)
424
+ Extension.appsignal_data_array_append_string(
425
+ pointer,
426
+ make_appsignal_string(value)
427
+ )
428
+ end
429
+
430
+ def append_integer(value)
431
+ Extension.appsignal_data_array_append_integer(pointer, value)
432
+ end
433
+
434
+ def append_float(value)
435
+ Extension.appsignal_data_array_append_float(pointer, value)
436
+ end
437
+
438
+ def append_boolean(value)
439
+ Extension.appsignal_data_array_append_boolean(pointer, value)
440
+ end
441
+
442
+ def append_nil
443
+ Extension.appsignal_data_array_append_null(pointer)
444
+ end
445
+
446
+ def append_data(value)
447
+ Extension.appsignal_data_array_append_data(pointer, value.pointer)
448
+ end
449
+
450
+ def ==(other)
451
+ Extension.appsignal_data_equal(pointer, other.pointer)
452
+ end
453
+
454
+ def to_s
455
+ make_ruby_string Extension.appsignal_data_to_json(pointer)
456
+ end
457
+ end
458
+ end
459
+ end
460
+ end