appsignal 2.5.0.alpha.1-java

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