stackify-ruby-apm 1.7.4 → 1.8.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 701a5bf72b0d237602bbb07c71923d404565da0161c71a36fd1886bfac0fddc9
4
- data.tar.gz: c91c611b46c3747bdf5f2e840a3c88cdd1562beb1a364cb1a80ba06c6d18ffc4
3
+ metadata.gz: 2a671e23d695c474d3aafa85df6756d98fa51610411f40e2c750a8e2e5ad2bb1
4
+ data.tar.gz: c34ada9683508fbf2345434260c616100a5394fc58c22c4ea5eeceb8e7be78fe
5
5
  SHA512:
6
- metadata.gz: 778c0414e397291ee79cfa4a570fa4a85db6f84db87f070591e53102d1b8be76ee46c871518c19fea615d21f9227c3e67b29dd2923468175d5b4a38579fea1e6
7
- data.tar.gz: 5576bd8a1932c69c0ee70e157d60ba59f4024ebc7230a941f31051c370d31b43203693171ef8f8bc0555cd0ba5d4ccb0161a55210c5ecd8004a7cb3a11e232f8
6
+ metadata.gz: 135db2d570f4d24b94ebd39f70909eb1ca21beb52052eaf25f1788d339039803f229ccdfaea00618386f6656378ae934e79f4a85d4c8eee059ff3941794b9c3f
7
+ data.tar.gz: b6d344829e9d14e8736bf3e0807fe2c9995d859a733fd1b79920196bc30df3afeac1c2374ad469e1a4bffe9428f43b258243af5138c61981e627ba14f37928f7
data/Gemfile CHANGED
@@ -9,13 +9,15 @@ group :test do
9
9
  gem 'activerecord'
10
10
  gem 'curb', '0.9.8'
11
11
  gem 'fakeredis'
12
+ gem 'google-protobuf', '3.5.0'
12
13
  gem 'http'
13
14
  gem 'httpclient'
14
15
  gem 'mongo'
15
16
  gem 'mysql2'
17
+ gem 'net_http_unix', '~> 0.2'
16
18
  gem 'pg', '~> 0.20'
17
19
  gem 'rack-test'
18
- gem 'rails'
20
+ gem 'rails', '~> 4.0'
19
21
  gem 'rubocop', require: false
20
22
  gem 'sequel'
21
23
  gem 'sinatra'
data/Gemfile.lock CHANGED
@@ -1,79 +1,82 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- stackify-ruby-apm (1.3.1)
4
+ stackify-ruby-apm (1.7.4)
5
5
  concurrent-ruby (~> 1.0)
6
6
  delegate_matcher (~> 0.4)
7
+ google-protobuf (= 3.5.0)
8
+ net_http_unix (~> 0.2)
7
9
  rufus-scheduler (~> 3.5)
8
10
 
9
11
  GEM
10
12
  remote: https://rubygems.org/
11
13
  specs:
12
- actionmailer (4.2.11)
13
- actionpack (= 4.2.11)
14
- actionview (= 4.2.11)
15
- activejob (= 4.2.11)
14
+ actionmailer (4.2.11.1)
15
+ actionpack (= 4.2.11.1)
16
+ actionview (= 4.2.11.1)
17
+ activejob (= 4.2.11.1)
16
18
  mail (~> 2.5, >= 2.5.4)
17
19
  rails-dom-testing (~> 1.0, >= 1.0.5)
18
- actionpack (4.2.11)
19
- actionview (= 4.2.11)
20
- activesupport (= 4.2.11)
20
+ actionpack (4.2.11.1)
21
+ actionview (= 4.2.11.1)
22
+ activesupport (= 4.2.11.1)
21
23
  rack (~> 1.6)
22
24
  rack-test (~> 0.6.2)
23
25
  rails-dom-testing (~> 1.0, >= 1.0.5)
24
26
  rails-html-sanitizer (~> 1.0, >= 1.0.2)
25
- actionview (4.2.11)
26
- activesupport (= 4.2.11)
27
+ actionview (4.2.11.1)
28
+ activesupport (= 4.2.11.1)
27
29
  builder (~> 3.1)
28
30
  erubis (~> 2.7.0)
29
31
  rails-dom-testing (~> 1.0, >= 1.0.5)
30
32
  rails-html-sanitizer (~> 1.0, >= 1.0.3)
31
- activejob (4.2.11)
32
- activesupport (= 4.2.11)
33
+ activejob (4.2.11.1)
34
+ activesupport (= 4.2.11.1)
33
35
  globalid (>= 0.3.0)
34
- activemodel (4.2.11)
35
- activesupport (= 4.2.11)
36
+ activemodel (4.2.11.1)
37
+ activesupport (= 4.2.11.1)
36
38
  builder (~> 3.1)
37
- activerecord (4.2.11)
38
- activemodel (= 4.2.11)
39
- activesupport (= 4.2.11)
39
+ activerecord (4.2.11.1)
40
+ activemodel (= 4.2.11.1)
41
+ activesupport (= 4.2.11.1)
40
42
  arel (~> 6.0)
41
- activesupport (4.2.11)
43
+ activesupport (4.2.11.1)
42
44
  i18n (~> 0.7)
43
45
  minitest (~> 5.1)
44
46
  thread_safe (~> 0.3, >= 0.3.4)
45
47
  tzinfo (~> 1.1)
46
- addressable (2.6.0)
47
- public_suffix (>= 2.0.2, < 4.0)
48
+ addressable (2.7.0)
49
+ public_suffix (>= 2.0.2, < 5.0)
48
50
  arel (6.0.4)
49
51
  ast (2.4.0)
50
- bson (4.4.2)
52
+ bson (4.5.0)
51
53
  builder (3.2.3)
52
- concurrent-ruby (1.1.4)
54
+ concurrent-ruby (1.1.5)
53
55
  crack (0.4.3)
54
56
  safe_yaml (~> 1.0.0)
55
- crass (1.0.4)
57
+ crass (1.0.5)
56
58
  curb (0.9.8)
57
59
  delegate_matcher (0.4.3)
58
60
  proc_extensions (~> 0.2)
59
61
  diff-lcs (1.3)
60
- domain_name (0.5.20180417)
62
+ domain_name (0.5.20190701)
61
63
  unf (>= 0.0.5, < 1.0.0)
62
64
  erubis (2.7.0)
63
- et-orbi (1.2.0)
65
+ et-orbi (1.2.2)
64
66
  tzinfo
65
67
  fakeredis (0.7.0)
66
68
  redis (>= 3.2, < 5.0)
67
- faraday (0.15.4)
69
+ faraday (0.17.1)
68
70
  multipart-post (>= 1.2, < 3)
69
71
  file-tail (1.2.0)
70
72
  tins (~> 1.0)
71
- fugit (1.2.0)
73
+ fugit (1.3.3)
72
74
  et-orbi (~> 1.1, >= 1.1.8)
73
75
  raabro (~> 1.1)
74
76
  globalid (0.4.2)
75
77
  activesupport (>= 4.2.0)
76
- hashdiff (0.3.8)
78
+ google-protobuf (3.5.0)
79
+ hashdiff (1.0.0)
77
80
  http (3.0.0)
78
81
  addressable (~> 2.3)
79
82
  http-cookie (~> 1.0)
@@ -86,28 +89,25 @@ GEM
86
89
  httpclient (2.8.3)
87
90
  i18n (0.9.5)
88
91
  concurrent-ruby (~> 1.0)
