elastic-apm 2.9.1 → 2.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ci/.jenkins_codecov.yml +5 -0
- data/.ci/.jenkins_exclude.yml +9 -19
- data/.ci/.jenkins_framework.yml +1 -4
- data/.ci/.jenkins_master_framework.yml +3 -0
- data/.ci/Jenkinsfile +43 -118
- data/.ci/downstreamTests.groovy +59 -30
- data/.ci/jobs/apm-agent-ruby-downstream.yml +31 -0
- data/.ci/jobs/apm-agent-ruby-mbp.yml +34 -0
- data/.ci/jobs/defaults.yml +1 -36
- data/.pre-commit-config.yaml +22 -0
- data/.rspec +0 -1
- data/.rubocop.yml +3 -3
- data/CHANGELOG.md +12 -0
- data/docs/api.asciidoc +2 -2
- data/docs/configuration.asciidoc +37 -1
- data/docs/metrics.asciidoc +77 -6
- data/lib/elastic_apm.rb +2 -2
- data/lib/elastic_apm/agent.rb +11 -2
- data/lib/elastic_apm/central_config.rb +141 -0
- data/lib/elastic_apm/central_config/cache_control.rb +34 -0
- data/lib/elastic_apm/config.rb +152 -338
- data/lib/elastic_apm/config/bytes.rb +25 -0
- data/lib/elastic_apm/config/duration.rb +6 -8
- data/lib/elastic_apm/config/options.rb +134 -0
- data/lib/elastic_apm/config/regexp_list.rb +13 -0
- data/lib/elastic_apm/metadata.rb +2 -1
- data/lib/elastic_apm/metrics.rb +2 -1
- data/lib/elastic_apm/metrics/vm.rb +57 -0
- data/lib/elastic_apm/normalizers/action_view.rb +1 -1
- data/lib/elastic_apm/railtie.rb +10 -5
- data/lib/elastic_apm/spies/mongo.rb +13 -2
- data/lib/elastic_apm/stacktrace_builder.rb +2 -2
- data/lib/elastic_apm/transport/connection.rb +2 -0
- data/lib/elastic_apm/transport/serializers/metadata_serializer.rb +6 -1
- data/lib/elastic_apm/version.rb +1 -1
- metadata +11 -3
- data/lib/elastic_apm/config/size.rb +0 -28
@@ -4,3 +4,37 @@
|
|
4
4
|
display-name: APM Agent Ruby
|
5
5
|
description: APM Agent Ruby
|
6
6
|
script-path: .ci/Jenkinsfile
|
7
|
+
scm:
|
8
|
+
- github:
|
9
|
+
branch-discovery: no-pr
|
10
|
+
discover-pr-forks-strategy: merge-current
|
11
|
+
discover-pr-forks-trust: permission
|
12
|
+
discover-pr-origin: merge-current
|
13
|
+
discover-tags: true
|
14
|
+
repo: apm-agent-ruby
|
15
|
+
repo-owner: elastic
|
16
|
+
credentials-id: 2a9602aa-ab9f-4e52-baf3-b71ca88469c7-UserAndToken
|
17
|
+
ssh-checkout:
|
18
|
+
credentials: f6c7695a-671e-4f4f-a331-acdce44ff9ba
|
19
|
+
build-strategies:
|
20
|
+
- tags:
|
21
|
+
ignore-tags-older-than: -1
|
22
|
+
ignore-tags-newer-than: -1
|
23
|
+
- regular-branches: true
|
24
|
+
- change-request:
|
25
|
+
ignore-target-only-changes: false
|
26
|
+
clean:
|
27
|
+
after: true
|
28
|
+
before: true
|
29
|
+
prune: true
|
30
|
+
shallow-clone: true
|
31
|
+
depth: 3
|
32
|
+
do-not-fetch-tags: true
|
33
|
+
submodule:
|
34
|
+
disable: false
|
35
|
+
recursive: true
|
36
|
+
parent-credentials: true
|
37
|
+
timeout: 100
|
38
|
+
timeout: '15'
|
39
|
+
use-author: true
|
40
|
+
wipe-workspace: 'True'
|
data/.ci/jobs/defaults.yml
CHANGED
@@ -12,46 +12,11 @@
|
|
12
12
|
project-type: multibranch
|
13
13
|
logrotate:
|
14
14
|
daysToKeep: 30
|
15
|
-
numToKeep:
|
15
|
+
numToKeep: 300
|
16
16
|
number-to-keep: '100'
|
17
17
|
days-to-keep: '30'
|
18
18
|
concurrent: true
|
19
19
|
node: linux
|
20
|
-
script-path: .ci/Jenkinsfile
|
21
|
-
scm:
|
22
|
-
- github:
|
23
|
-
branch-discovery: all
|
24
|
-
discover-pr-forks-strategy: merge-current
|
25
|
-
discover-pr-forks-trust: permission
|
26
|
-
discover-pr-origin: merge-current
|
27
|
-
discover-tags: true
|
28
|
-
repo: apm-agent-ruby
|
29
|
-
repo-owner: elastic
|
30
|
-
credentials-id: 2a9602aa-ab9f-4e52-baf3-b71ca88469c7-UserAndToken
|
31
|
-
ssh-checkout:
|
32
|
-
credentials: f6c7695a-671e-4f4f-a331-acdce44ff9ba
|
33
|
-
build-strategies:
|
34
|
-
- tags:
|
35
|
-
ignore-tags-older-than: -1
|
36
|
-
ignore-tags-newer-than: -1
|
37
|
-
- regular-branches: true
|
38
|
-
- change-request:
|
39
|
-
ignore-target-only-changes: false
|
40
|
-
clean:
|
41
|
-
after: true
|
42
|
-
before: true
|
43
|
-
prune: true
|
44
|
-
shallow-clone: true
|
45
|
-
depth: 3
|
46
|
-
do-not-fetch-tags: true
|
47
|
-
submodule:
|
48
|
-
disable: false
|
49
|
-
recursive: true
|
50
|
-
parent-credentials: true
|
51
|
-
timeout: 100
|
52
|
-
timeout: '15'
|
53
|
-
use-author: true
|
54
|
-
wipe-workspace: 'True'
|
55
20
|
periodic-folder-trigger: 1d
|
56
21
|
prune-dead-branches: true
|
57
22
|
publishers:
|
@@ -0,0 +1,22 @@
|
|
1
|
+
repos:
|
2
|
+
- repo: git://github.com/pre-commit/pre-commit-hooks
|
3
|
+
rev: v2.2.3
|
4
|
+
hooks:
|
5
|
+
- id: check-case-conflict
|
6
|
+
- id: check-executables-have-shebangs
|
7
|
+
- id: check-json
|
8
|
+
- id: check-merge-conflict
|
9
|
+
- id: check-yaml
|
10
|
+
- id: check-xml
|
11
|
+
- id: end-of-file-fixer
|
12
|
+
|
13
|
+
- repo: git@github.com:elastic/apm-pipeline-library
|
14
|
+
rev: current
|
15
|
+
hooks:
|
16
|
+
- id: check-bash-syntax
|
17
|
+
- id: check-abstract-classes-and-trait
|
18
|
+
- id: check-jsonslurper-class
|
19
|
+
- id: check-jenkins-pipelines
|
20
|
+
- id: check-unicode-non-breaking-spaces
|
21
|
+
- id: remove-unicode-non-breaking-spaces
|
22
|
+
- id: check-jjbb
|
data/.rspec
CHANGED
data/.rubocop.yml
CHANGED
@@ -66,9 +66,6 @@ Style/DoubleNegation:
|
|
66
66
|
Style/EmptyMethod:
|
67
67
|
Enabled: false
|
68
68
|
|
69
|
-
Rails/Delegate:
|
70
|
-
Enabled: false
|
71
|
-
|
72
69
|
Style/NumericPredicate:
|
73
70
|
Enabled: false
|
74
71
|
|
@@ -83,3 +80,6 @@ Naming/MemoizedInstanceVariableName:
|
|
83
80
|
|
84
81
|
Style/SpecialGlobalVars:
|
85
82
|
Enabled: false
|
83
|
+
|
84
|
+
Style/MissingRespondToMissing:
|
85
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
|
5
5
|
This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## 2.10.0
|
8
|
+
|
9
|
+
### Added
|
10
|
+
|
11
|
+
- Add Ruby specific metrics ([#437](https://github.com/elastic/apm-agent-ruby/pull/437))
|
12
|
+
- Support for APM Agent Configuration via Kibana ([#464](https://github.com/elastic/apm-agent-ruby/pull/464))
|
13
|
+
- Change span name format and add command to context's db.statement for `MongoSpy` ([#488](https://github.com/elastic/apm-agent-ruby/pull/490))
|
14
|
+
|
15
|
+
### Changed
|
16
|
+
|
17
|
+
- `ElasticAPM.report` and `ElasticAPM.report_message` return the string ID of the generated `Error` objects ([#507](https://github.com/elastic/apm-agent-ruby/pull/507))
|
18
|
+
|
7
19
|
## 2.9.1 (2019-06-28)
|
8
20
|
|
9
21
|
### Fixed
|
data/docs/api.asciidoc
CHANGED
@@ -212,7 +212,7 @@ Arguments:
|
|
212
212
|
* `handled`: Whether the error was _handled_ eg. wasn't rescued and was represented
|
213
213
|
to the user. Default: `true`.
|
214
214
|
|
215
|
-
Returns `[ElasticAPM::Error]
|
215
|
+
Returns `[String]` ID of the generated `[ElasticAPM::Error]` object.
|
216
216
|
|
217
217
|
[float]
|
218
218
|
[[api-agent-report-message]]
|
@@ -231,7 +231,7 @@ Arguments:
|
|
231
231
|
|
232
232
|
* `message`: A custom error string. **Required**.
|
233
233
|
|
234
|
-
Returns `[ElasticAPM::Error]
|
234
|
+
Returns `[String]` ID of the generated `[ElasticAPM::Error]` object.
|
235
235
|
|
236
236
|
[float]
|
237
237
|
[[api-context]]
|
data/docs/configuration.asciidoc
CHANGED
@@ -62,7 +62,7 @@ Some options can be set with `ENV` variables and all of them may be set in
|
|
62
62
|
your source code.
|
63
63
|
|
64
64
|
When setting values for lists using `ENV` variables, strings are split by comma
|
65
|
-
eg `
|
65
|
+
eg `ELASTIC_APM_CUSTOM_KEY_FILTERS="a,b" # => [/a/, /b/]`.
|
66
66
|
|
67
67
|
[float]
|
68
68
|
[[config-config-file]]
|
@@ -213,6 +213,21 @@ Whether or not to attach the request headers to transactions and errors.
|
|
213
213
|
|
214
214
|
Whether or not to attach `ENV` from Rack to transactions and errors.
|
215
215
|
|
216
|
+
[float]
|
217
|
+
[[config-central-config]]
|
218
|
+
==== `central_config`
|
219
|
+
|============
|
220
|
+
| Environment | `Config` key | Default
|
221
|
+
| `ELASTIC_APM_CENTRAL_CONFIG` | `central_config` | `true`
|
222
|
+
|============
|
223
|
+
|
224
|
+
Enable {kibana-ref}/agent-configuration.html[APM Agent Configuration via Kibana].
|
225
|
+
If set to `true`, the client will poll the APM Server regularly for new agent configuration.
|
226
|
+
|
227
|
+
Usually APM Server determines how often to poll, but if not the default interval is 5 minutes.
|
228
|
+
|
229
|
+
NOTE: This feature requires APM Server v7.3 or later and that the APM Server is configured with `kibana.enabled: true`.
|
230
|
+
|
216
231
|
[float]
|
217
232
|
[[config-custom-key-filters]]
|
218
233
|
==== `custom_key_filters`
|
@@ -244,6 +259,10 @@ Add default tags to add to every transaction.
|
|
244
259
|
|
245
260
|
WARNING: Be aware that tags are indexed in Elasticsearch. Using too many unique keys will result in *https://www.elastic.co/blog/found-crash-elasticsearch#mapping-explosion[Mapping explosion]*.
|
246
261
|
|
262
|
+
NOTE: `global_labels` are supported as of APM server version 7.2. `default_tags` will eventually be
|
263
|
+
deprecated so please transition to using `global_labels` instead. In the meantime, any `default_tags`
|
264
|
+
that are set will override `global_labels`.
|
265
|
+
|
247
266
|
[float]
|
248
267
|
[[config-disable-send]]
|
249
268
|
==== `disable_send`
|
@@ -337,6 +356,23 @@ Version number of the used framework.
|
|
337
356
|
For Ruby on Rails and Sinatra, this defaults to the used version of the framework,
|
338
357
|
otherwise, the default is `nil`.
|
339
358
|
|
359
|
+
[float]
|
360
|
+
[[config-global-labels]]
|
361
|
+
==== `global_labels`
|
362
|
+
|
363
|
+
[options="header"]
|
364
|
+
|============
|
365
|
+
| Environment | `Config` key | Default | Example
|
366
|
+
| `ELASTIC_APM_GLOBAL_LABELS` | `global_labels` | `nil` | `dept=engineering,rack=number8`
|
367
|
+
|============
|
368
|
+
|
369
|
+
Labels added to all events, with the format key=value[,key=value[,...]].
|
370
|
+
|
371
|
+
NOTE: This option requires APM Server 7.2 or greater, and will have no effect when using older
|
372
|
+
server versions. `default_tags` will eventually be deprecated but in the meantime, their value
|
373
|
+
will override any `global_labels`. Please transition to using `global_labels` instead of
|
374
|
+
`default_tags` in light of this deprecation.
|
375
|
+
|
340
376
|
[float]
|
341
377
|
[[config-hostname]]
|
342
378
|
==== `hostname`
|
data/docs/metrics.asciidoc
CHANGED
@@ -12,11 +12,15 @@ You can adjust the interval by setting <<config-metrics-interval,`metrics_interv
|
|
12
12
|
|
13
13
|
The metrics will be stored in the `apm-*` index and have the `processor.event` property set to `metric`.
|
14
14
|
|
15
|
+
[float]
|
16
|
+
[[metrics-system]]
|
17
|
+
=== System metrics
|
18
|
+
|
15
19
|
**Note:** Metrics from the Ruby agent are Linux only for now.
|
16
20
|
|
17
21
|
[float]
|
18
22
|
[[metric-system.cpu.total.norm.pct]]
|
19
|
-
|
23
|
+
==== `system.cpu.total.norm.pct`
|
20
24
|
|
21
25
|
* *Type:* Float
|
22
26
|
* *Format:* Percent
|
@@ -26,7 +30,7 @@ normalised by the number of cores.
|
|
26
30
|
|
27
31
|
[float]
|
28
32
|
[[metric-system.memory.total]]
|
29
|
-
|
33
|
+
==== `system.memory.total`
|
30
34
|
|
31
35
|
* *Type:* Long
|
32
36
|
* *Format:* Bytes
|
@@ -35,7 +39,7 @@ The total memory of the system in bytes.
|
|
35
39
|
|
36
40
|
[float]
|
37
41
|
[[metric-system.memory.actual.free]]
|
38
|
-
|
42
|
+
==== `system.memory.actual.free`
|
39
43
|
|
40
44
|
* *Type:* Long
|
41
45
|
* *Format:* Bytes
|
@@ -44,7 +48,7 @@ Free memory of the system in bytes.
|
|
44
48
|
|
45
49
|
[float]
|
46
50
|
[[metric-system.process.cpu.total.norm.pct]]
|
47
|
-
|
51
|
+
==== `system.process.cpu.total.norm.pct`
|
48
52
|
|
49
53
|
* *Type:* Float
|
50
54
|
* *Format:* Percent
|
@@ -54,7 +58,7 @@ This value is normalized by the number of CPU cores and it ranges from 0 to 100%
|
|
54
58
|
|
55
59
|
[float]
|
56
60
|
[[metric-system.process.memory.size]]
|
57
|
-
|
61
|
+
==== `system.process.memory.size`
|
58
62
|
|
59
63
|
* *Type:* Long
|
60
64
|
* *Format:* Bytes
|
@@ -63,10 +67,77 @@ The total virtual memory the process has.
|
|
63
67
|
|
64
68
|
[float]
|
65
69
|
[[metric-system.process.memory.rss.bytes]]
|
66
|
-
|
70
|
+
==== `system.process.memory.rss.bytes`
|
67
71
|
|
68
72
|
* *Type:* Long
|
69
73
|
* *Format:* Bytes
|
70
74
|
|
71
75
|
The Resident Set Size,
|
72
76
|
the amount of memory the process occupies in main memory (RAM).
|
77
|
+
|
78
|
+
[float]
|
79
|
+
[[metrics-ruby]]
|
80
|
+
=== Ruby Metrics
|
81
|
+
|
82
|
+
[float]
|
83
|
+
[[metric-ruby.gc.counts]]
|
84
|
+
==== `ruby.gc.count`
|
85
|
+
|
86
|
+
* *Type:* Integer
|
87
|
+
* *Format:* Count
|
88
|
+
|
89
|
+
The number of Garbage Collection runs since the process started.
|
90
|
+
|
91
|
+
[float]
|
92
|
+
[[metric-ruby.threads]]
|
93
|
+
==== `ruby.threads`
|
94
|
+
|
95
|
+
* *Type:* Integer
|
96
|
+
* *Format:* Count
|
97
|
+
|
98
|
+
The number of threads belonging to the current process.
|
99
|
+
|
100
|
+
[float]
|
101
|
+
[[metric-ruby.heap.slots.live]]
|
102
|
+
==== `ruby.heap.slots.live`
|
103
|
+
|
104
|
+
* *Type:* Integer
|
105
|
+
* *Format:* Slots
|
106
|
+
|
107
|
+
Current amount of heap slots that are live.
|
108
|
+
|
109
|
+
**NB:** Not currently supported on JRuby.
|
110
|
+
|
111
|
+
[float]
|
112
|
+
[[metric-ruby.heap.slots.free]]
|
113
|
+
==== `ruby.heap.slots.free`
|
114
|
+
|
115
|
+
* *Type:* Integer
|
116
|
+
* *Format:* Slots
|
117
|
+
|
118
|
+
Current amount of heap slots that are free.
|
119
|
+
|
120
|
+
**NB:** Not currently supported on JRuby.
|
121
|
+
|
122
|
+
[float]
|
123
|
+
[[metrics-ruby.heap.allocations.total]]
|
124
|
+
==== `ruby.heap.allocations.total`
|
125
|
+
|
126
|
+
* *Type:* Integer
|
127
|
+
* *Format:* Objects
|
128
|
+
|
129
|
+
Current amount of allocated objects on the heap.
|
130
|
+
|
131
|
+
**NB:** Not currently supported on JRuby.
|
132
|
+
|
133
|
+
[float]
|
134
|
+
[[metrics-ruby.gc.time]]
|
135
|
+
==== `ruby.gc.time`
|
136
|
+
|
137
|
+
* *Type:* Float
|
138
|
+
* *Format:* Seconds
|
139
|
+
|
140
|
+
The total time spent in garbage collection.
|
141
|
+
|
142
|
+
**NB:** You need to enable Ruby's GC Profiler for this to get reported.
|
143
|
+
You can do this at any time when your application boots by calling `GC::Profiler.enable`.
|
data/lib/elastic_apm.rb
CHANGED
@@ -305,7 +305,7 @@ module ElasticAPM # rubocop:disable Metrics/ModuleLength
|
|
305
305
|
# @param exception [Exception] The exception
|
306
306
|
# @param context [Context] An optional [Context]
|
307
307
|
# @param handled [Boolean] Whether the exception was rescued
|
308
|
-
# @return [
|
308
|
+
# @return [String] ID of the generated [Error]
|
309
309
|
def report(exception, context: nil, handled: true)
|
310
310
|
agent&.report(exception, context: context, handled: handled)
|
311
311
|
end
|
@@ -314,7 +314,7 @@ module ElasticAPM # rubocop:disable Metrics/ModuleLength
|
|
314
314
|
#
|
315
315
|
# @param message [String] The message
|
316
316
|
# @param context [Context] An optional [Context]
|
317
|
-
# @return [
|
317
|
+
# @return [String] ID of the generated [Error]
|
318
318
|
def report_message(message, context: nil, **attrs)
|
319
319
|
agent&.report_message(
|
320
320
|
message,
|
data/lib/elastic_apm/agent.rb
CHANGED
@@ -1,13 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'elastic_apm/error'
|
4
|
+
|
3
5
|
require 'elastic_apm/context_builder'
|
4
6
|
require 'elastic_apm/error_builder'
|
5
7
|
require 'elastic_apm/stacktrace_builder'
|
6
|
-
|
8
|
+
|
9
|
+
require 'elastic_apm/central_config'
|
7
10
|
require 'elastic_apm/transport/base'
|
8
|
-
require 'elastic_apm/spies'
|
9
11
|
require 'elastic_apm/metrics'
|
10
12
|
|
13
|
+
require 'elastic_apm/spies'
|
14
|
+
|
11
15
|
module ElasticAPM
|
12
16
|
# rubocop:disable Metrics/ClassLength
|
13
17
|
# @api private
|
@@ -57,6 +61,7 @@ module ElasticAPM
|
|
57
61
|
!!@instance
|
58
62
|
end
|
59
63
|
|
64
|
+
# rubocop:disable Metrics/MethodLength
|
60
65
|
def initialize(config)
|
61
66
|
@config = config
|
62
67
|
|
@@ -64,6 +69,7 @@ module ElasticAPM
|
|
64
69
|
@context_builder = ContextBuilder.new(config)
|
65
70
|
@error_builder = ErrorBuilder.new(self)
|
66
71
|
|
72
|
+
@central_config = CentralConfig.new(config)
|
67
73
|
@transport = Transport::Base.new(config)
|
68
74
|
@instrumenter = Instrumenter.new(
|
69
75
|
config,
|
@@ -71,6 +77,7 @@ module ElasticAPM
|
|
71
77
|
) { |event| enqueue event }
|
72
78
|
@metrics = Metrics.new(config) { |event| enqueue event }
|
73
79
|
end
|
80
|
+
# rubocop:enable Metrics/MethodLength
|
74
81
|
|
75
82
|
attr_reader :config, :transport, :instrumenter,
|
76
83
|
:stacktrace_builder, :context_builder, :error_builder, :metrics
|
@@ -189,6 +196,7 @@ module ElasticAPM
|
|
189
196
|
handled: handled
|
190
197
|
)
|
191
198
|
enqueue error
|
199
|
+
error.id
|
192
200
|
end
|
193
201
|
|
194
202
|
def report_message(message, context: nil, backtrace: nil, **attrs)
|
@@ -199,6 +207,7 @@ module ElasticAPM
|
|
199
207
|
**attrs
|
200
208
|
)
|
201
209
|
enqueue error
|
210
|
+
error.id
|
202
211
|
end
|
203
212
|
|
204
213
|
# filters
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'elastic_apm/central_config/cache_control'
|
4
|
+
|
5
|
+
module ElasticAPM
|
6
|
+
# @api private
|
7
|
+
class CentralConfig
|
8
|
+
include Logging
|
9
|
+
|
10
|
+
# @api private
|
11
|
+
class ResponseError < InternalError
|
12
|
+
def initialize(response)
|
13
|
+
@response = response
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :response
|
17
|
+
end
|
18
|
+
class ClientError < ResponseError; end
|
19
|
+
class ServerError < ResponseError; end
|
20
|
+
|
21
|
+
DEFAULT_MAX_AGE = 300
|
22
|
+
|
23
|
+
def initialize(config)
|
24
|
+
@config = config
|
25
|
+
@modified_options = {}
|
26
|
+
@service_info = {
|
27
|
+
'service.name': config.service_name,
|
28
|
+
'service.environment': config.environment
|
29
|
+
}.to_json
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :config
|
33
|
+
attr_reader :scheduled_task, :promise # for specs
|
34
|
+
|
35
|
+
def start
|
36
|
+
return unless config.central_config?
|
37
|
+
|
38
|
+
fetch_and_apply_config
|
39
|
+
end
|
40
|
+
|
41
|
+
def fetch_and_apply_config
|
42
|
+
@promise =
|
43
|
+
Concurrent::Promise
|
44
|
+
.execute(&method(:fetch_config))
|
45
|
+
.on_success(&method(:handle_success))
|
46
|
+
.rescue(&method(:handle_error))
|
47
|
+
end
|
48
|
+
|
49
|
+
def stop
|
50
|
+
@scheduled_task&.cancel
|
51
|
+
end
|
52
|
+
|
53
|
+
# rubocop:disable Metrics/MethodLength
|
54
|
+
def fetch_config
|
55
|
+
resp = perform_request
|
56
|
+
|
57
|
+
case resp.status
|
58
|
+
when 200..299
|
59
|
+
resp
|
60
|
+
when 300..399
|
61
|
+
resp
|
62
|
+
when 400..499
|
63
|
+
raise ClientError, resp
|
64
|
+
when 500..599
|
65
|
+
raise ServerError, resp
|
66
|
+
end
|
67
|
+
end
|
68
|
+
# rubocop:enable Metrics/MethodLength
|
69
|
+
|
70
|
+
def assign(update)
|
71
|
+
# For each updated option, store the original value,
|
72
|
+
# unless already stored
|
73
|
+
update.each_key do |key|
|
74
|
+
@modified_options[key] ||= config.get(key.to_sym)&.value
|
75
|
+
end
|
76
|
+
|
77
|
+
# If the new update doesn't set a previously modified option,
|
78
|
+
# revert it to the original
|
79
|
+
@modified_options.each_key do |key|
|
80
|
+
next if update.key?(key)
|
81
|
+
update[key] = @modified_options.delete(key)
|
82
|
+
end
|
83
|
+
|
84
|
+
config.assign(update)
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
# rubocop:disable Metrics/MethodLength
|
90
|
+
def handle_success(resp)
|
91
|
+
if resp.status == 304
|
92
|
+
info 'Received 304 Not Modified'
|
93
|
+
else
|
94
|
+
update = JSON.parse(resp.body.to_s)
|
95
|
+
assign(update)
|
96
|
+
|
97
|
+
info 'Updated config from Kibana'
|
98
|
+
end
|
99
|
+
|
100
|
+
schedule_next_fetch(resp)
|
101
|
+
|
102
|
+
true
|
103
|
+
rescue Exception => e
|
104
|
+
error 'Failed to apply remote config, %s', e.inspect
|
105
|
+
debug { e.backtrace.join('\n') }
|
106
|
+
end
|
107
|
+
# rubocop:enable Metrics/MethodLength
|
108
|
+
|
109
|
+
def handle_error(error)
|
110
|
+
error(
|
111
|
+
'Failed fetching config: %s, trying again in %d seconds',
|
112
|
+
error.response.body, DEFAULT_MAX_AGE
|
113
|
+
)
|
114
|
+
|
115
|
+
assign({})
|
116
|
+
|
117
|
+
schedule_next_fetch(error.response)
|
118
|
+
end
|
119
|
+
|
120
|
+
def perform_request
|
121
|
+
Http.post(
|
122
|
+
config.server_url + '/agent/v1/config/',
|
123
|
+
body: @service_info,
|
124
|
+
headers: { etag: 1, content_type: 'application/json' }
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
def schedule_next_fetch(resp)
|
129
|
+
seconds =
|
130
|
+
if (cache_header = resp.headers['Cache-Control'])
|
131
|
+
CacheControl.new(cache_header).max_age
|
132
|
+
else
|
133
|
+
DEFAULT_MAX_AGE
|
134
|
+
end
|
135
|
+
|
136
|
+
@scheduled_task =
|
137
|
+
Concurrent::ScheduledTask
|
138
|
+
.execute(seconds, &method(:fetch_and_apply_config))
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|