appsignal 1.4.0.alpha.2 → 1.4.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +3 -1
  3. data/.travis.yml +3 -1
  4. data/CHANGELOG.md +38 -1
  5. data/Rakefile +29 -12
  6. data/benchmark.rake +3 -7
  7. data/ext/agent.yml +11 -11
  8. data/ext/appsignal_extension.c +364 -72
  9. data/ext/extconf.rb +2 -4
  10. data/gemfiles/resque.gemfile +1 -0
  11. data/lib/appsignal.rb +40 -30
  12. data/lib/appsignal/auth_check.rb +1 -1
  13. data/lib/appsignal/cli/diagnose.rb +4 -3
  14. data/lib/appsignal/cli/install.rb +16 -15
  15. data/lib/appsignal/config.rb +31 -31
  16. data/lib/appsignal/event_formatter.rb +1 -1
  17. data/lib/appsignal/extension.rb +6 -0
  18. data/lib/appsignal/garbage_collection_profiler.rb +47 -0
  19. data/lib/appsignal/hooks.rb +1 -0
  20. data/lib/appsignal/hooks/active_support_notifications.rb +43 -0
  21. data/lib/appsignal/integrations/capistrano/appsignal.cap +1 -1
  22. data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +2 -2
  23. data/lib/appsignal/integrations/mongo_ruby_driver.rb +1 -1
  24. data/lib/appsignal/integrations/object.rb +4 -4
  25. data/lib/appsignal/integrations/padrino.rb +1 -1
  26. data/lib/appsignal/integrations/sinatra.rb +1 -1
  27. data/lib/appsignal/integrations/webmachine.rb +2 -2
  28. data/lib/appsignal/js_exception_transaction.rb +7 -10
  29. data/lib/appsignal/marker.rb +3 -2
  30. data/lib/appsignal/rack/generic_instrumentation.rb +1 -1
  31. data/lib/appsignal/rack/sinatra_instrumentation.rb +13 -6
  32. data/lib/appsignal/rack/streaming_listener.rb +5 -3
  33. data/lib/appsignal/system.rb +36 -0
  34. data/lib/appsignal/transaction.rb +20 -20
  35. data/lib/appsignal/transmitter.rb +11 -7
  36. data/lib/appsignal/utils.rb +76 -2
  37. data/lib/appsignal/version.rb +1 -1
  38. data/spec/lib/appsignal/auth_check_spec.rb +0 -2
  39. data/spec/lib/appsignal/capistrano2_spec.rb +99 -79
  40. data/spec/lib/appsignal/capistrano3_spec.rb +57 -78
  41. data/spec/lib/appsignal/cli/diagnose_spec.rb +17 -15
  42. data/spec/lib/appsignal/cli/install_spec.rb +38 -20
  43. data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +2 -5
  44. data/spec/lib/appsignal/cli_spec.rb +2 -5
  45. data/spec/lib/appsignal/config_spec.rb +385 -158
  46. data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +1 -3
  47. data/spec/lib/appsignal/event_formatter/active_record/instantiation_formatter_spec.rb +0 -2
  48. data/spec/lib/appsignal/event_formatter/active_record/sql_formatter_spec.rb +0 -2
  49. data/spec/lib/appsignal/event_formatter/elastic_search/search_formatter_spec.rb +0 -2
  50. data/spec/lib/appsignal/event_formatter/faraday/request_formatter_spec.rb +0 -2
  51. data/spec/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter_spec.rb +0 -2
  52. data/spec/lib/appsignal/event_formatter/moped/query_formatter_spec.rb +0 -2
  53. data/spec/lib/appsignal/event_formatter_spec.rb +0 -2
  54. data/spec/lib/appsignal/extension_spec.rb +7 -8
  55. data/spec/lib/appsignal/garbage_collection_profiler_spec.rb +71 -0
  56. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +42 -0
  57. data/spec/lib/appsignal/hooks/celluloid_spec.rb +0 -2
  58. data/spec/lib/appsignal/hooks/data_mapper_spec.rb +0 -2
  59. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +0 -2
  60. data/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb +0 -2
  61. data/spec/lib/appsignal/hooks/net_http_spec.rb +0 -2
  62. data/spec/lib/appsignal/hooks/passenger_spec.rb +0 -2
  63. data/spec/lib/appsignal/hooks/puma_spec.rb +0 -2
  64. data/spec/lib/appsignal/hooks/rake_spec.rb +1 -2
  65. data/spec/lib/appsignal/hooks/redis_spec.rb +0 -2
  66. data/spec/lib/appsignal/hooks/sequel_spec.rb +19 -21
  67. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +1 -4
  68. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +2 -3
  69. data/spec/lib/appsignal/hooks/unicorn_spec.rb +0 -2
  70. data/spec/lib/appsignal/hooks/webmachine_spec.rb +4 -11
  71. data/spec/lib/appsignal/hooks_spec.rb +0 -2
  72. data/spec/lib/appsignal/integrations/data_mapper_spec.rb +0 -1
  73. data/spec/lib/appsignal/integrations/grape_spec.rb +1 -3
  74. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +1 -2
  75. data/spec/lib/appsignal/integrations/object_spec.rb +32 -3
  76. data/spec/lib/appsignal/integrations/padrino_spec.rb +4 -11
  77. data/spec/lib/appsignal/integrations/railtie_spec.rb +1 -3
  78. data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +1 -3
  79. data/spec/lib/appsignal/integrations/resque_spec.rb +2 -4
  80. data/spec/lib/appsignal/integrations/sinatra_spec.rb +33 -8
  81. data/spec/lib/appsignal/integrations/webmachine_spec.rb +6 -15
  82. data/spec/lib/appsignal/js_exception_transaction_spec.rb +3 -5
  83. data/spec/lib/appsignal/marker_spec.rb +35 -48
  84. data/spec/lib/appsignal/minutely_spec.rb +0 -2
  85. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +0 -2
  86. data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +0 -2
  87. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +3 -5
  88. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +47 -11
  89. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +6 -7
  90. data/spec/lib/appsignal/system/container_spec.rb +67 -0
  91. data/spec/lib/appsignal/system_spec.rb +49 -0
  92. data/spec/lib/appsignal/transaction_spec.rb +30 -13
  93. data/spec/lib/appsignal/transmitter_spec.rb +53 -20
  94. data/spec/lib/appsignal/utils/gzip_spec.rb +10 -0
  95. data/spec/lib/appsignal/utils/params_sanitizer_spec.rb +0 -2
  96. data/spec/lib/appsignal/utils/query_params_sanitizer_spec.rb +0 -2
  97. data/spec/lib/appsignal/utils_spec.rb +59 -3
  98. data/spec/lib/appsignal_spec.rb +132 -58
  99. data/spec/spec_helper.rb +24 -116
  100. data/spec/support/fixtures/containers/cgroups/docker +14 -0
  101. data/spec/support/fixtures/containers/cgroups/docker_systemd +8 -0
  102. data/spec/support/fixtures/containers/cgroups/lxc +10 -0
  103. data/spec/support/fixtures/containers/cgroups/no_permission +0 -0
  104. data/spec/support/fixtures/containers/cgroups/none +1 -0
  105. data/spec/support/helpers/api_request_helper.rb +22 -0
  106. data/spec/support/helpers/dependency_helper.rb +61 -0
  107. data/spec/support/helpers/directory_helper.rb +27 -0
  108. data/spec/support/helpers/std_streams_helper.rb +35 -0
  109. data/spec/support/helpers/system_helpers.rb +24 -0
  110. data/spec/support/helpers/transaction_helpers.rb +7 -64
  111. data/spec/support/helpers/very_specific_error.rb +8 -0
  112. data/spec/support/mocks/fake_gc_profiler.rb +19 -0
  113. data/spec/support/project_fixture/config/appsignal.yml +10 -1
  114. metadata +60 -35
  115. data/circle.yml +0 -12
  116. data/lib/appsignal/subscriber.rb +0 -55
  117. data/lib/appsignal/update_active_support.rb +0 -20
  118. data/lib/vendor/active_support/notifications.rb +0 -212
  119. data/lib/vendor/active_support/notifications/fanout.rb +0 -157
  120. data/lib/vendor/active_support/notifications/instrumenter.rb +0 -73
  121. data/lib/vendor/active_support/per_thread_registry.rb +0 -53
  122. data/spec/lib/appsignal/subscriber_spec.rb +0 -160
  123. data/spec/lib/appsignal/update_active_support_spec.rb +0 -17
  124. data/spec/support/helpers/notification_helpers.rb +0 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 418a7f404c4466510643a211e5c02f471eca6774