89
- loofah (2.2.3)
92
+ loofah (2.4.0)
90
93
  crass (~> 1.0.2)
91
94
  nokogiri (>= 1.5.9)
92
95
  mail (2.7.1)
93
96
  mini_mime (>= 0.1.1)
94
- mini_mime (1.0.1)
97
+ mini_mime (1.0.2)
95
98
  mini_portile2 (2.1.0)
96
- minitest (5.11.3)
97
- mongo (2.7.1)
99
+ minitest (5.12.0)
100
+ mongo (2.10.2)
98
101
  bson (>= 4.4.2, < 5.0.0)
99
- multipart-post (2.0.0)
100
- mysql2 (0.5.2)
101
- mysql2 (0.5.2-x64-mingw32)
102
+ multipart-post (2.1.1)
103
+ mysql2 (0.5.3)
104
+ net_http_unix (0.2.2)
102
105
  nokogiri (1.6.8.1)
103
106
  mini_portile2 (~> 2.1.0)
104
- nokogiri (1.6.8.1-x64-mingw32)
105
- mini_portile2 (~> 2.1.0)
106
107
  parallel (1.13.0)
107
- parser (2.6.0.0)
108
+ parser (2.6.5.0)
108
109
  ast (~> 2.4.0)
109
110
  pg (0.21.0)
110
- pg (0.21.0-x64-mingw32)
111
111
  powerpack (0.1.2)
112
112
  proc_extensions (0.2)
113
113
  sourcify (~> 0.5)
@@ -118,16 +118,16 @@ GEM
118
118
  rack
119
119
  rack-test (0.6.3)
120
120
  rack (>= 1.0)
121
- rails (4.2.11)
122
- actionmailer (= 4.2.11)
123
- actionpack (= 4.2.11)
124
- actionview (= 4.2.11)
125
- activejob (= 4.2.11)
126
- activemodel (= 4.2.11)
127
- activerecord (= 4.2.11)
128
- activesupport (= 4.2.11)
121
+ rails (4.2.11.1)
122
+ actionmailer (= 4.2.11.1)
123
+ actionpack (= 4.2.11.1)
124
+ actionview (= 4.2.11.1)
125
+ activejob (= 4.2.11.1)
126
+ activemodel (= 4.2.11.1)
127
+ activerecord (= 4.2.11.1)
128
+ activesupport (= 4.2.11.1)
129
129
  bundler (>= 1.3.0, < 2.0)
130
- railties (= 4.2.11)
130
+ railties (= 4.2.11.1)
131
131
  sprockets-rails
132
132
  rails-deprecated_sanitizer (1.0.3)
133
133
  activesupport (>= 4.2.0.alpha)
@@ -135,30 +135,30 @@ GEM
135
135
  activesupport (>= 4.2.0, < 5.0)
136
136
  nokogiri (~> 1.6)
137
137
  rails-deprecated_sanitizer (>= 1.0.1)
138
- rails-html-sanitizer (1.0.4)
139
- loofah (~> 2.2, >= 2.2.2)
140
- railties (4.2.11)
141
- actionpack (= 4.2.11)
142
- activesupport (= 4.2.11)
138
+ rails-html-sanitizer (1.3.0)
139
+ loofah (~> 2.3)
140
+ railties (4.2.11.1)
141
+ actionpack (= 4.2.11.1)
142
+ activesupport (= 4.2.11.1)
143
143
  rake (>= 0.8.7)
144
144
  thor (>= 0.18.1, < 2.0)
145
145
  rainbow (2.2.2)
146
146
  rake
147
147
  rake (10.5.0)
148
148
  redis (3.3.5)
149
- rspec (3.8.0)
150
- rspec-core (~> 3.8.0)
151
- rspec-expectations (~> 3.8.0)
152
- rspec-mocks (~> 3.8.0)
153
- rspec-core (3.8.0)
154
- rspec-support (~> 3.8.0)
155
- rspec-expectations (3.8.2)
149
+ rspec (3.9.0)
150
+ rspec-core (~> 3.9.0)
151
+ rspec-expectations (~> 3.9.0)
152
+ rspec-mocks (~> 3.9.0)
153
+ rspec-core (3.9.0)
154
+ rspec-support (~> 3.9.0)
155
+ rspec-expectations (3.9.0)
156
156
  diff-lcs (>= 1.2.0, < 2.0)
157
- rspec-support (~> 3.8.0)
158
- rspec-mocks (3.8.0)
157
+ rspec-support (~> 3.9.0)
158
+ rspec-mocks (3.9.0)
159
159
  diff-lcs (>= 1.2.0, < 2.0)
160
- rspec-support (~> 3.8.0)
161
- rspec-support (3.8.0)
160
+ rspec-support (~> 3.9.0)
161
+ rspec-support (3.9.0)
162
162
  rubocop (0.50.0)
163
163
  parallel (~> 1.10)
164
164
  parser (>= 2.3.3.1, < 3.0)
@@ -166,22 +166,22 @@ GEM
166
166
  rainbow (>= 2.2.2, < 3.0)
167
167
  ruby-progressbar (~> 1.7)
168
168
  unicode-display_width (~> 1.0, >= 1.0.1)
169
- ruby-progressbar (1.10.0)
170
- ruby2ruby (2.4.2)
169
+ ruby-progressbar (1.10.1)
170
+ ruby2ruby (2.4.4)
171
171
  ruby_parser (~> 3.1)
172
172
  sexp_processor (~> 4.6)
173
- ruby_parser (3.13.1)
173
+ ruby_parser (3.14.0)
174
174
  sexp_processor (~> 4.9)
175
175
  rufus-scheduler (3.6.0)
176
176
  fugit (~> 1.1, >= 1.1.6)
177
177
  safe_yaml (1.0.5)
178
- sequel (5.18.0)
179
- sexp_processor (4.12.0)
178
+ sequel (5.27.0)
179
+ sexp_processor (4.13.0)
180
180
  sinatra (1.4.8)
181
181
  rack (~> 1.5)
182
182
  rack-protection (~> 1.4)
183
183
  tilt (>= 1.3, < 3)
184
- sinatra-activerecord (2.0.13)
184
+ sinatra-activerecord (2.0.14)
185
185
  activerecord (>= 3.2)
186
186
  sinatra (>= 1.0)
187
187
  sourcify (0.5.0)
@@ -197,43 +197,44 @@ GEM
197
197
  activesupport (>= 4.0)
198
198
  sprockets (>= 3.0.0)
199
199
  sqlite3 (1.3.13)
200
- sqlite3 (1.3.13-x64-mingw32)
201
- stackify-api-ruby (1.0.13)
200
+ stackify-api-ruby (1.1.0)
202
201
  faraday (~> 0.8)
202
+ google-protobuf (~> 3.0)
203
+ net_http_unix (~> 0.2)
203
204
  thor (0.20.3)
204
205
  thread_safe (0.3.6)
205
- tilt (2.0.9)
206
+ tilt (2.0.10)
206
207
  timecop (0.9.1)
207
- tins (1.20.2)
208
- to_bool (1.2.0)
208
+ tins (1.22.2)
209
+ to_bool (2.0.0)
209
210
  tzinfo (1.2.5)
210
211
  thread_safe (~> 0.1)
211
212
  unf (0.1.4)
212
213
  unf_ext
213
- unf_ext (0.0.7.5)
214
- unf_ext (0.0.7.5-x64-mingw32)
215
- unicode-display_width (1.5.0)
216
- webmock (3.5.1)
214
+ unf_ext (0.0.7.6)
215
+ unicode-display_width (1.6.0)
216
+ webmock (3.7.6)
217
217
  addressable (>= 2.3.6)
