appsignal 2.4.3 → 2.5.0.alpha.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +14 -5
- data/.rubocop_todo.yml +3 -0
- data/.travis.yml +3 -4
- data/CHANGELOG.md +3 -0
- data/Rakefile +21 -6
- data/appsignal.gemspec +12 -5
- data/ext/Rakefile +27 -0
- data/ext/agent.yml +52 -21
- data/ext/base.rb +79 -0
- data/ext/extconf.rb +5 -76
- data/gemfiles/sequel-435.gemfile +5 -1
- data/gemfiles/sequel.gemfile +5 -1
- data/lib/appsignal.rb +11 -6
- data/lib/appsignal/cli.rb +1 -2
- data/lib/appsignal/cli/install.rb +3 -3
- data/lib/appsignal/config.rb +56 -37
- data/lib/appsignal/extension.rb +28 -4
- data/lib/appsignal/extension/jruby.rb +460 -0
- data/lib/appsignal/hooks/sidekiq.rb +4 -4
- data/lib/appsignal/integrations/capistrano/appsignal.cap +7 -2
- data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +8 -3
- data/lib/appsignal/system.rb +16 -1
- data/lib/appsignal/transaction.rb +2 -2
- data/lib/appsignal/utils.rb +3 -1
- data/lib/appsignal/version.rb +1 -3
- data/spec/.rubocop.yml +3 -0
- data/spec/lib/appsignal/capistrano2_spec.rb +55 -41
- data/spec/lib/appsignal/capistrano3_spec.rb +87 -61
- data/spec/lib/appsignal/cli/diagnose_spec.rb +3 -3
- data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +4 -4
- data/spec/lib/appsignal/config_spec.rb +54 -21
- data/spec/lib/appsignal/extension/jruby_spec.rb +43 -0
- data/spec/lib/appsignal/extension_spec.rb +28 -12
- data/spec/lib/appsignal/hooks/sequel_spec.rb +7 -1
- data/spec/lib/appsignal/integrations/que_spec.rb +5 -5
- data/spec/lib/appsignal/system_spec.rb +5 -4
- data/spec/lib/appsignal/transaction_spec.rb +8 -8
- data/spec/lib/appsignal/utils/params_sanitizer_spec.rb +4 -4
- data/spec/lib/appsignal/utils/query_params_sanitizer_spec.rb +3 -3
- data/spec/lib/appsignal_spec.rb +5 -3
- data/spec/spec_helper.rb +29 -8
- data/spec/support/helpers/config_helpers.rb +3 -2
- metadata +12 -7
data/gemfiles/sequel-435.gemfile
CHANGED
data/gemfiles/sequel.gemfile
CHANGED
data/lib/appsignal.rb
CHANGED
@@ -63,6 +63,11 @@ module Appsignal
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
+
# @api private
|
67
|
+
def testing?
|
68
|
+
false
|
69
|
+
end
|
70
|
+
|
66
71
|
# Start the AppSignal integration.
|
67
72
|
#
|
68
73
|
# Starts AppSignal with the given configuration. If no configuration is set
|
@@ -88,7 +93,7 @@ module Appsignal
|
|
88
93
|
#
|
89
94
|
# @return [void]
|
90
95
|
# @since 0.7.0
|
91
|
-
def start
|
96
|
+
def start # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
92
97
|
unless extension_loaded?
|
93
98
|
logger.info("Not starting appsignal, extension is not loaded")
|
94
99
|
return
|
@@ -119,7 +124,7 @@ module Appsignal
|
|
119
124
|
Appsignal::EventFormatter.initialize_formatters
|
120
125
|
initialize_extensions
|
121
126
|
|
122
|
-
if config[:enable_allocation_tracking]
|
127
|
+
if config[:enable_allocation_tracking] && !Appsignal::System.jruby?
|
123
128
|
Appsignal::Extension.install_allocation_event_hook
|
124
129
|
end
|
125
130
|
|
@@ -553,7 +558,7 @@ module Appsignal
|
|
553
558
|
# {.instrument_sql} instead of {EventFormatter::SQL_BODY_FORMAT}.
|
554
559
|
# @yield yields the given block of code instrumented in an AppSignal
|
555
560
|
# event.
|
556
|
-
# @return [Object] Returns the
|
561
|
+
# @return [Object] Returns the block's return value.
|
557
562
|
#
|
558
563
|
# @see Appsignal::Transaction#instrument
|
559
564
|
# @see .instrument_sql
|
@@ -588,7 +593,7 @@ module Appsignal
|
|
588
593
|
# @param title [String, nil] Human readable name of the event.
|
589
594
|
# @param body [String, nil] SQL query that's being executed.
|
590
595
|
# @yield yields the given block of code instrumented in an AppSignal event.
|
591
|
-
# @return [Object] Returns the
|
596
|
+
# @return [Object] Returns the block's return value.
|
592
597
|
#
|
593
598
|
# @see .instrument
|
594
599
|
# @see http://docs.appsignal.com/ruby/instrumentation/instrumentation.html
|
@@ -698,7 +703,7 @@ module Appsignal
|
|
698
703
|
# @see Extension
|
699
704
|
# @since 1.0.0
|
700
705
|
def extension_loaded?
|
701
|
-
|
706
|
+
!!extension_loaded
|
702
707
|
end
|
703
708
|
|
704
709
|
# Returns the active state of the AppSignal integration.
|
@@ -778,6 +783,7 @@ module Appsignal
|
|
778
783
|
end
|
779
784
|
end
|
780
785
|
|
786
|
+
require "appsignal/system"
|
781
787
|
require "appsignal/utils"
|
782
788
|
require "appsignal/extension"
|
783
789
|
require "appsignal/auth_check"
|
@@ -796,4 +802,3 @@ require "appsignal/rack/generic_instrumentation"
|
|
796
802
|
require "appsignal/rack/js_exception_catcher"
|
797
803
|
require "appsignal/js_exception_transaction"
|
798
804
|
require "appsignal/transmitter"
|
799
|
-
require "appsignal/system"
|
data/lib/appsignal/cli.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require "optparse"
|
2
2
|
require "logger"
|
3
|
-
require "yaml"
|
4
3
|
require "appsignal"
|
5
4
|
require "appsignal/cli/helpers"
|
6
5
|
require "appsignal/cli/demo"
|
@@ -11,7 +10,7 @@ require "appsignal/cli/notify_of_deploy"
|
|
11
10
|
module Appsignal
|
12
11
|
# @api private
|
13
12
|
class CLI
|
14
|
-
AVAILABLE_COMMANDS = %w
|
13
|
+
AVAILABLE_COMMANDS = %w[demo diagnose install notify_of_deploy].freeze
|
15
14
|
|
16
15
|
class << self
|
17
16
|
attr_accessor :options
|
@@ -92,7 +92,7 @@ module Appsignal
|
|
92
92
|
puts "Installing for Sinatra"
|
93
93
|
config[:name] = required_input(" Enter application name: ")
|
94
94
|
puts
|
95
|
-
configure(config, %w
|
95
|
+
configure(config, %w[development production staging], true)
|
96
96
|
|
97
97
|
puts "Finish Sinatra configuration"
|
98
98
|
puts " Sinatra requires some manual configuration."
|
@@ -110,7 +110,7 @@ module Appsignal
|
|
110
110
|
puts "Installing for Padrino"
|
111
111
|
config[:name] = required_input(" Enter application name: ")
|
112
112
|
puts
|
113
|
-
configure(config, %w
|
113
|
+
configure(config, %w[development production staging], true)
|
114
114
|
|
115
115
|
puts "Finish Padrino installation"
|
116
116
|
puts " Padrino requires some manual configuration."
|
@@ -130,7 +130,7 @@ module Appsignal
|
|
130
130
|
config[:name] = required_input(" Enter application name: ")
|
131
131
|
puts
|
132
132
|
|
133
|
-
configure(config, %w
|
133
|
+
configure(config, %w[development production staging], true)
|
134
134
|
|
135
135
|
puts "Manual Grape configuration needed"
|
136
136
|
puts " See the installation instructions at:"
|
data/lib/appsignal/config.rb
CHANGED
@@ -63,6 +63,12 @@ module Appsignal
|
|
63
63
|
"APPSIGNAL_FILES_WORLD_ACCESSIBLE" => :files_world_accessible
|
64
64
|
}.freeze
|
65
65
|
|
66
|
+
# Mapping of old and deprecated AppSignal configuration keys
|
67
|
+
DEPRECATED_CONFIG_KEY_MAPPING = {
|
68
|
+
:api_key => :push_api_key,
|
69
|
+
:ignore_exceptions => :ignore_errors
|
70
|
+
}.freeze
|
71
|
+
|
66
72
|
attr_reader :root_path, :env, :initial_config, :config_hash
|
67
73
|
attr_accessor :logger
|
68
74
|
|
@@ -161,6 +167,26 @@ module Appsignal
|
|
161
167
|
ENV["_APPSIGNAL_FILES_WORLD_ACCESSIBLE"] = config_hash[:files_world_accessible].to_s
|
162
168
|
end
|
163
169
|
|
170
|
+
def validate
|
171
|
+
# Strip path from endpoint so we're backwards compatible with
|
172
|
+
# earlier versions of the gem.
|
173
|
+
# TODO: Move to its own method, maybe in `#[]=`?
|
174
|
+
endpoint_uri = URI(config_hash[:endpoint])
|
175
|
+
config_hash[:endpoint] =
|
176
|
+
if endpoint_uri.port == 443
|
177
|
+
"#{endpoint_uri.scheme}://#{endpoint_uri.host}"
|
178
|
+
else
|
179
|
+
"#{endpoint_uri.scheme}://#{endpoint_uri.host}:#{endpoint_uri.port}"
|
180
|
+
end
|
181
|
+
|
182
|
+
if config_hash[:push_api_key]
|
183
|
+
@valid = true
|
184
|
+
else
|
185
|
+
@valid = false
|
186
|
+
@logger.error "Push api key not set after loading config"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
164
190
|
private
|
165
191
|
|
166
192
|
def config_file
|
@@ -181,18 +207,12 @@ module Appsignal
|
|
181
207
|
configurations = YAML.load(ERB.new(IO.read(config_file)).result)
|
182
208
|
config_for_this_env = configurations[env]
|
183
209
|
if config_for_this_env
|
184
|
-
config_for_this_env =
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
if !config_for_this_env[:push_api_key] && config_for_this_env[:api_key]
|
191
|
-
config_for_this_env[:push_api_key] = config_for_this_env[:api_key]
|
192
|
-
end
|
193
|
-
if !config_for_this_env[:ignore_errors] && config_for_this_env[:ignore_exceptions]
|
194
|
-
config_for_this_env[:ignore_errors] = config_for_this_env[:ignore_exceptions]
|
195
|
-
end
|
210
|
+
config_for_this_env =
|
211
|
+
config_for_this_env.each_with_object({}) do |(key, value), hash|
|
212
|
+
hash[key.to_sym] = value # convert keys to symbols
|
213
|
+
end
|
214
|
+
|
215
|
+
config_for_this_env = maintain_backwards_compatibility(config_for_this_env)
|
196
216
|
|
197
217
|
merge(@config_hash, config_for_this_env)
|
198
218
|
else
|
@@ -200,35 +220,53 @@ module Appsignal
|
|
200
220
|
end
|
201
221
|
end
|
202
222
|
|
223
|
+
# Maintain backwards compatibility with config files generated by earlier
|
224
|
+
# versions of the gem
|
225
|
+
#
|
226
|
+
# Used by {#load_from_disk}. No compatibility for env variables or initial config currently.
|
227
|
+
def maintain_backwards_compatibility(configuration)
|
228
|
+
configuration.tap do |config|
|
229
|
+
DEPRECATED_CONFIG_KEY_MAPPING.each do |old_key, new_key|
|
230
|
+
old_config_value = config.delete(old_key)
|
231
|
+
next unless old_config_value
|
232
|
+
logger.warn "Old configuration key found. Please update the "\
|
233
|
+
"'#{old_key}' to '#{new_key}'."
|
234
|
+
|
235
|
+
next if config[new_key] # Skip if new key is already in use
|
236
|
+
config[new_key] = old_config_value
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
203
241
|
def load_from_environment
|
204
242
|
config = {}
|
205
243
|
|
206
244
|
# Configuration with string type
|
207
|
-
%w
|
245
|
+
%w[APPSIGNAL_PUSH_API_KEY APPSIGNAL_APP_NAME APPSIGNAL_PUSH_API_ENDPOINT
|
208
246
|
APPSIGNAL_FRONTEND_ERROR_CATCHING_PATH APPSIGNAL_HTTP_PROXY
|
209
247
|
APPSIGNAL_LOG APPSIGNAL_LOG_PATH APPSIGNAL_WORKING_DIR_PATH
|
210
|
-
APPSIGNAL_HOSTNAME APPSIGNAL_CA_FILE_PATH
|
248
|
+
APPSIGNAL_HOSTNAME APPSIGNAL_CA_FILE_PATH].each do |var|
|
211
249
|
env_var = ENV[var]
|
212
250
|
next unless env_var
|
213
251
|
config[ENV_TO_KEY_MAPPING[var]] = env_var
|
214
252
|
end
|
215
253
|
|
216
254
|
# Configuration with boolean type
|
217
|
-
%w
|
255
|
+
%w[APPSIGNAL_ACTIVE APPSIGNAL_DEBUG APPSIGNAL_INSTRUMENT_NET_HTTP
|
218
256
|
APPSIGNAL_INSTRUMENT_REDIS APPSIGNAL_INSTRUMENT_SEQUEL
|
219
257
|
APPSIGNAL_SKIP_SESSION_DATA APPSIGNAL_ENABLE_FRONTEND_ERROR_CATCHING
|
220
258
|
APPSIGNAL_ENABLE_ALLOCATION_TRACKING APPSIGNAL_ENABLE_GC_INSTRUMENTATION
|
221
259
|
APPSIGNAL_RUNNING_IN_CONTAINER APPSIGNAL_ENABLE_HOST_METRICS
|
222
260
|
APPSIGNAL_SEND_PARAMS APPSIGNAL_ENABLE_MINUTELY_PROBES
|
223
|
-
APPSIGNAL_FILES_WORLD_ACCESSIBLE
|
261
|
+
APPSIGNAL_FILES_WORLD_ACCESSIBLE].each do |var|
|
224
262
|
env_var = ENV[var]
|
225
263
|
next unless env_var
|
226
264
|
config[ENV_TO_KEY_MAPPING[var]] = env_var.casecmp("true").zero?
|
227
265
|
end
|
228
266
|
|
229
267
|
# Configuration with array of strings type
|
230
|
-
%w
|
231
|
-
APPSIGNAL_IGNORE_NAMESPACES APPSIGNAL_FILTER_PARAMETERS
|
268
|
+
%w[APPSIGNAL_IGNORE_ACTIONS APPSIGNAL_IGNORE_ERRORS
|
269
|
+
APPSIGNAL_IGNORE_NAMESPACES APPSIGNAL_FILTER_PARAMETERS].each do |var|
|
232
270
|
env_var = ENV[var]
|
233
271
|
next unless env_var
|
234
272
|
config[ENV_TO_KEY_MAPPING[var]] = env_var.split(",")
|
@@ -245,24 +283,5 @@ module Appsignal
|
|
245
283
|
original_config[key] = value
|
246
284
|
end
|
247
285
|
end
|
248
|
-
|
249
|
-
def validate
|
250
|
-
# Strip path from endpoint so we're backwards compatible with
|
251
|
-
# earlier versions of the gem.
|
252
|
-
endpoint_uri = URI(config_hash[:endpoint])
|
253
|
-
config_hash[:endpoint] =
|
254
|
-
if endpoint_uri.port == 443
|
255
|
-
"#{endpoint_uri.scheme}://#{endpoint_uri.host}"
|
256
|
-
else
|
257
|
-
"#{endpoint_uri.scheme}://#{endpoint_uri.host}:#{endpoint_uri.port}"
|
258
|
-
end
|
259
|
-
|
260
|
-
if config_hash[:push_api_key]
|
261
|
-
@valid = true
|
262
|
-
else
|
263
|
-
@valid = false
|
264
|
-
@logger.error "Push api key not set after loading config"
|
265
|
-
end
|
266
|
-
end
|
267
286
|
end
|
268
287
|
end
|
data/lib/appsignal/extension.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
require "yaml"
|
2
2
|
|
3
3
|
begin
|
4
|
-
|
5
|
-
|
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
|
6
11
|
rescue LoadError => err
|
7
12
|
Appsignal.logger.error(
|
8
13
|
"Failed to load extension (#{err}), please check the install.log file in " \
|
9
|
-
"the ext directory of the gem and
|
14
|
+
"the ext directory of the gem and email us at support@appsignal.com"
|
10
15
|
)
|
11
16
|
Appsignal.extension_loaded = false
|
12
17
|
end
|
@@ -25,11 +30,30 @@ module Appsignal
|
|
25
30
|
agent_config["version"]
|
26
31
|
end
|
27
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.
|
28
37
|
def method_missing(m, *args, &block)
|
29
|
-
|
38
|
+
super if Appsignal.testing?
|
30
39
|
end
|
31
40
|
end
|
32
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
|
+
|
33
57
|
class Data
|
34
58
|
def inspect
|
35
59
|
"#<#{self.class.name}:#{object_id} #{self}>"
|
@@ -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
|