4
- data.tar.gz: 76eb38f7a9095fce099bd1273018c25403e6fa40
3
+ metadata.gz: 596cead7e715bf92192c49a6a74a452836a72d2e
4
+ data.tar.gz: 08bbd29e1f602c14aaaf934284ab37f084d0879e
5
5
  SHA512:
6
- metadata.gz: 6ad62b586d4c3f410129badb7355318ad6b099ddcdd739ef2c6d0f786b5f74b992fdaf4f3169eaccb98c15acdd22f729cf48826e5baaebd83b2ae074c033011d
7
- data.tar.gz: 814450ee63b012e911f8e8b4c3a0c643a9b8b4f7282a42466318c38c10a8e7a38d32b484fe0bce392fbcefdc1d6faba136c548237b034933f0ff6a56ff3db907
6
+ metadata.gz: 303d79b2ba2a59165230a1462c53bc2e259438055319ce505d3b007a3825d8ddbcc2d9a78a3d1d77631e35ef425916fb412df085296cfe1ed22eb609444665d2
7
+ data.tar.gz: d95b49731fe7838487773f772b02a2c8da3d687df4be19e95b4c52d19c36090afba4c3b85bf7a4fd21ccd10f3ee1ddcfc2a7fd9cf10b301626463881ade5a0f6
data/.rspec CHANGED
@@ -1 +1,3 @@
1
- --order default --warnings
1
+ --order default
2
+ --warnings
3
+ --require spec_helper
@@ -45,4 +45,6 @@ matrix:
45
45
  env:
46
46
  global: "RAILS_ENV=test"
47
47
 
48
- script: "bundle exec rake travis"
48
+ before_script: "bundle exec rake extension:install"
49
+
50
+ script: "bundle exec rake test"
@@ -1,5 +1,40 @@
1
1
  # 1.4.0