218
218
  crack (>= 0.3.2)
219
- hashdiff
219
+ hashdiff (>= 0.4.0, < 2.0.0)
220
220
 
221
221
  PLATFORMS
222
222
  ruby
223
- x64-mingw32
224
223
 
225
224
  DEPENDENCIES
226
225
  activerecord
227
226
  bundler (~> 1.16)
228
227
  curb (= 0.9.8)
229
228
  fakeredis
229
+ google-protobuf (= 3.5.0)
230
230
  http
231
231
  httpclient
232
232
  mongo
233
233
  mysql2
234
+ net_http_unix (~> 0.2)
234
235
  pg (~> 0.20)
235
236
  rack-test
236
- rails
237
+ rails (~> 4.0)
237
238
  rake (~> 10.0)
238
239
  rspec (~> 3.0)
239
240
  rubocop
@@ -0,0 +1,39 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # source: stackify-trace.proto
3
+
4
+ require 'google/protobuf'
5
+
6
+ Google::Protobuf::DescriptorPool.generated_pool.build do
7
+ add_message 'stackify.Traces' do
8
+ repeated :traces, :message, 1, 'stackify.Trace'
9
+ end
10
+ add_message 'stackify.Trace' do
11
+ optional :frame, :message, 1, 'stackify.TraceFrame'
12
+ end
13
+ add_message 'stackify.TraceFrame' do
14
+ optional :call, :string, 1
15
+ optional :start_timestamp_millis, :double, 2
16
+ optional :end_timestamp_millis, :double, 3
17
+ map :properties, :string, :string, 4
18
+ repeated :frames, :message, 5, 'stackify.TraceFrame'
19
+ repeated :exceptions, :message, 6, 'stackify.TraceException'
20
+ end
21
+ add_message 'stackify.TraceException' do
22
+ optional :caught_by, :string, 1
23
+ optional :exception, :string, 2
24
+ optional :message, :string, 3
25
+ optional :timestamp_millis, :double, 4
26
+ repeated :frames, :message, 5, 'stackify.TraceExceptionFrame'
27
+ end
28
+ add_message 'stackify.TraceExceptionFrame' do
29
+ optional :method, :string, 1
30
+ end
31
+ end
32
+
33
+ module StackifyProtoBuf
34
+ Traces = Google::Protobuf::DescriptorPool.generated_pool.lookup('stackify.Traces').msgclass
35
+ Trace = Google::Protobuf::DescriptorPool.generated_pool.lookup('stackify.Trace').msgclass
36
+ TraceFrame = Google::Protobuf::DescriptorPool.generated_pool.lookup('stackify.TraceFrame').msgclass
37
+ TraceException = Google::Protobuf::DescriptorPool.generated_pool.lookup('stackify.TraceException').msgclass
38
+ TraceExceptionFrame = Google::Protobuf::DescriptorPool.generated_pool.lookup('stackify.TraceExceptionFrame').msgclass
39
+ end
@@ -25,21 +25,26 @@ module StackifyRubyAPM
25
25
  @instance
26
26
  end
27
27
 
28
+ # rubocop:disable Metrics/PerceivedComplexity
28
29
  # rubocop:disable Metrics/CyclomaticComplexity
29
30
  def self.start(config)
30
31
  return @instance if @instance
31
32
 
32
33
  config = Config.new(config) unless config.is_a?(Config)
33
- pid = $PID || Process.pid
34
- host_name = config.hostname || `hostname`
35
- date_now = Time.now
36
- current_trace_file = config.log_trace_path + squish(host_name) + '#' + squish(pid.to_s)
37
-
38
- if ENV['STACKIFY_RUBY_ENV'] != 'rspec'
39
- config.tracer_logger = StackifyLogger.new(current_trace_file, config.filenum_rotate, config.logger_byte_size)
40
- config.debug_logger
41
- config.logtime_created = date_now.strftime('%H:%M')
42
- Util::TraceLogWatcher.delete_trace_logs(config)
34
+ case config.transport.downcase
35
+ # For unix socket we don't create a trace log file
36
+ when StackifyRubyAPM::TRACE_LOG
37
+ # For Default transport let's create initial trace log file
38
+ pid = $PID || Process.pid
39
+ host_name = (config.hostname || `hostname`).strip
40
+ date_now = Time.now
41
+ current_trace_file = config.log_trace_path + squish(host_name) + '#' + squish(pid.to_s)
42
+ if ENV['STACKIFY_RUBY_ENV'] != 'rspec'
43
+ config.tracer_logger = StackifyLogger.new(current_trace_file, config.filenum_rotate, config.logger_byte_size)
44
+ config.debug_logger
45
+ config.logtime_created = date_now.strftime('%H:%M')
46
+ Util::TraceLogWatcher.delete_trace_logs(config)
47
+ end
43
48
  end
44
49
 
45
50
  LOCK.synchronize do
@@ -49,6 +54,7 @@ module StackifyRubyAPM
49
54
  end
50
55
  end
51
56
  # rubocop:enable Metrics/CyclomaticComplexity
57
+ # rubocop:enable Metrics/PerceivedComplexity
52
58
 
53
59
  def self.stop
54
60
  LOCK.synchronize do
@@ -93,6 +99,7 @@ module StackifyRubyAPM
93
99
 
94
100
  def start
95
101
  info '[Agent] start()'
102
+ info '[Agent] transport type: ' + @config.transport
96
103
  spies_name = ''
97
104
  # If the rake task is detected as being ran then we don't load the spies
98
105
  StackifyRubyAPM::Util.apm_disabled_in_rake
@@ -103,7 +110,7 @@ module StackifyRubyAPM
103
110
  require "stackify_apm/spies/#{lib}"
104
111
  end
105
112
 
106
- debug '[Agent] Loaded spies: ' + spies_name if ENV['STACKIFY_APM_LOG_LEVEL'] == '0'
113
+ debug '[Agent] Loaded spies: ' + spies_name if ENV['STACKIFY_TRANSPORT_LOG_LEVEL'] == '0'
107
114
  self
108
115
  end
109
116
 
@@ -119,7 +126,7 @@ module StackifyRubyAPM
119
126
  end
120
127
 
121
128
  def should_flush_transactions?
122
- return true unless config.flush_interval
129
+ return true unless config.flush_interval_seconds
123
130
  return true if pending_transactions.length >= config.max_queue_size
124
131
 
125
132
  false
@@ -188,7 +195,7 @@ module StackifyRubyAPM
188
195
  private
189
196
 
190
197
  def boot_worker
191
- debug '[Agent] Booting worker' if ENV['STACKIFY_APM_LOG_LEVEL'] == '0'
198
+ debug '[Agent] Booting worker' if ENV['STACKIFY_TRANSPORT_LOG_LEVEL'] == '0'
192
199
 
193
200
  @worker_thread = Thread.new do
