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 +4 -4
- data/Gemfile +3 -1
- data/Gemfile.lock +83 -82
- data/lib/proto/stackify_trace.rb +39 -0
- data/lib/stackify_apm/agent.rb +20 -13
- data/lib/stackify_apm/config.rb +44 -25
- data/lib/stackify_apm/instrumenter.rb +2 -3
- data/lib/stackify_apm/middleware.rb +12 -10
- data/lib/stackify_apm/response_manipulator.rb +2 -29
- data/lib/stackify_apm/root_info.rb +2 -2
- data/lib/stackify_apm/serializers/transactions.rb +71 -1
- data/lib/stackify_apm/spies/stackify_logger.rb +1 -1
- data/lib/stackify_apm/subscriber.rb +1 -1
- data/lib/stackify_apm/trace_logger.rb +8 -19
- data/lib/stackify_apm/transport/agent_base.rb +35 -0
- data/lib/stackify_apm/transport/agent_http_client.rb +62 -0
- data/lib/stackify_apm/transport/log_client.rb +42 -0
- data/lib/stackify_apm/transport/unix_socket_client.rb +57 -0
- data/lib/stackify_apm/transport_selector.rb +22 -0
- data/lib/stackify_apm/version.rb +1 -1
- data/lib/stackify_apm/worker.rb +4 -4
- data/lib/stackify_ruby_apm.rb +8 -0
- data/stackify-ruby-apm.gemspec +3 -0
- metadata +50 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a671e23d695c474d3aafa85df6756d98fa51610411f40e2c750a8e2e5ad2bb1
|
4
|
+
data.tar.gz: c34ada9683508fbf2345434260c616100a5394fc58c22c4ea5eeceb8e7be78fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
47
|
-
public_suffix (>= 2.0.2, <
|
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.
|
52
|
+
bson (4.5.0)
|
51
53
|
builder (3.2.3)
|
52
|
-
concurrent-ruby (1.1.
|
54
|
+
concurrent-ruby (1.1.5)
|
53
55
|
crack (0.4.3)
|
54
56
|
safe_yaml (~> 1.0.0)
|
55
|
-
crass (1.0.
|
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.
|
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.
|
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.
|
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.
|
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
|
-
|
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.
|
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.
|
97
|
+
mini_mime (1.0.2)
|
95
98
|
mini_portile2 (2.1.0)
|
96
|
-
minitest (5.
|
97
|
-
mongo (2.
|
99
|
+
minitest (5.12.0)
|
100
|
+
mongo (2.10.2)
|
98
101
|
bson (>= 4.4.2, < 5.0.0)
|
99
|
-
multipart-post (2.
|
100
|
-
mysql2 (0.5.
|
101
|
-
|
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.
|
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
|
139
|
-
loofah (~> 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.
|
150
|
-
rspec-core (~> 3.
|
151
|
-
rspec-expectations (~> 3.
|
152
|
-
rspec-mocks (~> 3.
|
153
|
-
rspec-core (3.
|
154
|
-
rspec-support (~> 3.
|
155
|
-
rspec-expectations (3.
|
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.
|
158
|
-
rspec-mocks (3.
|
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.
|
161
|
-
rspec-support (3.
|
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.
|
170
|
-
ruby2ruby (2.4.
|
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.
|
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.
|
179
|
-
sexp_processor (4.
|
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.
|
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
|
-
|
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.
|
206
|
+
tilt (2.0.10)
|
206
207
|
timecop (0.9.1)
|
207
|
-
tins (1.
|
208
|
-
to_bool (
|
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.
|
214
|
-
|
215
|
-
|
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
|
data/lib/stackify_apm/agent.rb
CHANGED
@@ -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
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
config.
|
41
|
-
|
42
|
-
|
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['
|
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.
|
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['
|
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(
|
data/lib/stackify_apm/config.rb
CHANGED
@@ -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
|
-
|
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
|
-
'
|
62
|
-
'
|
63
|
-
'
|
64
|
-
'
|
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
|
-
'
|
67
|
-
'
|
68
|
-
'
|
69
|
-
'
|
70
|
-
'
|
71
|
-
'
|
72
|
-
'
|
73
|
-
'
|
74
|
-
'
|
75
|
-
'
|
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 :
|
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 :
|
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
|
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['
|
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['
|
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
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
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['
|
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
|
-
|
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
|
-
|
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
|
data/lib/stackify_apm/version.rb
CHANGED
data/lib/stackify_apm/worker.rb
CHANGED
@@ -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
|
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
|
-
#
|
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.
|
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['
|
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
|
data/lib/stackify_ruby_apm.rb
CHANGED
@@ -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)
|
data/stackify-ruby-apm.gemspec
CHANGED
@@ -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.
|
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:
|
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
|