stackify-ruby-apm 1.7.4 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
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