194
201
  Worker.new(
@@ -8,6 +8,8 @@ require 'logger'
8
8
  require 'yaml'
9
9
  require 'socket'
10
10
  module StackifyRubyAPM
11
+ TRANSPORT = [TRACE_LOG = 'default'.freeze, UNIX_SOCKET = 'agent_socket'.freeze, AGENT_HTTP = 'agent_http'.freeze].freeze
12
+
11
13
  # @api private
12
14
  class Config
13
15
  include Log
@@ -22,6 +24,7 @@ module StackifyRubyAPM
22
24
  rum_enabled: false,
23
25
  rum_cookie_path: '/',
24
26
  rum_cookie_name: '.Stackify.Rum',
27
+ transport: StackifyRubyAPM::TRACE_LOG,
25
28
  instrument: true,
26
29
  debug_logging: false,
27
30
  log_path: StackifyRubyAPM::Util.host_os == 'WINDOWS' ? 'C:\ProgramData\Stackify\Ruby\log\stackify-ruby-apm-1.log' : '/usr/local/stackify/stackify-ruby-apm/log/stackify-ruby-apm-1.log',
@@ -29,14 +32,16 @@ module StackifyRubyAPM
29
32
  log_trace_path: StackifyRubyAPM::Util.host_os == 'WINDOWS' ? 'C:\ProgramData\Stackify\Ruby\log\\' : '/usr/local/stackify/stackify-ruby-apm/log/',
30
33
 
31
34
  max_queue_size: 500, # Maximum queue length of transactions before sending transactions to the APM.
32
- flush_interval: 1, # interval with which transactions should be sent to the APM. Default value: 10 seconds
35
+ flush_interval_seconds: 1, # interval with which transactions should be sent to the APM. Default value: 1 seconds
36
+ delay_seconds: 10, # Interval in seconds between tries
37
+ max_retries: 3, # Number of attempts
33
38
 
34
39
  filter_exception_types: [],
35
40
 
36
41
  tracer_logger: nil,
37
42
  logger_byte_size: 50_000_000, # e.g, 50_000_000=50mb
38
43
  filenum_rotate: 20,
39
- debugger_byte_size: 20_000_000,
44
+ debugger_byte_size: 20_000_000, # e.g, 20_000_000=20mb
40
45
  debugger_filenum_rotate: 3,
41
46
  logtime_created: 0,
42
47
  http_status: nil,
@@ -54,29 +59,35 @@ module StackifyRubyAPM
54
59
 
55
60
  view_paths: [],
56
61
  root_path: Dir.pwd,
57
- stackify_properties_file: '/usr/local/stackify/stackify-ruby-apm/stackify.properties'
62
+ stackify_properties_file: '/usr/local/stackify/stackify-ruby-apm/stackify.properties',
63
+ agent_traces_url: '/traces',
64
+ unix_socket_path: '/usr/local/stackify/stackify.sock',
65
+ transport_http_endpoint: 'https://localhost:10601'
58
66
  }.freeze
59
67
 
60
68
  ENV_TO_KEY = {
61
- 'STACKIFY_APM_ENVIRONMENT_NAME' => 'environment_name',
62
- 'STACKIFY_APM_RUM_SCRIPT_SRC' => 'rum_script_src',
63
- 'STACKIFY_APM_RUM_AUTO_INJECTION' => 'rum_auto_injection',
64
- 'STACKIFY_APM_RUM_ENABLED' => 'rum_enabled',
69
+ 'STACKIFY_DEBUG' => [:bool, 'debug_logging'],
70
+ 'STACKIFY_APPLICATION_NAME' => 'application_name',
71
+ 'STACKIFY_ENVIRONMENT_NAME' => 'environment_name',
72
+ 'STACKIFY_RUM' => [:bool, 'rum_enabled'],
73
+ 'STACKIFY_RUM_AUTO_INJECT' => [:bool, 'rum_auto_injection'],
74
+ 'STACKIFY_RUM_SCRIPT_SRC' => 'rum_script_src',
75
+ 'STACKIFY_TRANSPORT' => 'transport',
76
+ 'STACKIFY_TRANSPORT_LOG_PATH' => 'log_path',
77
+ 'STACKIFY_TRANSPORT_LOG_LEVEL' => [:int, 'log_level'],
78
+ 'STACKIFY_TRANSPORT_SOCKET_PATH' => 'unix_socket_path',
79
+ 'STACKIFY_TRANSPORT_HTTP_ENDPOINT' => 'transport_http_endpoint',
65
80
  'STACKIFY_ALREADY_INSTRUMENTED_FLAG' => 'already_instrumented_flag',
66
- 'STACKIFY_APM_DEBUG_LOGGING' => 'debug_logging',
67
- 'STACKIFY_APM_INSTRUMENT' => [:bool, 'instrument'],
68
- 'STACKIFY_APM_HOSTNAME' => 'hostname',
69
- 'STACKIFY_APM_LOG_PATH' => 'log_path',
70
- 'STACKIFY_APM_LOG_LEVEL' => [:int, 'log_level'],
71
- 'STACKIFY_APM_APPLICATION_NAME' => 'application_name',
72
- 'STACKIFY_APM_SOURCE_LINES_ERROR_APP_FRAMES' => [:int, 'source_lines_error_app_frames'],
73
- 'STACKIFY_APM_SOURCE_LINES_SPAN_APP_FRAMES' => [:int, 'source_lines_span_app_frames'],
74
- 'STACKIFY_APM_SOURCE_LINES_ERROR_LIBRARY_FRAMES' => [:int, 'source_lines_error_library_frames'],
75
- 'STACKIFY_APM_SOURCE_LINES_SPAN_LIBRARY_FRAMES' => [:int, 'source_lines_span_library_frames'],
76
- 'STACKIFY_APM_SPAN_FRAMES_MIN_DURATION' => [:int, 'span_frames_min_duration'],
77
- 'STACKIFY_APM_MAX_QUEUE_SIZE' => [:int, 'max_queue_size'],
78
- 'STACKIFY_APM_FLUSH_INTERVAL' => 'flush_interval',
79
- 'STACKIFY_APM_DISABLED_SPIES' => [:list, 'disabled_spies']
81
+ 'STACKIFY_INSTRUMENT' => [:bool, 'instrument'],
82
+ 'STACKIFY_HOSTNAME' => 'hostname',
83
+ 'STACKIFY_SOURCE_LINES_ERROR_APP_FRAMES' => [:int, 'source_lines_error_app_frames'],
84
+ 'STACKIFY_SOURCE_LINES_SPAN_APP_FRAMES' => [:int, 'source_lines_span_app_frames'],
85
+ 'STACKIFY_SOURCE_LINES_ERROR_LIBRARY_FRAMES' => [:int, 'source_lines_error_library_frames'],
86
+ 'STACKIFY_SOURCE_LINES_SPAN_LIBRARY_FRAMES' => [:int, 'source_lines_span_library_frames'],
87
+ 'STACKIFY_SPAN_FRAMES_MIN_DURATION' => [:int, 'span_frames_min_duration'],
88
+ 'STACKIFY_MAX_QUEUE_SIZE' => [:int, 'max_queue_size'],
89
+ 'STACKIFY_FLUSH_INTERVAL' => 'flush_interval_seconds',
90
+ 'STACKIFY_DISABLED_SPIES' => [:list, 'disabled_spies']
80
91
  }.freeze
81
92
 
82
93
  def initialize(options = {})
@@ -86,7 +97,7 @@ module StackifyRubyAPM
86
97
  set_from_env
87
98
  yield self if block_given?
88
99
  debug_logger
89
- StackifyRubyAPM::Util.host_os == 'WINDOWS' ? load_stackify_props_windows : load_stackify_props
100
+ StackifyRubyAPM::Util.host_os == 'WINDOWS' ? load_stackify_props_windows : load_stackify_props_linux
90
101
  validate_apm_yml
91
102
  end
92
103
 