2
- * Support for a wider range of Linux versions, including Alpine
2
+ * Add Appsignal.instrument_sql convenience methods
3
+ * Use Appsignal.instrument internally instead of AS instrument
4
+ * Override AS instrument instead of subscribing
5
+ * Use have_library to link libappsignal
6
+ * Refactor rescueing of exceptions
7
+ * Use GC::Profiler to track garbage collection time
8
+ * Recognize wether we're running in container
9
+ * Change load order to set system config first
10
+ * Remove unused config method
11
+
12
+ # 1.3.6
13
+ * Support blocks arguments on method instrumentation
14
+ * Support `APPSIGNAL_APP_ENV` for Sinatra
15
+ * Minor improvements to installer
16
+ * More robust handing of non-writable log files
17
+ * Cleaner internal exception handling
18
+ * Support for mixed case keywords in sql lexing
19
+ * Support for inserting multiple rows in sql lexing
20
+
21
+ # 1.3.5
22
+
23
+ * Fix SSL certificate config in appsignal-agent. PR #151
24
+ * Remove mounted_at Sinatra middleware option. Now detected by default. PR #146
25
+ * Sinatra applications with middleware loading before AppSignal's middleware
26
+ would crash a request. Fixed in PR #156
27
+
28
+ # 1.3.4
29
+
30
+ * Fix argument order for `record_event` in the AppSignal extension
31
+
32
+ # 1.3.3
33
+
34
+ * Output AppSignal environment on `appsignal diagnose`
35
+ * Prevent transaction crashes on Sinatra routes with optional parameters
36
+ * Listen to `stage` option to Capistrano 2 for automatic environment detection
37
+ * Add `appsignal_env` option to Capistrano 2 to set a custom environment
3
38
 
4
39
  # 1.3.2
5
40
  * Add method to discard a transaction
@@ -26,6 +61,8 @@
26
61
  * Allow overriding Padrino environment with APPSIGNAL_APP_ENV
27
62
  * Add mkmf.log to diagnose command
28
63
  * Allow for local install with bundler `bundle exec rake install`
64
+ * Listen to `stage` option to Capistrano 3 for automatic environment detection
65
+ * Add `appsignal_env` option to Capistrano 3 to set a custom environment
29
66
 
30
67
  # 1.2.5
31
68
  * Bugfix in CPU utilization calculation for host metrics
data/Rakefile CHANGED
@@ -103,8 +103,8 @@ task :publish do
103
103
  end
104
104
  end
105
105
 
106
- task :install do
107
- system 'cd ext && rm -f libappsignal.a appsignal-agent appsignal_extension.h Makefile appsignal.bundle && ruby extconf.rb && make && cd ..'
106
+ desc 'Install the AppSignal gem, extension and all possible dependencies.'
107
+ task :install => "extension:install" do
108
108
  Bundler.with_clean_env do
109
109
  GEMFILES.each do |gemfile|
110
110
  system "bundle --gemfile gemfiles/#{gemfile}.gemfile"
@@ -114,8 +114,10 @@ end
114
114
 
115
115
  task :spec_all_gemfiles do
116
116
  GEMFILES.each do |gemfile|
117
- puts "Running #{gemfile}"
118
- raise 'Not successful' unless system("env BUNDLE_GEMFILE=gemfiles/#{gemfile}.gemfile bundle exec rspec")
117
+ puts "Running tests for #{gemfile}"
118
+ unless system("env BUNDLE_GEMFILE=gemfiles/#{gemfile}.gemfile bundle exec rspec")
119
+ raise 'Not successful'
120
+ end
119
121
  end
120
122
  end
121
123
 
@@ -135,7 +137,7 @@ task :generate_bundle_and_spec_all do
135
137
  out << "#{switch_command.call(version)} || { echo 'Switching Ruby failed'; exit 1; }"
136
138
  out << "ruby -v"
137
139
  out << "echo 'Compiling extension'"
138
- out << 'cd ext && rm -f appsignal-agent appsignal_extension.bundle appsignal.h libappsignal.a Makefile && ruby extconf.rb && make && cd ..'
140
+ out << 'cd ext && rm -f appsignal-agent appsignal_extension.bundle appsignal.h libappsignal.a Makefile && ruby extconf.rb && make && cd ..'
139
141
  GEMFILES.each do |gemfile|
140
142
  unless EXCLUSIONS[gemfile] && EXCLUSIONS[gemfile].include?(short_version)
141
143
  out << "echo 'Bundling #{gemfile} in #{short_version}'"
@@ -169,19 +171,34 @@ task :console do
169
171
  IRB.start
170
172
  end
171
173
 
172
- task :install_extension do
173
- `cd ext && rm -f libappsignal.a && ruby extconf.rb && make clean && make`
174
+ namespace :extension do
175
+ desc 'Install the AppSignal gem extension'
176
+ task :install => :clean do
177
+ system 'cd ext && ruby extconf.rb && make clean && make'
178
+ end
179
+
180
+ desc 'Clean the AppSignal gem extension directory of installation artifacts'
181
+ task :clean do
182
+ system <<-COMMAND
183
+ cd ext &&
184
+ rm -f appsignal.bundle \
185
+ appsignal-agent \
186
+ appsignal.h \
187
+ appsignal_extension.o \
188
+ install.log \
189
+ libappsignal.a \
190
+ Makefile \
191
+ mkmf.log
192
+ COMMAND
193
+ end
174
194
  end
175
195
 
176
196
  begin
177
197
  require 'rspec/core/rake_task'
178
- RSpec::Core::RakeTask.new(:rspec) do |t|
179
- t.pattern = Dir.glob('spec/**/*_spec.rb')
180
- end
198
+ desc 'Run the AppSignal gem test suite.'
199
+ RSpec::Core::RakeTask.new :test
181
200
  rescue LoadError
182
201
  # When running rake install, there is no RSpec yet.
183
202
  end
184
203
 
185
- task :travis => [:install_extension, :rspec]
186
-
187
204
  task :default => [:generate_bundle_and_spec_all, :spec_all_gemfiles]
@@ -1,10 +1,7 @@
1
+ require 'active_support'
1
2
  require 'appsignal'
2
3
  require 'benchmark'
3
4
 
