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

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