@@ -103,6 +114,10 @@ module StackifyRubyAPM
103
114
  attr_accessor :instrument
104
115
  attr_accessor :enabled_environments
105
116
  attr_accessor :stackify_properties_file
117
+ attr_accessor :transport
118
+ attr_accessor :agent_traces_url
119
+ attr_accessor :unix_socket_path
120
+ attr_accessor :transport_http_endpoint
106
121
 
107
122
  attr_accessor :application_name
108
123
  attr_accessor :hostname
@@ -129,7 +144,9 @@ module StackifyRubyAPM
129
144
  attr_accessor :span_frames_min_duration
130
145
 
131
146
  attr_accessor :max_queue_size
132
- attr_accessor :flush_interval
147
+ attr_accessor :flush_interval_seconds
148
+ attr_accessor :delay_seconds
149
+ attr_accessor :max_retries
133
150
 
134
151
  attr_accessor :filter_exception_types
135
152
 
@@ -258,7 +275,7 @@ module StackifyRubyAPM
258
275
 
259
276
  # rubocop:disable Naming/AccessorMethodName
260
277
  def set_rails(app)
261
- self.application_name ||= format_name(application_name || app.class.parent_name)
278
+ self.application_name ||= format_name(application_name || app.class.parent_name).strip
262
279
  self.logger ||= Rails.logger
263
280
 
264
281
  self.root_path = Rails.root.to_s
@@ -278,7 +295,7 @@ module StackifyRubyAPM
278
295
  end
279
296
 
280
297
  # rubocop:disable Metrics/CyclomaticComplexity
281
- def load_stackify_props
298
+ def load_stackify_props_linux
282
299
  @client_id = nil
283
300
  @device_id = nil
284
301
  @client_run_domain = nil
@@ -341,6 +358,8 @@ module StackifyRubyAPM
341
358
  info '[Config] rum_auto_injection must be Boolean type: true/false.' unless [TrueClass, FalseClass].include?(@rum_auto_injection.class) && defined?(@rum_auto_injection)
342
359
  info '[Config] application_name must be String type.' unless @application_name.is_a?(String) && defined?(@application_name)
343
360
  info '[Config] environment_name must be String type.' unless @environment_name.is_a?(String) && defined?(@environment_name)
361
+ info '[Config] transport must be String type.' unless @transport.is_a?(String) && defined?(@transport)
362
+ info '[Config] Transport should be one of these values: [agent_socket, default, agent_http]. Should be a String.' if defined?(@transport) && !%w[agent_socket default agent_http].include?(@transport.downcase)
344
363
  end
345
364
  # rubocop:enable Metrics/CyclomaticComplexity
346
365
  # rubocop:enable Metrics/PerceivedComplexity
@@ -27,7 +27,7 @@ module StackifyRubyAPM
27
27
  end
28
28
 
29
29
  def initialize(agent)
30
- debug '[Instrumenter] initialize()' if ENV['STACKIFY_APM_LOG_LEVEL'] == '0'
30
+ debug '[Instrumenter] initialize()' if ENV['STACKIFY_TRANSPORT_LOG_LEVEL'] == '0'
31
31
  @agent = agent
32
32
  @config = agent.config
33
33
 
@@ -95,8 +95,7 @@ module StackifyRubyAPM
95
95
  # Once the transaction is submitted it will be stored temporarily in queue
96
96
  #
97
97
  def submit_transaction(transaction)
98
- debug '[Instrumenter] submit_transaction(transaction)' if ENV['STACKIFY_APM_LOG_LEVEL'] == '0'
99
- debug '[Instrumenter] submit_transaction(transaction) transaction: ' + transaction.inspect.to_s if ENV['STACKIFY_APM_LOG_LEVEL'] == '0'
98
+ debug '[Instrumenter] submit_transaction(transaction) transaction: ' + transaction.inspect.to_s if ENV['STACKIFY_TRANSPORT_LOG_LEVEL'] == '0'
100
99
  agent.enqueue_transaction transaction
101
100
  return unless config.debug_transactions
102
101
  end
@@ -14,7 +14,7 @@
14
14
  # -> SUBMITS transaction: stackify_apm/transaction.rb (#submit)
15
15
  # -> instrumenter submits transaction
16
16
  # -> worker will run (if != running), responsible for sending transactions to APM
17
- # for every 10 secs (based on config.flush_interval)
17
+ # for every 1 secs (based on config.flush_interval_seconds)
18
18
  # -> transaction will be stored in queue by Agent
19
19
  # -> worker will constantly execute transaction sending to APM
20
20
  #
@@ -46,21 +46,23 @@ module StackifyRubyAPM
46
46
  @rack_headers = resp[1]
47
47
  @rack_body = resp[2]
48
48
  @configuration = config
49
- response_manupulate = StackifyRubyAPM::ResponseManipulator.new(env, resp, @configuration)
50
49
 
51
50
  if okay_to_modify?
52
51
  @configuration.already_instrumented_flag = true
53
- if @configuration.rum_auto_injection.is_a?(TrueClass)
54
- response_string = response_manupulate.adjust_pagehtml_response
55
- end
56
- if response_string
57
- response = Rack::Response.new(response_string, @rack_status, @rack_headers)
58
- response.set_cookie(@configuration.rum_cookie_name, value: transaction.id, path: @configuration.rum_cookie_path) if @configuration.rum_enabled.is_a?(TrueClass)
59
- resp = response.finish
60
- elsif @configuration.rum_enabled.is_a?(TrueClass)
52
+ if @configuration.rum_enabled.is_a?(TrueClass)
61
53
  response = Rack::Response.new @rack_body, @rack_status, @rack_headers
62
54
  response.set_cookie(@configuration.rum_cookie_name, value: transaction.id, path: @configuration.rum_cookie_path)
63
55
  resp = response.finish
56
+ end
57
+ if @configuration.rum_auto_injection.is_a?(TrueClass)
58
+ response_manupulate = StackifyRubyAPM::ResponseManipulator.new(env, resp, @configuration)
59
+ response_string = response_manupulate.adjust_pagehtml_response
60
+ if response_string
61
+ response = Rack::Response.new(response_string, resp[0].to_i, resp[1])
62
+ resp = response.finish
63
+ else
64
+ resp
65
+ end
64
66
  else
65
67
  resp
66
68
  end
@@ -62,25 +62,13 @@ module StackifyRubyAPM
62
62
  end
63
63
 
64
64
  return unless inject_flag
65
- jsfile_to_inject = StackifyRubyAPM.inject_rum_script
66
65
 
67
66
  # Only scan the first 50k (roughly) then give up.
68
- beginning_of_source = source[0..SCAN_LIMIT]
69
-
70
- meta_tag_positions = [
71
- find_x_ua_compatible_position(beginning_of_source),
72
- find_charset_position(beginning_of_source)
73
- ].compact
74
-
75
- insertion_index = if !meta_tag_positions.empty?
76
- meta_tag_positions.max
77
- else
78
- find_end_of_head_open(beginning_of_source)
79
- end
67
+ insertion_index = find_end_of_head_open(source[0..SCAN_LIMIT])
80
68
 
81
69
  if insertion_index && inject_flag
82
70
  source = source[0...insertion_index] <<
83
- jsfile_to_inject <<
71
+ StackifyRubyAPM.inject_rum_script <<
84
72
  source[insertion_index..-1]
85
73
  end
86
74
  source
@@ -93,21 +81,6 @@ module StackifyRubyAPM
93
81
  beginning_of_source.index(GT, head_open) - 6 if head_open