4
- class ::Appsignal::EventFormatter::ActiveRecord::SqlFormatter
5
- def connection_config; {:adapter => 'mysql'}; end
6
- end
7
-
8
5
  GC.disable
9
6
 
10
7
  task :default => :'benchmark:all'
@@ -46,9 +43,8 @@ def run_benchmark
46
43
  )
47
44
  Appsignal::Transaction.create("transaction_#{i}", Appsignal::Transaction::HTTP_REQUEST, request)
48
45
 
49
- ActiveSupport::Notifications.instrument('process_action.action_controller') do
50
- ActiveSupport::Notifications.instrument('sql.active_record', :sql => 'SELECT `users`.* FROM `users`
51
- WHERE `users`.`id` = ?')
46
+ Appsignal.instrument('process_action.action_controller') do
47
+ ActiveSupport::Notifications.instrument('sql.active_record', :sql => 'SELECT `users`.* FROM `users` WHERE `users`.`id` = ?')
52
48
  10.times do
53
49
  ActiveSupport::Notifications.instrument('sql.active_record', :sql => 'SELECT `todos`.* FROM `todos` WHERE `todos`.`id` = ?')
54
50
  end
@@ -1,18 +1,18 @@
1
1
  ---
2
- version: 063afb6
2
+ version: 61c23ea
3
3
  triples:
4
4
  x86_64-linux:
5
- checksum: 01782fccb0a9908ac010944d825c5ad4520fccd7363089222ba9071216e9cd13
6
- download_url: https://appsignal-agent-releases.global.ssl.fastly.net/063afb6/appsignal-x86_64-linux-all-static.tar.gz
5
+ checksum: 6a0a1ebf6a1a9c7d2ac939f9077fd279155359ed72c74284d70daf0f53b27b10
6
+ download_url: https://appsignal-agent-releases.global.ssl.fastly.net/61c23ea/appsignal-x86_64-linux-all-static.tar.gz
7
7
  i686-linux:
8
- checksum: ef37569b39c2ba6a69db9c64e18f32aa19116b47d818450aa71e9d825a1cacc7
9
- download_url: https://appsignal-agent-releases.global.ssl.fastly.net/063afb6/appsignal-i686-linux-all-static.tar.gz
8
+ checksum: 498e11631eae3418a55a733ac13b993c35afb782be9fb5c4e5b6be0f52f4f76c
9
+ download_url: https://appsignal-agent-releases.global.ssl.fastly.net/61c23ea/appsignal-i686-linux-all-static.tar.gz
10
10
  x86-linux:
11
- checksum: ef37569b39c2ba6a69db9c64e18f32aa19116b47d818450aa71e9d825a1cacc7
12
- download_url: https://appsignal-agent-releases.global.ssl.fastly.net/063afb6/appsignal-i686-linux-all-static.tar.gz
11
+ checksum: 498e11631eae3418a55a733ac13b993c35afb782be9fb5c4e5b6be0f52f4f76c
12
+ download_url: https://appsignal-agent-releases.global.ssl.fastly.net/61c23ea/appsignal-i686-linux-all-static.tar.gz
13
13
  x86_64-darwin:
14
- checksum: 88123e35e5eaad135cf64f719fb9a9156db7a9aab999bd1aabf6a34e078972b6
15
- download_url: https://appsignal-agent-releases.global.ssl.fastly.net/063afb6/appsignal-x86_64-darwin-all-static.tar.gz
14
+ checksum: 62a6ffc8d379bcba0cf7e48f92690b62ffacee81f3e996ace215f56eb03d2be6
15
+ download_url: https://appsignal-agent-releases.global.ssl.fastly.net/61c23ea/appsignal-x86_64-darwin-all-static.tar.gz
16
16
  universal-darwin:
17
- checksum: 88123e35e5eaad135cf64f719fb9a9156db7a9aab999bd1aabf6a34e078972b6
18
- download_url: https://appsignal-agent-releases.global.ssl.fastly.net/063afb6/appsignal-x86_64-darwin-all-static.tar.gz
17
+ checksum: 62a6ffc8d379bcba0cf7e48f92690b62ffacee81f3e996ace215f56eb03d2be6
18
+ download_url: https://appsignal-agent-releases.global.ssl.fastly.net/61c23ea/appsignal-x86_64-darwin-all-static.tar.gz
@@ -17,7 +17,8 @@ static inline VALUE make_ruby_string(appsignal_string_t string) {
17
17
 
18
18
  VALUE Appsignal;
19
19
  VALUE Extension;
20
- VALUE ExtTransaction;
20
+ VALUE Transaction;
21
+ VALUE Data;
21
22
 
22
23
  static VALUE start(VALUE self) {
23
24
  appsignal_start();
@@ -44,106 +45,155 @@ static VALUE get_server_state(VALUE self, VALUE key) {
44
45
  }
45
46
  }
46
47
 
47
- static VALUE start_transaction(VALUE self, VALUE transaction_id, VALUE namespace) {
48
+ static VALUE start_transaction(VALUE self, VALUE transaction_id, VALUE namespace, VALUE gc_duration_ms) {
48
49
  appsignal_transaction_t* transaction;
49
50
 
50
51
  Check_Type(transaction_id, T_STRING);
51
52
  Check_Type(namespace, T_STRING);
53
+ Check_Type(gc_duration_ms, T_FIXNUM);
52
54
 
53
55
  transaction = appsignal_start_transaction(
54
56
  make_appsignal_string(transaction_id),
55
- make_appsignal_string(namespace)
57
+ make_appsignal_string(namespace),
58
+ NUM2LONG(gc_duration_ms)
56
59
  );
57
60
 
58
61
  if (transaction) {
59
- return Data_Wrap_Struct(ExtTransaction, NULL, appsignal_free_transaction, transaction);
62
+ return Data_Wrap_Struct(Transaction, NULL, appsignal_free_transaction, transaction);
60
63
  } else {
61
64
  return Qnil;
62
65
  }
63
66
  }
64
67
 
65
- static VALUE start_event(VALUE self) {
68
+ static VALUE start_event(VALUE self, VALUE gc_duration_ms) {
66
69
  appsignal_transaction_t* transaction;
67
70
 
71
+ Check_Type(gc_duration_ms, T_FIXNUM);
72
+
68
73
  Data_Get_Struct(self, appsignal_transaction_t, transaction);
69
74
 
70
- appsignal_start_event(transaction);
75
+ appsignal_start_event(transaction, NUM2LONG(gc_duration_ms));
71
76
 
72
77
  return Qnil;
73
78
  }
74
79
 
75
- static VALUE finish_event(VALUE self, VALUE name, VALUE title, VALUE body, VALUE body_format) {
80
+ static VALUE finish_event(VALUE self, VALUE name, VALUE title, VALUE body, VALUE body_format, VALUE gc_duration_ms) {
76
81
  appsignal_transaction_t* transaction;
82
+ appsignal_data_t* body_data;
83
+ int body_type;
77
84
 
78
85
  Check_Type(name, T_STRING);
79
86
  Check_Type(title, T_STRING);
80
- Check_Type(body, T_STRING);
81
87
  Check_Type(body_format, T_FIXNUM);
88
+
82
89
  Data_Get_Struct(self, appsignal_transaction_t, transaction);
83
90
 
84
- appsignal_finish_event(
85
- transaction,
86
- make_appsignal_string(name),
87
- make_appsignal_string(title),
88
- make_appsignal_string(body),
89
- FIX2INT(body_format)
90
- );
91
+ body_type = TYPE(body);
92
+ if (body_type == T_STRING) {
93
+ appsignal_finish_event(
94
+ transaction,
95
+ make_appsignal_string(name),
96
+ make_appsignal_string(title),
97
+ make_appsignal_string(body),
98
+ FIX2INT(body_format),
99
+ FIX2LONG(gc_duration_ms)
100
+ );
101
+ } else if (body_type == RUBY_T_DATA) {
102
+ Data_Get_Struct(body, appsignal_data_t, body_data);
103
+ appsignal_finish_event_data(
104
+ transaction,
105
+ make_appsignal_string(name),
106
+ make_appsignal_string(title),
107
+ body_data,
108
+ FIX2INT(body_format),
109
+ FIX2LONG(gc_duration_ms)
110
+ );
111
+ } else {
112
+ rb_raise(rb_eTypeError, "body should be a String or Appsignal::Extension::Data");
113
+ }
114
+
91
115
  return Qnil;
92
116
  }
93
117
 
94
- static VALUE record_event(VALUE self, VALUE name, VALUE title, VALUE body, VALUE duration, VALUE body_format) {
118
+ static VALUE record_event(VALUE self, VALUE name, VALUE title, VALUE body, VALUE duration, VALUE body_format, VALUE gc_duration_ms) {
95
119
  appsignal_transaction_t* transaction;
120
+ appsignal_data_t* body_data;
121
+ int body_type;
96
122
  int duration_type;
97
123
 
98
124
  Check_Type(name, T_STRING);
99
125
  Check_Type(title, T_STRING);
100
- Check_Type(body, T_STRING);
101
126
  duration_type = TYPE(duration);
102
127
  if (duration_type != T_FIXNUM && duration_type != T_BIGNUM) {
103
128
  rb_raise(rb_eTypeError, "duration should be a Fixnum or Bignum");
104
129
  }
105
130
  Check_Type(body_format, T_FIXNUM);
131
+
106
132
  Data_Get_Struct(self, appsignal_transaction_t, transaction);
107
133
 
108
- appsignal_record_event(
109
- transaction,
110
- make_appsignal_string(name),
111
- make_appsignal_string(title),
112
- make_appsignal_string(body),
113
- FIX2INT(body_format),
114
- NUM2LONG(duration)
115
- );
134
+ body_type = TYPE(body);
135
+ if (body_type == T_STRING) {
136
+ appsignal_record_event(
137
+ transaction,
138
+ make_appsignal_string(name),
139
+ make_appsignal_string(title),
140
+ make_appsignal_string(body),
141
+ FIX2INT(body_format),
142
+ NUM2LONG(duration),
143
+ NUM2LONG(gc_duration_ms)
144
+ );
145
+ } else if (body_type == RUBY_T_DATA) {
146
+ Data_Get_Struct(body, appsignal_data_t, body_data);
147
+ appsignal_record_event_data(
148
+ transaction,
149
+ make_appsignal_string(name),
150
+ make_appsignal_string(title),
151
+ body_data,
152
+ FIX2INT(body_format),
153
+ NUM2LONG(duration),
154
+ NUM2LONG(gc_duration_ms)
155
+ );
156
+ } else {
157
+ rb_raise(rb_eTypeError, "body should be a String or Appsignal::Extension::Data");
158
+ }
159
+
116
160
  return Qnil;
117
161
  }
118
162
 
119
163
  static VALUE set_transaction_error(VALUE self, VALUE name, VALUE message, VALUE backtrace) {
120
164
  appsignal_transaction_t* transaction;
165
+ appsignal_data_t* backtrace_data;
121
166
 
122
167
  Check_Type(name, T_STRING);
123
168
  Check_Type(message, T_STRING);
124
- Check_Type(backtrace, T_STRING);
169
+ Check_Type(backtrace, RUBY_T_DATA);
170
+
125
171
  Data_Get_Struct(self, appsignal_transaction_t, transaction);
172
+ Data_Get_Struct(backtrace, appsignal_data_t, backtrace_data);
126
173
 
127
174
  appsignal_set_transaction_error(
128
175
  transaction,
129
176
  make_appsignal_string(name),
130
177
  make_appsignal_string(message),
131
- make_appsignal_string(backtrace)
178
+ backtrace_data
132
179
  );
133
180
  return Qnil;
134
181
  }
135
182
 
136
183
  static VALUE set_transaction_sample_data(VALUE self, VALUE key, VALUE payload) {
137
184
  appsignal_transaction_t* transaction;
185
+ appsignal_data_t* payload_data;
138
186
 
139
187
  Check_Type(key, T_STRING);
140
- Check_Type(payload, T_STRING);
188
+ Check_Type(payload, RUBY_T_DATA);
189
+
141
190
  Data_Get_Struct(self, appsignal_transaction_t, transaction);
191
+ Data_Get_Struct(payload, appsignal_data_t, payload_data);
142
192
 
143
193
  appsignal_set_transaction_sample_data(
144
194
  transaction,
145
195
  make_appsignal_string(key),
146
- make_appsignal_string(payload)
196
+ payload_data
147
197
  );
148
198
  return Qnil;
149
199
  }
@@ -194,13 +244,14 @@ static VALUE set_transaction_metadata(VALUE self, VALUE key, VALUE value) {
194
244
  return Qnil;
195
245
  }
196
246
 
197
- static VALUE finish_transaction(VALUE self) {
247
+ static VALUE finish_transaction(VALUE self, VALUE gc_duration_ms) {
198
248
  appsignal_transaction_t* transaction;
199
249
  int sample;
200
250
 
251
+ Check_Type(gc_duration_ms, T_FIXNUM);
201
252
  Data_Get_Struct(self, appsignal_transaction_t, transaction);
202
253
 
203
- sample = appsignal_finish_transaction(transaction);
254
+ sample = appsignal_finish_transaction(transaction, NUM2LONG(gc_duration_ms));
204
255
  return sample == 1 ? Qtrue : Qfalse;
205
256
  }
206
257
 
@@ -213,6 +264,249 @@ static VALUE complete_transaction(VALUE self) {
213
264
  return Qnil;
214
265
  }
215
266
 
267
+ static VALUE data_map_new(VALUE self) {
268
+ appsignal_data_t* data;
269
+
270
+ data = appsignal_data_map_new();
271
+
272
+ if (data) {
273
+ return Data_Wrap_Struct(Data, NULL, appsignal_free_data, data);
274
+ } else {
275
+ return Qnil;
276
+ }
277
+ }
278
+
279
+ static VALUE data_array_new(VALUE self) {
280
+ appsignal_data_t* data;
281
+
282
+ data = appsignal_data_array_new();
283
+
284
+ if (data) {
285
+ return Data_Wrap_Struct(Data, NULL, appsignal_free_data, data);
286
+ } else {
287
+ return Qnil;
288
+ }
289
+ }
290
+
291
+ static VALUE data_set_string(VALUE self, VALUE key, VALUE value) {
292
+ appsignal_data_t* data;
293
+
294
+ Check_Type(key, T_STRING);
295
+ Check_Type(value, T_STRING);
296
+
297
+ Data_Get_Struct(self, appsignal_data_t, data);
298
+
299
+ appsignal_data_map_set_string(
300
+ data,
301
+ make_appsignal_string(key),
302
+ make_appsignal_string(value)
303
+ );
304
+
305
+ return Qnil;
306
+ }
307
+
308
+ static VALUE data_set_fixnum(VALUE self, VALUE key, VALUE value) {
309
+ appsignal_data_t* data;
310
+
311
+ Check_Type(key, T_STRING);
312
+ Check_Type(value, T_FIXNUM);
313
+
314
+ Data_Get_Struct(self, appsignal_data_t, data);
315
+
316
+ appsignal_data_map_set_integer(
317
+ data,
318
+ make_appsignal_string(key),
319
+ FIX2LONG(value)
320
+ );
321
+
322
+ return Qnil;
323
+ }
324
+
325
+ static VALUE data_set_float(VALUE self, VALUE key, VALUE value) {
326
+ appsignal_data_t* data;
327
+
328
+ Check_Type(key, T_STRING);
329
+ Check_Type(value, T_FLOAT);
330
+
331
+ Data_Get_Struct(self, appsignal_data_t, data);
332
+
333
+ appsignal_data_map_set_float(
334
+ data,
335
+ make_appsignal_string(key),
336
+ NUM2DBL(value)
337
+ );
338
+
339
+ return Qnil;
340
+ }
341
+
342
+ static VALUE data_set_boolean(VALUE self, VALUE key, VALUE value) {
343
+ appsignal_data_t* data;
344
+
345
+ Check_Type(key, T_STRING);
346
+
347
+ Data_Get_Struct(self, appsignal_data_t, data);
348
+
349
+ appsignal_data_map_set_boolean(
350
+ data,
351
+ make_appsignal_string(key),
352
+ RTEST(value)
353
+ );
354
+
355
+ return Qnil;
356
+ }
357
+
358
+ static VALUE data_set_nil(VALUE self, VALUE key) {
359
+ appsignal_data_t* data;
360
+
361
+ Check_Type(key, T_STRING);
362
+
363
+ Data_Get_Struct(self, appsignal_data_t, data);
364
+
365
+ appsignal_data_map_set_null(
366
+ data,
367
+ make_appsignal_string(key)
368
+ );
369
+
370
+ return Qnil;
371
+ }
372
+
373
+ static VALUE data_set_data(VALUE self, VALUE key, VALUE value) {
374
+ appsignal_data_t* data;
375
+ appsignal_data_t* value_data;
376
+
377
+ Check_Type(key, T_STRING);
378
+ Check_Type(value, RUBY_T_DATA);
379
+
380
+ Data_Get_Struct(self, appsignal_data_t, data);
381
+ Data_Get_Struct(value, appsignal_data_t, value_data);
382
+
383
+ appsignal_data_map_set_data(
384
+ data,
385
+ make_appsignal_string(key),
386
+ value_data
387
+ );
388
+
389
+ return Qnil;
390
+ }
391
+
392
+ static VALUE data_append_string(VALUE self, VALUE value) {
393
+ appsignal_data_t* data;
394
+
395
+ Check_Type(value, T_STRING);
396
+
397
+ Data_Get_Struct(self, appsignal_data_t, data);
398
+
399
+ appsignal_data_array_append_string(
400
+ data,
401
+ make_appsignal_string(value)
402
+ );
403
+
404
+ return Qnil;
405
+ }
406
+
407
+ static VALUE data_append_fixnum(VALUE self, VALUE value) {
408
+ appsignal_data_t* data;
409
+
410
+ Check_Type(value, T_FIXNUM);
411
+
412
+ Data_Get_Struct(self, appsignal_data_t, data);
413
+
414
+ appsignal_data_array_append_integer(
415
+ data,
416
+ FIX2LONG(value)
417
+ );
418
+
419
+ return Qnil;
420
+ }
421
+
422
+ static VALUE data_append_float(VALUE self, VALUE value) {
423
+ appsignal_data_t* data;
424
+
425
+ Check_Type(value, T_FLOAT);
426
+
427
+ Data_Get_Struct(self, appsignal_data_t, data);
428
+
429
+ appsignal_data_array_append_float(
430
+ data,
431
+ NUM2DBL(value)
432
+ );
433
+
434
+ return Qnil;
435
+ }
436
+
437
+ static VALUE data_append_boolean(VALUE self, VALUE value) {
438
+ appsignal_data_t* data;
439
+
440
+ Data_Get_Struct(self, appsignal_data_t, data);
441
+
442
+ appsignal_data_array_append_boolean(
443
+ data,
444
+ RTEST(value)
445
+ );
446
+
447
+ return Qnil;
448
+ }
449
+
450
+ static VALUE data_append_nil(VALUE self, VALUE value) {
451
+ appsignal_data_t* data;
452
+
453
+ Data_Get_Struct(self, appsignal_data_t, data);
454
+
455
+ appsignal_data_array_append_null(data);
456
+
457
+ return Qnil;
458
+ }
459
+
460
+ static VALUE data_append_data(VALUE self, VALUE value) {
461
+ appsignal_data_t* data;
462
+ appsignal_data_t* value_data;
463
+
464
+ Check_Type(value, RUBY_T_DATA);
465
+
466
+ Data_Get_Struct(self, appsignal_data_t, data);
467
+ Data_Get_Struct(value, appsignal_data_t, value_data);
468
+
469
+ appsignal_data_array_append_data(
470
+ data,
471
+ value_data
472
+ );
473
+
474
+ return Qnil;
475
+ }
476
+
477
+ static VALUE data_equal(VALUE self, VALUE other) {
478
+ appsignal_data_t* data;
479
+ appsignal_data_t* other_data;
480
+
481
+ if (TYPE(other) != RUBY_T_DATA) {
482
+ return Qfalse;
483
+ }
484
+
485
+ Data_Get_Struct(self, appsignal_data_t, data);
486
+ Data_Get_Struct(other, appsignal_data_t, other_data);
487
+
488
+ if (appsignal_data_equal(data, other_data) == 1) {
489
+ return Qtrue;
490
+ } else {
491
+ return Qfalse;
492
+ }
493
+ }
494
+
495
+ static VALUE data_to_s(VALUE self) {
496
+ appsignal_data_t* data;
497
+ appsignal_string_t json;
498
+
499
+ Data_Get_Struct(self, appsignal_data_t, data);
500
+
501
+ json = appsignal_data_to_json(data);
502
+
503
+ if (json.len == 0) {
504
+ return Qnil;
505
+ } else {
506
+ return make_ruby_string(json);
507
+ }
508
+ }
509
+
216
510
  static VALUE set_gauge(VALUE self, VALUE key, VALUE value) {
217
511
  Check_Type(key, T_STRING);
218
512
  Check_Type(value, T_FLOAT);
@@ -272,14 +566,6 @@ static void track_allocation(rb_event_flag_t flag, VALUE arg1, VALUE arg2, ID ar
272
566
  appsignal_track_allocation();
273
567
  }
274
568
 
275
- static void track_gc_start(rb_event_flag_t flag, VALUE arg1, VALUE arg2, ID arg3, VALUE arg4) {
276
- appsignal_track_gc_start();
277
- }
278
-
279
- static void track_gc_end(rb_event_flag_t flag, VALUE arg1, VALUE arg2, ID arg3, VALUE arg4) {
280
- appsignal_track_gc_end();
281
- }
282
-
283
569
  static VALUE install_allocation_event_hook() {
284
570
  // This event hook is only available on Ruby 2.1 and 2.2
285
571
  #if defined(RUBY_INTERNAL_EVENT_NEWOBJ)
@@ -293,30 +579,11 @@ static VALUE install_allocation_event_hook() {
293
579
  return Qnil;
294
580
  }
295
581
 
296
- static VALUE install_gc_event_hooks() {
297
- // These event hooks are only available on Ruby 2.1 and 2.2
298
- #if defined(RUBY_INTERNAL_EVENT_GC_START)
299
- rb_add_event_hook(
300
- track_gc_start,
301
- RUBY_INTERNAL_EVENT_GC_START,
302
- Qnil
303
- );
304
- #endif
305
- #if defined(RUBY_INTERNAL_EVENT_GC_END_MARK)
306
- rb_add_event_hook(
307
- track_gc_end,
308
- RUBY_INTERNAL_EVENT_GC_END_MARK,
309
- Qnil
310
- );
311
- #endif
312
-
313
- return Qnil;
314
- }
315
-
316
582
  void Init_appsignal_extension(void) {
317
583
  Appsignal = rb_define_module("Appsignal");
318
584
  Extension = rb_define_class_under(Appsignal, "Extension", rb_cObject);
319
- ExtTransaction = rb_define_class_under(Extension, "ExtTransaction", rb_cObject);
585
+ Transaction = rb_define_class_under(Extension, "Transaction", rb_cObject);
586
+ Data = rb_define_class_under(Extension, "Data", rb_cObject);
320
587
 
321
588
  // Starting and stopping
322
589
  rb_define_singleton_method(Extension, "start", start, 0);
@@ -326,23 +593,48 @@ void Init_appsignal_extension(void) {
326
593
  rb_define_singleton_method(Extension, "get_server_state", get_server_state, 1);
327
594
 
328
595
  // Start transaction
329
- rb_define_singleton_method(Extension, "start_transaction", start_transaction, 2);
596
+ rb_define_singleton_method(Extension, "start_transaction", start_transaction, 3);
330
597
 
331
598
  // Transaction instance methods
332
- rb_define_method(ExtTransaction, "start_event", start_event, 0);
333
- rb_define_method(ExtTransaction, "finish_event", finish_event, 4);
334
- rb_define_method(ExtTransaction, "record_event", record_event, 5);
335
- rb_define_method(ExtTransaction, "set_error", set_transaction_error, 3);
336
- rb_define_method(ExtTransaction, "set_sample_data", set_transaction_sample_data, 2);
337
- rb_define_method(ExtTransaction, "set_action", set_transaction_action, 1);
338
- rb_define_method(ExtTransaction, "set_queue_start", set_transaction_queue_start, 1);
339
- rb_define_method(ExtTransaction, "set_metadata", set_transaction_metadata, 2);
340
- rb_define_method(ExtTransaction, "finish", finish_transaction, 0);
341
- rb_define_method(ExtTransaction, "complete", complete_transaction, 0);
599
+ rb_define_method(Transaction, "start_event", start_event, 1);
600
+ rb_define_method(Transaction, "finish_event", finish_event, 5);
601
+ rb_define_method(Transaction, "record_event", record_event, 6);
602
+ rb_define_method(Transaction, "set_error", set_transaction_error, 3);
603
+ rb_define_method(Transaction, "set_sample_data", set_transaction_sample_data, 2);
604
+ rb_define_method(Transaction, "set_action", set_transaction_action, 1);
605
+ rb_define_method(Transaction, "set_queue_start", set_transaction_queue_start, 1);
606
+ rb_define_method(Transaction, "set_metadata", set_transaction_metadata, 2);
607
+ rb_define_method(Transaction, "finish", finish_transaction, 1);
608
+ rb_define_method(Transaction, "complete", complete_transaction, 0);
609
+
610
+ // Create a data map or array
611
+ rb_define_singleton_method(Extension, "data_map_new", data_map_new, 0);
612
+ rb_define_singleton_method(Extension, "data_array_new", data_array_new, 0);
613
+
614
+ // Add content to a data map
615
+ rb_define_method(Data, "set_string", data_set_string, 2);
616
+ rb_define_method(Data, "set_fixnum", data_set_fixnum, 2);
617
+ rb_define_method(Data, "set_float", data_set_float, 2);
618
+ rb_define_method(Data, "set_boolean", data_set_boolean, 2);
619
+ rb_define_method(Data, "set_nil", data_set_nil, 1);
620
+ rb_define_method(Data, "set_data", data_set_data, 2);
621
+
622
+ // Add content to a data array
623
+ rb_define_method(Data, "append_string", data_append_string, 1);
624
+ rb_define_method(Data, "append_fixnum", data_append_fixnum, 1);
625
+ rb_define_method(Data, "append_float", data_append_float, 1);
626
+ rb_define_method(Data, "append_boolean", data_append_boolean, 1);
627
+ rb_define_method(Data, "append_nil", data_append_nil, 0);
628
+ rb_define_method(Data, "append_data", data_append_data, 1);
629
+
630
+ // Data equality
631
+ rb_define_method(Data, "==", data_equal, 1);
632
+
633
+ // Get Json content of a data
634
+ rb_define_method(Data, "to_s", data_to_s, 0);
342
635
 
343
636
  // Event hook installation
344
637
  rb_define_singleton_method(Extension, "install_allocation_event_hook", install_allocation_event_hook, 0);
345
- rb_define_singleton_method(Extension, "install_gc_event_hooks", install_gc_event_hooks, 0);
346
638
 
347
639
  // Metrics
348
640
  rb_define_singleton_method(Extension, "set_gauge", set_gauge, 2);