94
82
  end
95
83
 
96
- def find_rum_script_variable_index(beginning_of_source)
97
- head_open = beginning_of_source.index(RUM_SCRIPT_VARIABLE)
98
- beginning_of_source.index(BRKT, head_open) - 20 if head_open
99
- end
100
-
101
- def find_x_ua_compatible_position(beginning_of_source)
102
- match = X_UA_COMPATIBLE_RE.match(beginning_of_source)
103
- match.end(0) if match
104
- end
105
-
106
- def find_charset_position(beginning_of_source)
107
- match = CHARSET_RE.match(beginning_of_source)
108
- match.end(0) if match
109
- end
110
-
111
84
  def gather_source(response)
112
85
  source = nil
113
86
  response.each { |fragment| source ? (source << fragment.to_s) : (source = fragment.to_s) }
@@ -19,14 +19,14 @@ module StackifyRubyAPM
19
19
  CATEGORY: 'Ruby',
20
20
  APPLICATION_PATH: '/',
21
21
  APPLICATION_FILESYSTEM_PATH: @config.root_path,
22
- APPLICATION_NAME: @config.application_name,
22
+ APPLICATION_NAME: @config.application_name.strip,
23
23
  APPLICATION_ENV: @config.environment_name || 'Development',
24
24
  REPORTING_URL: @transaction.name,
25
25
  TRACE_ID: @transaction.id,
26
26
  THREAD_ID: Thread.current.object_id,
27
27
  TRACE_SOURCE: 'RUBY',
28
28
  TRACE_TARGET: 'RETRACE',
29
- HOST_NAME: @config.hostname || `hostname`,
29
+ HOST_NAME: (@config.hostname || `hostname`).strip,
30
30
  OS_TYPE: StackifyRubyAPM::Util.host_os,
31
31
  PROCESS_ID: pid,
32
32
  TRACE_VERSION: '2.0',
@@ -8,7 +8,9 @@ module StackifyRubyAPM
8
8
  class Transactions < Serializer
9
9
  include Log
10
10
 
11
- def build(config, transaction)
11
+ # This method will return a Hash object(Transaction).
12
+ # It will accept Config and Transaction instance.
13
+ def build_json(config, transaction)
12
14
  root_span_json = {
13
15
  id: -1,
14
16
  call: transaction.name,
@@ -27,10 +29,78 @@ module StackifyRubyAPM
27
29
 
28
30
  add_children_spans(root_span_json, children_spans_json)
29
31
  root_span_json
32
+ rescue StandardError => e
33
+ debug "[Transactions::Serializer] build_json() exception: #{e.inspect}"
34
+ end
35
+
36
+ # This method will build a Protobuf object.
37
+ # It will accept the Config and Transaction instance.
38
+ # Return a Stackify::Trace object.
39
+ def build_protobuf(config, transaction)
40
+ root_span_hash = build_json(config, transaction)
41
+ begin
42
+ # create Trace object
43
+ trace = StackifyProtoBuf::Trace.new
44
+ # create TraceFrame object
45
+ trace_frame = StackifyProtoBuf::TraceFrame.new
46
+ trace_frame.call = root_span_hash[:call].to_s
47
+ trace_frame.start_timestamp_millis = root_span_hash[:reqBegin]
48
+ trace_frame.end_timestamp_millis = root_span_hash[:reqEnd]
49
+
50
+ exception = StackifyProtoBuf::TraceException.new
51
+ if root_span_hash[:exceptions].count > 0
52
+ ex = root_span_hash[:exceptions]
53
+ ex.each do |exc|
54
+ exception.caught_by = exc[:CaughtBy].to_s
55
+ exception.exception = exc[:Exception].to_s
56
+ exception.message = exc[:Message].to_s
57
+ exception.timestamp_millis = exc[:Timestamp].to_f
58
+ exc[:Frames].each do |f|
59
+ trace_ex_frame = StackifyProtoBuf::TraceExceptionFrame.new
60
+ trace_ex_frame.method = f[:Method].to_s
61
+ exception.frames.push(trace_ex_frame)
62
+ end
63
+ trace_frame.exceptions.push(exception)
64
+ end
65
+ end
66
+
67
+ # create props
68
+ root_frame_props = Google::Protobuf::Map.new(:string, :string)
69
+ root_span_hash[:props].each { |key, value| root_frame_props[key.to_s] = value.to_s }
70
+ trace_frame.properties = root_frame_props
71
+
72
+ add_child_frame trace_frame, root_span_hash
73
+ trace.frame = trace_frame
74
+ return trace
75
+ rescue StandardError => e
76
+ debug "[Serializers::Transactions] build_protobuf() exception: #{e.inspect}"
77
+ end
30
78
  end
31
79
 
32
80
  private
33
81
 
82
+ # It accept StackifyProtoBuf::TraceFrame instance and Root span hash
83
+ # It will create a parent-child structure if there is :stacks found in the current level
84
+ def add_child_frame(trace_frame, root_span_hash)
85
+ root_span_hash[:stacks].each do |span|
86
+ child_frame = StackifyProtoBuf::TraceFrame.new
87
+ child_frame.call = span[:call].to_s
88
+ child_frame.start_timestamp_millis = span[:reqBegin]
89
+ child_frame.end_timestamp_millis = span[:reqEnd]
90
+
91
+ map_props = Google::Protobuf::Map.new(:string, :string)
92
+ span[:props].each { |key, value| map_props[key.to_s] = value.to_s }
93
+ child_frame.properties = map_props
94
+
95
+ trace_frame.frames.push(child_frame)
96
+ if span[:stacks] && span[:stacks].count > 0
97
+ add_child_frame child_frame, span
98
+ end
99
+ end
100
+ rescue StandardError => e
101
+ debug "[Serializers::Transactions] add_child_frame() exception: #{e.inspect}"
102
+ end
103
+
34
104
  # Add Children Spans to span_json
35
105
  def add_children_spans(span_json, children_spans_json)
36
106
  id = span_json[:id]
@@ -5,7 +5,7 @@ module StackifyRubyAPM
5
5
  module Spies
6
6
  # @api private
7
7
  class StackifyLoggerSpy
8
- if defined? Stackify
8
+ if defined?(Stackify) && defined?(::Stackify::LoggerClient)
9
9
  ::Stackify::LoggerClient.class_eval do
10
10
  require 'securerandom'
11
11
  alias_method 'log_message_task_without_apm', 'log_message_task'
@@ -12,7 +12,7 @@ module StackifyRubyAPM
12
12
  include Log
13
13
 
14
14
  def initialize(agent)
15
- debug '[Subscriber] initialize(agent)' if ENV['STACKIFY_APM_LOG_LEVEL'] == '0'
15
+ debug '[Subscriber] initialize(agent)' if ENV['STACKIFY_TRANSPORT_LOG_LEVEL'] == '0'
16
16
  @agent = agent
17
17
  @normalizers = Normalizers.build(agent.config)
18
18
  end
@@ -13,30 +13,19 @@ module StackifyRubyAPM
13
13
  def initialize(config)
14
14
  @config = config
15
15
  @trace_file_counter = 0
16
- @transaction_serializers = Serializers::Transactions.new(config)
16
+ begin
17
+ @transaction_serializers = Serializers::Transactions.new(config)
18
+ @transport = StackifyRubyAPM::TransportSelector.new(@config).transport
19
+ rescue StandardError => exception
20
+ debug '[TraceLogger] initialize()' if ENV['STACKIFY_TRANSPORT_LOG_LEVEL'] == '0'
21
+ debug exception.inspect
22
+ end
17
23
  end
18
24
 
19
25
  attr_accessor :trace_file_counter
20
26
 
21
27
  def post(transactions = [])
22
- debug '[TraceLogger] post()' if ENV['STACKIFY_APM_LOG_LEVEL'] == '0'
23
- # convert transactions to json
24
- json_traces = []
25
- transactions.each do |transaction|
26
- # convert transaction to json
27
- json_transaction = @transaction_serializers.build(@config, transaction).to_json
28
-
29
- # add to json traces array
30
- json_traces.push(json_transaction)
31
- end
32
-
33
- current_datetime = Time.now.utc.strftime('%Y-%m-%d, %H:%M:%S.%6N')
34
-
35
- return unless ENV['STACKIFY_RUBY_ENV'] != 'rspec'
36
-
37
- json_traces.each do |json_trace|
38
- @config.tracer_logger.<<("#{current_datetime} > #{json_trace} \n")
39
- end
28
+ @transport.post(transactions)
40
29
  end
41
30
  end
42
31
  end
@@ -0,0 +1,35 @@
1
+ require 'stackify_apm/root_info'
2
+ require 'stackify_apm/serializers'
3
+
4
+ module StackifyRubyAPM
5
+ # This class will take care of building a protobuf message.
6
+ # @api private
7
+ class AgentBaseTransport
8
+ include Log
9
+
10
+ def initialize(config)
11
+ @config = config
12
+ @transaction_serializers = Serializers::Transactions.new(config)
13
+ end
14
+
15
+ # This method will build a group of Stackify::Traces from the protobuf objects.
16
+ # It accept Array of transactions.
17
+ def build_message(transactions = [])
18
+ # convert transactions to protobuf
19
+ traces = StackifyProtoBuf::Traces.new
20
+ transactions.each do |transaction|
21
+ # convert transaction to protobuf
22
+ protobuf_transaction = @transaction_serializers.build_protobuf(@config, transaction)
23
+ # add to traces array
24
+ traces.traces.push(protobuf_transaction)
25
+ end
26
+ return traces
27
+ rescue StandardError => e
28
+ debug "[AgentBaseTransport] build_message() exception: #{e.inspect}"
29
+ end
30
+
31
+ def post(_transactions = [])
32
+ raise NotImplementedError
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+ require 'faraday'
5
+ require 'ostruct'
6
+
7
+ module StackifyRubyAPM
8
+ # This class will handle the sending of protobuf messages through HTTP.
9
+ # @api private
10
+ class AgentHTTPClient < AgentBaseTransport
11
+ include Log
12
+
13
+ HEADERS = {
14
+ 'Content-Type' => 'application/x-protobuf'
15
+ }.freeze
16
+
17
+ def initialize(config)
18
+ @config = config
19
+ super(config)
20
+ end
21
+
22
+ # rubocop:disable Metrics/CyclomaticComplexity
23
+ # rubocop:disable Metrics/PerceivedComplexity
24
+ #
25
+ # This method will send a protobuf message to HTTP request.
26
+ # It will accept Array of transactions.
27
+ def post(transactions = [])
28
+ debug '[AgentHTTPClient] post()' if ENV['STACKIFY_TRANSPORT_LOG_LEVEL'] == '0'
29
+ return unless ENV['STACKIFY_RUBY_ENV'] != 'rspec'
30
+ max_retries = @config.max_retries
31
+ retry_count = 0
32
+ delay = @config.delay_seconds
33
+ begin
34
+ protobuf_obj = build_message(transactions)
35
+ message = StackifyProtoBuf::Traces.encode(protobuf_obj)
36
+ # Convert message into binary and send it to http request
37
+ conn = Faraday.new(ssl: { verify: false })
38
+ response = conn.post do |req|
39
+ req.url URI(@config.transport_http_endpoint + @config.agent_traces_url)
40
+ req.headers = HEADERS
41
+ req.body = message
42
+ end
43
+ if response.try(:status) == 200
44
+ debug '[AgentHTTPClient] Successfully send message via http request.' if ENV['STACKIFY_TRANSPORT_LOG_LEVEL'] == '0'
45
+ elsif ENV['STACKIFY_TRANSPORT_LOG_LEVEL'] == '0'
46
+ debug "[AgentHTTPClient] Failure sending via http request: #{response.inspect}"
47
+ end
48
+ rescue StandardError => e
49
+ debug '[AgentHTTPClient] All retries are exhausted!' if retry_count >= max_retries
50
+ retry_count += 1
51
+ if retry_count < max_retries
52
+ debug "[AgentHTTPClient] post() exception: #{e.inspect}"
53
+ debug "[AgentHTTPClient] An error occured. Retries left: #{max_retries - retry_count}"
54
+ end
55
+ sleep delay += retry_count
56
+ retry if retry_count < max_retries + 1
57
+ end
58
+ end
59
+ # rubocop:enable Metrics/CyclomaticComplexity
60
+ # rubocop:enable Metrics/PerceivedComplexity
61
+ end
62
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stackify_apm/root_info'
4
+ require 'stackify_apm/serializers'
5
+
6
+ module StackifyRubyAPM
7
+ # This class will handle the writing of messages through a logfile.
8
+ # @api private
9
+ class LogClient
10
+ include Log
11
+
12
+ def initialize(config)
13
+ @config = config
14
+ @transaction_serializers = Serializers::Transactions.new(@config)
15
+ end
16
+
17
+ # This method will build an Array of Transactions in a json format.
18
+ # It will accept Array of transactions.
19
+ def post(transactions = [])
20
+ # convert transactions to json
21
+ json_traces = []
22
+ transactions.each do |transaction|
23
+ # convert transaction to json
24
+ json_transaction = @transaction_serializers.build_json(@config, transaction).to_json
25
+
26
+ # add to json traces array
27
+ json_traces.push(json_transaction)
28
+ end
29
+
30
+ current_datetime = Time.now.utc.strftime('%Y-%m-%d, %H:%M:%S.%6N')
31
+
32
+ return unless ENV['STACKIFY_RUBY_ENV'] != 'rspec'
33
+
34
+ json_traces.each do |json_trace|
35
+ @config.tracer_logger.<<("#{current_datetime} > #{json_trace} \n")
36
+ end
37
+ debug '[LogClient] post() Successfully write to logfile.' if ENV['STACKIFY_TRANSPORT_LOG_LEVEL'] == '0'
38
+ rescue StandardError => e
39
+ debug "[LogClient] post() exception: #{e.inspect}"
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net_http_unix'
4
+ require 'ostruct'
5
+
6
+ module StackifyRubyAPM
7
+ # This class will handle the sending of protobuf messages through unix domain socket.
8
+ # @api private
9
+ class UnixSocketClient < AgentBaseTransport
10
+ include Log
11
+
12
+ def initialize(config)
13
+ @config = config
14
+ super(config)
15
+ end
16
+
17
+ # rubocop:disable Metrics/CyclomaticComplexity
18
+ # rubocop:disable Metrics/PerceivedComplexity
19
+ #
20
+ # This method will send a protobuf message to the unix domain socket.
21
+ # It will accept Array of transactions.
22
+ def post(transactions = [])
23
+ debug '[UnixSocketClient] post()' if ENV['STACKIFY_TRANSPORT_LOG_LEVEL'] == '0'
24
+ return unless ENV['STACKIFY_RUBY_ENV'] != 'rspec'
25
+ max_retries = @config.max_retries
26
+ retry_count = 0
27
+ delay = @config.delay_seconds
28
+ begin
29
+ # Convert message into binary and send it to unix domain socket
30
+ protobuf_obj = build_message(transactions)
31
+ message = StackifyProtoBuf::Traces.encode(protobuf_obj)
32
+ client = NetX::HTTPUnix.new('unix://' + @config.unix_socket_path)
33
+ req = Net::HTTP::Post.new(@config.agent_traces_url)
34
+ req.set_content_type('application/x-protobuf')
35
+ req.body = message
36
+ response = client.request(req)
37
+ debug "[UnixSocketClient] status_code = #{response.code}" if ENV['STACKIFY_TRANSPORT_LOG_LEVEL'] == '0'
38
+ if response.code.to_i == 200
39
+ debug '[UnixSocketClient] Successfully sent message via unix domain socket.' if ENV['STACKIFY_TRANSPORT_LOG_LEVEL'] == '0'
40
+ elsif ENV['STACKIFY_TRANSPORT_LOG_LEVEL'] == '0'
41
+ debug "[UnixSocketClient] Failure sending via unix domain socket: #{response.inspect}"
42
+ end
43
+ rescue StandardError => e
44
+ debug '[UnixSocketClient] All retries are exhausted!' if retry_count >= max_retries
45
+ retry_count += 1
46
+ if retry_count < max_retries
47
+ debug "[UnixSocketClient] post() exception: #{e.inspect}"
48
+ debug "[UnixSocketClient] An error occured. Retries left: #{max_retries - retry_count}"
49
+ end
50
+ sleep delay += retry_count
51
+ retry if retry_count < max_retries + 1
52
+ end
53
+ end
54
+ # rubocop:enable Metrics/CyclomaticComplexity
55
+ # rubocop:enable Metrics/PerceivedComplexity
56
+ end
57
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This class handle the selection of the Transport.
4
+
5
+ module StackifyRubyAPM
6
+ # @api private
7
+ class TransportSelector
8
+ attr_reader :transport
9
+
10
+ def initialize(config)
11
+ @transport =
12
+ case config.transport.strip.downcase
13
+ when StackifyRubyAPM::UNIX_SOCKET
14
+ StackifyRubyAPM::UnixSocketClient.new(config)
15
+ when StackifyRubyAPM::AGENT_HTTP
16
+ StackifyRubyAPM::AgentHTTPClient.new(config)
17
+ else
18
+ StackifyRubyAPM::LogClient.new(config)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Sets the version of the APM
4
4
  module StackifyRubyAPM
5
- VERSION = '1.7.4'.freeze
5
+ VERSION = '1.8.0'.freeze
6
6
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # This class will receive the transactions and send it to HTTP/TraceLogger.
4
- # Responsible for sending transactions to APM for every 10 secs (config.flush_interval default)
4
+ # Responsible for sending transactions to APM for every 1 secs (config.flush_interval_seconds default)
5
5
  # Worker will constantly execute transaction sending to APM until the Agent is stopped.
6
6
 
7
7
  require 'concurrent/timer_task'
@@ -66,11 +66,11 @@ module StackifyRubyAPM
66
66
  Thread.exit
67
67
  end
68
68
 
69
- # flush_interval - interval with which transactions should be sent to the APM. Default value: 10 seconds
69
+ # flush_interval_seconds - interval with which transactions should be sent to the APM.
70
70
  # The running task responsible for initiating the transactions sending
71
71
  #
72
72
  def build_timer_task
73
- Concurrent::TimerTask.new(execution_interval: config.flush_interval) do
73
+ Concurrent::TimerTask.new(execution_interval: config.flush_interval_seconds) do
74
74
  messages.push(FlushMsg.new)
75
75
  end
76
76
  end
@@ -81,7 +81,7 @@ module StackifyRubyAPM
81
81
  def collect_and_send_transactions
82
82
  return if pending_transactions.empty?
83
83
  transactions = collect_batched_transactions
84
- debug '[Worker] collect_and_send_transactions() transactions : ' + transactions.inspect.to_s if ENV['STACKIFY_APM_LOG_LEVEL'] == '0'
84
+ debug '[Worker] collect_and_send_transactions() transactions : ' + transactions.inspect.to_s if ENV['STACKIFY_TRANSPORT_LOG_LEVEL'] == '0'
85
85
  begin
86
86
  @trace_logger.post(transactions)
87
87
  rescue ::Exception => e
@@ -28,6 +28,14 @@ require 'stackify_apm/internal_error'
28
28
  require 'stackify_apm/response_manipulator'
29
29
  require 'stackify_apm/middleware'
30
30
  require 'stackify_apm/instrumenter_helper'
31
+ require 'stackify_apm/transport_selector'
32
+ require 'stackify_apm/transport/agent_base'
33
+ require 'stackify_apm/transport/log_client'
34
+ require 'stackify_apm/transport/unix_socket_client'
35
+ require 'stackify_apm/transport/agent_http_client'
36
+
37
+ require 'google/protobuf'
38
+ require 'proto/stackify_trace'
31
39
 
32
40
  # Checks if the framework using is Rails
33
41
  require 'stackify_apm/railtie' if defined?(::Rails::Railtie)
@@ -26,5 +26,8 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency 'rspec', '~> 3.0'
27
27
  spec.add_dependency('concurrent-ruby', '~> 1.0')
28
28
  spec.add_dependency('delegate_matcher', '~> 0.4')
29
+ spec.add_dependency('faraday', '~> 0.8')
30
+ spec.add_dependency('google-protobuf', '3.5.0')
31
+ spec.add_dependency('net_http_unix', '~> 0.2')
29
32
  spec.add_dependency('rufus-scheduler', '~> 3.5')
30
33
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stackify-ruby-apm
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.4
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stackify
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-12-05 00:00:00.000000000 Z
11
+ date: 2020-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,6 +80,48 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0.4'
83
+ - !ruby/object:Gem::Dependency
84
+ name: faraday
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.8'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.8'
97
+ - !ruby/object:Gem::Dependency
98
+ name: google-protobuf
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 3.5.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 3.5.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: net_http_unix
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.2'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.2'
83
125
  - !ruby/object:Gem::Dependency
84
126
  name: rufus-scheduler
85
127
  requirement: !ruby/object:Gem::Requirement
@@ -112,6 +154,7 @@ files:
112
154
  - README.md
113
155
  - Rakefile
114
156
  - docker-compose.yml
157
+ - lib/proto/stackify_trace.rb
115
158
  - lib/stackify-ruby-apm.rb
116
159
  - lib/stackify_apm/agent.rb
117
160
  - lib/stackify_apm/config.rb
@@ -173,6 +216,11 @@ files:
173
216
  - lib/stackify_apm/subscriber.rb
174
217
  - lib/stackify_apm/trace_logger.rb
175
218
  - lib/stackify_apm/transaction.rb
219
+ - lib/stackify_apm/transport/agent_base.rb
220
+ - lib/stackify_apm/transport/agent_http_client.rb
221
+ - lib/stackify_apm/transport/log_client.rb
222
+ - lib/stackify_apm/transport/unix_socket_client.rb
223
+ - lib/stackify_apm/transport_selector.rb
176
224
  - lib/stackify_apm/util.rb
177
225
  - lib/stackify_apm/util/dig.rb
178
226
  - lib/stackify_apm/util/inflector.rb