elastic-apm 2.8.1 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.ci/.jenkins_codecov.yml +5 -0
  3. data/.ci/.jenkins_exclude.yml +63 -0
  4. data/.ci/.jenkins_framework.yml +9 -0
  5. data/.ci/.jenkins_master_framework.yml +3 -0
  6. data/.ci/.jenkins_ruby.yml +11 -0
  7. data/.ci/Jenkinsfile +268 -0
  8. data/.ci/bin/check_paths_for_matches.py +80 -0
  9. data/.ci/downstreamTests.groovy +188 -0
  10. data/.ci/jobs/apm-agent-ruby-downstream.yml +37 -0
  11. data/.ci/jobs/apm-agent-ruby-linting-mbp.yml +38 -0
  12. data/.ci/jobs/apm-agent-ruby-mbp.yml +41 -0
  13. data/.ci/jobs/apm-agent-ruby.yml +4 -0
  14. data/.ci/jobs/defaults.yml +24 -0
  15. data/.ci/linting.groovy +32 -0
  16. data/.ci/prepare-git-context.sh +23 -0
  17. data/.pre-commit-config.yaml +22 -0
  18. data/.rspec +0 -1
  19. data/.rubocop.yml +3 -3
  20. data/CHANGELOG.md +59 -2
  21. data/docs/api.asciidoc +24 -7
  22. data/docs/configuration.asciidoc +43 -4
  23. data/docs/index.asciidoc +2 -0
  24. data/docs/log-correlation.asciidoc +96 -0
  25. data/docs/metrics.asciidoc +77 -6
  26. data/lib/elastic_apm.rb +37 -5
  27. data/lib/elastic_apm/agent.rb +29 -4
  28. data/lib/elastic_apm/central_config.rb +141 -0
  29. data/lib/elastic_apm/central_config/cache_control.rb +34 -0
  30. data/lib/elastic_apm/config.rb +165 -340
  31. data/lib/elastic_apm/config/bytes.rb +25 -0
  32. data/lib/elastic_apm/config/duration.rb +6 -8
  33. data/lib/elastic_apm/config/options.rb +134 -0
  34. data/lib/elastic_apm/config/regexp_list.rb +13 -0
  35. data/lib/elastic_apm/context_builder.rb +2 -0
  36. data/lib/elastic_apm/error/exception.rb +3 -1
  37. data/lib/elastic_apm/error_builder.rb +6 -3
  38. data/lib/elastic_apm/instrumenter.rb +6 -0
  39. data/lib/elastic_apm/metadata.rb +2 -1
  40. data/lib/elastic_apm/metrics.rb +2 -1
  41. data/lib/elastic_apm/metrics/vm.rb +60 -0
  42. data/lib/elastic_apm/normalizers/action_controller.rb +5 -2
  43. data/lib/elastic_apm/normalizers/action_mailer.rb +5 -2
  44. data/lib/elastic_apm/normalizers/action_view.rb +14 -9
  45. data/lib/elastic_apm/normalizers/active_record.rb +5 -2
  46. data/lib/elastic_apm/rails.rb +59 -0
  47. data/lib/elastic_apm/railtie.rb +11 -48
  48. data/lib/elastic_apm/span.rb +29 -7
  49. data/lib/elastic_apm/spies/faraday.rb +9 -2
  50. data/lib/elastic_apm/spies/http.rb +9 -2
  51. data/lib/elastic_apm/spies/mongo.rb +18 -3
  52. data/lib/elastic_apm/spies/net_http.rb +8 -2
  53. data/lib/elastic_apm/stacktrace/frame.rb +3 -1
  54. data/lib/elastic_apm/stacktrace_builder.rb +2 -2
  55. data/lib/elastic_apm/subscriber.rb +11 -3
  56. data/lib/elastic_apm/transport/connection.rb +17 -3
  57. data/lib/elastic_apm/transport/connection/proxy_pipe.rb +8 -1
  58. data/lib/elastic_apm/transport/filters/secrets_filter.rb +3 -1
  59. data/lib/elastic_apm/transport/serializers/error_serializer.rb +12 -2
  60. data/lib/elastic_apm/transport/serializers/metadata_serializer.rb +6 -1
  61. data/lib/elastic_apm/transport/serializers/span_serializer.rb +11 -3
  62. data/lib/elastic_apm/version.rb +1 -1
  63. metadata +26 -4
  64. data/Jenkinsfile +0 -280
  65. data/lib/elastic_apm/config/size.rb +0 -28
@@ -9,8 +9,15 @@ module ElasticAPM
9
9
  # @api private
10
10
  class ProxyPipe
11
11
  def initialize(enc = nil, compress: true)
12
- @read, wr = IO.pipe(enc)
12
+ rd, wr = IO.pipe(enc)
13
+
14
+ @read = rd
13
15
  @write = Write.new(wr, compress: compress)
16
+
17
+ # Http.rb<4 calls rewind on the request bodies, but IO::Pipe raises
18
+ # ~mikker
19
+ return if HTTP::VERSION.to_i >= 4
20
+ def rd.rewind; end
14
21
  end
15
22
 
16
23
  attr_reader :read, :write
@@ -14,7 +14,8 @@ module ElasticAPM
14
14
  /secret/i,
15
15
  /token/i,
16
16
  /api[-._]?key/i,
17
- /session[-._]?id/i
17
+ /session[-._]?id/i,
18
+ /(set[-_])?cookie/i
18
19
  ].freeze
19
20
 
20
21
  VALUE_FILTERS = [
@@ -30,6 +31,7 @@ module ElasticAPM
30
31
  def call(payload)
31
32
  strip_from! payload.dig(:transaction, :context, :request, :headers)
32
33
  strip_from! payload.dig(:transaction, :context, :request, :env)
34
+ strip_from! payload.dig(:transaction, :context, :request, :cookies)
33
35
  strip_from! payload.dig(:transaction, :context, :response, :headers)
34
36
  strip_from! payload.dig(:error, :context, :request, :headers)
35
37
  strip_from! payload.dig(:error, :context, :response, :headers)
@@ -14,7 +14,7 @@ module ElasticAPM
14
14
  base = {
15
15
  id: error.id,
16
16
  transaction_id: error.transaction_id,
17
- transaction: error.transaction,
17
+ transaction: build_transaction(error.transaction),
18
18
  trace_id: error.trace_id,
19
19
  parent_id: error.parent_id,
20
20
 
@@ -48,7 +48,8 @@ module ElasticAPM
48
48
  code: keyword_field(exception.code),
49
49
  attributes: exception.attributes,
50
50
  stacktrace: exception.stacktrace.to_a,
51
- handled: exception.handled
51
+ handled: exception.handled,
52
+ cause: exception.cause && [build_exception(exception.cause)]
52
53
  }
53
54
  end
54
55
 
@@ -61,6 +62,15 @@ module ElasticAPM
61
62
  stacktrace: log.stacktrace.to_a
62
63
  }
63
64
  end
65
+
66
+ def build_transaction(transaction)
67
+ return unless transaction
68
+
69
+ {
70
+ sampled: transaction[:sampled],
71
+ type: keyword_field(transaction[:type])
72
+ }
73
+ end
64
74
  end
65
75
  end
66
76
  end
@@ -10,7 +10,8 @@ module ElasticAPM
10
10
  metadata: {
11
11
  service: build_service(metadata.service),
12
12
  process: build_process(metadata.process),
13
- system: build_system(metadata.system)
13
+ system: build_system(metadata.system),
14
+ labels: build_labels(metadata.labels)
14
15
  }
15
16
  }
16
17
  end
@@ -59,6 +60,10 @@ module ElasticAPM
59
60
  kubernetes: keyword_object(system.kubernetes)
60
61
  }
61
62
  end
63
+
64
+ def build_labels(labels)
65
+ keyword_object(labels)
66
+ end
62
67
  end
63
68
  end
64
69
  end
@@ -13,7 +13,7 @@ module ElasticAPM
13
13
 
14
14
  attr_reader :context_serializer
15
15
 
16
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
16
+ # rubocop:disable Metrics/MethodLength
17
17
  def build(span)
18
18
  {
19
19
  span: {
@@ -21,7 +21,7 @@ module ElasticAPM
21
21
  transaction_id: span.transaction_id,
22
22
  parent_id: span.parent_id,
23
23
  name: keyword_field(span.name),
24
- type: keyword_field(span.type),
24
+ type: join_type(span),
25
25
  duration: ms(span.duration),
26
26
  context: context_serializer.build(span.context),
27
27
  stacktrace: span.stacktrace.to_a,
@@ -30,7 +30,7 @@ module ElasticAPM
30
30
  }
31
31
  }
32
32
  end
33
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
33
+ # rubocop:enable Metrics/MethodLength
34
34
 
35
35
  # @api private
36
36
  class ContextSerializer < Serializer
@@ -66,6 +66,14 @@ module ElasticAPM
66
66
  }
67
67
  end
68
68
  end
69
+
70
+ private
71
+
72
+ def join_type(span)
73
+ combined = [span.type, span.subtype, span.action]
74
+ combined.compact!
75
+ combined.join '.'
76
+ end
69
77
  end
70
78
  end
71
79
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ElasticAPM
4
- VERSION = '2.8.1'
4
+ VERSION = '2.11.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elastic-apm
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.1
4
+ version: 2.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikkel Malmberg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-29 00:00:00.000000000 Z
11
+ date: 2019-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -45,15 +45,30 @@ executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
+ - ".ci/.jenkins_codecov.yml"
49
+ - ".ci/.jenkins_exclude.yml"
50
+ - ".ci/.jenkins_framework.yml"
51
+ - ".ci/.jenkins_master_framework.yml"
52
+ - ".ci/.jenkins_ruby.yml"
53
+ - ".ci/Jenkinsfile"
54
+ - ".ci/bin/check_paths_for_matches.py"
55
+ - ".ci/downstreamTests.groovy"
56
+ - ".ci/jobs/apm-agent-ruby-downstream.yml"
57
+ - ".ci/jobs/apm-agent-ruby-linting-mbp.yml"
58
+ - ".ci/jobs/apm-agent-ruby-mbp.yml"
59
+ - ".ci/jobs/apm-agent-ruby.yml"
60
+ - ".ci/jobs/defaults.yml"
61
+ - ".ci/linting.groovy"
62
+ - ".ci/prepare-git-context.sh"
48
63
  - ".gitignore"
49
64
  - ".hound.yml"
65
+ - ".pre-commit-config.yaml"
50
66
  - ".rspec"
51
67
  - ".rubocop.yml"
52
68
  - CHANGELOG.md
53
69
  - CODE_OF_CONDUCT.md
54
70
  - CONTRIBUTING.md
55
71
  - Gemfile
56
- - Jenkinsfile
57
72
  - LICENSE
58
73
  - README.md
59
74
  - Rakefile
@@ -78,6 +93,7 @@ files:
78
93
  - docs/getting-started-rails.asciidoc
79
94
  - docs/index.asciidoc
80
95
  - docs/introduction.asciidoc
96
+ - docs/log-correlation.asciidoc
81
97
  - docs/metrics.asciidoc
82
98
  - docs/opentracing.asciidoc
83
99
  - docs/release-notes.asciidoc
@@ -86,9 +102,13 @@ files:
86
102
  - lib/elastic-apm.rb
87
103
  - lib/elastic_apm.rb
88
104
  - lib/elastic_apm/agent.rb
105
+ - lib/elastic_apm/central_config.rb
106
+ - lib/elastic_apm/central_config/cache_control.rb
89
107
  - lib/elastic_apm/config.rb
108
+ - lib/elastic_apm/config/bytes.rb
90
109
  - lib/elastic_apm/config/duration.rb
91
- - lib/elastic_apm/config/size.rb
110
+ - lib/elastic_apm/config/options.rb
111
+ - lib/elastic_apm/config/regexp_list.rb
92
112
  - lib/elastic_apm/context.rb
93
113
  - lib/elastic_apm/context/request.rb
94
114
  - lib/elastic_apm/context/request/socket.rb
@@ -111,6 +131,7 @@ files:
111
131
  - lib/elastic_apm/metadata/system_info/container_info.rb
112
132
  - lib/elastic_apm/metrics.rb
113
133
  - lib/elastic_apm/metrics/cpu_mem.rb
134
+ - lib/elastic_apm/metrics/vm.rb
114
135
  - lib/elastic_apm/metricset.rb
115
136
  - lib/elastic_apm/middleware.rb
116
137
  - lib/elastic_apm/naively_hashable.rb
@@ -120,6 +141,7 @@ files:
120
141
  - lib/elastic_apm/normalizers/action_view.rb
121
142
  - lib/elastic_apm/normalizers/active_record.rb
122
143
  - lib/elastic_apm/opentracing.rb
144
+ - lib/elastic_apm/rails.rb
123
145
  - lib/elastic_apm/railtie.rb
124
146
  - lib/elastic_apm/span.rb
125
147
  - lib/elastic_apm/span/context.rb
@@ -1,280 +0,0 @@
1
- #!/usr/bin/env groovy
2
- @Library('apm@current') _
3
-
4
- import co.elastic.matrix.*
5
- import groovy.transform.Field
6
-
7
- /**
8
- This is the parallel tasks generator,
9
- it is need as field to store the results of the tests.
10
- */
11
- @Field def rubyTasksGen
12
-
13
- pipeline {
14
- agent any
15
- environment {
16
- BASE_DIR="src/github.com/elastic/apm-agent-ruby"
17
- PIPELINE_LOG_LEVEL='INFO'
18
- NOTIFY_TO = credentials('notify-to')
19
- JOB_GCS_BUCKET = credentials('gcs-bucket')
20
- CODECOV_SECRET = 'secret/apm-team/ci/apm-agent-ruby-codecov'
21
- DOCKER_REGISTRY = 'docker.elastic.co'
22
- DOCKER_SECRET = 'secret/apm-team/ci/docker-registry/prod'
23
- }
24
- options {
25
- timeout(time: 2, unit: 'HOURS')
26
- buildDiscarder(logRotator(numToKeepStr: '20', artifactNumToKeepStr: '20', daysToKeepStr: '30'))
27
- timestamps()
28
- ansiColor('xterm')
29
- disableResume()
30
- durabilityHint('PERFORMANCE_OPTIMIZED')
31
- rateLimitBuilds(throttle: [count: 60, durationName: 'hour', userBoost: true])
32
- quietPeriod(10)
33
- }
34
- triggers {
35
- issueCommentTrigger('(?i).*(?:jenkins\\W+)?run\\W+(?:the\\W+)?tests(?:\\W+please)?.*')
36
- }
37
- parameters {
38
- booleanParam(name: 'Run_As_Master_Branch', defaultValue: false, description: 'Allow to run any steps on a PR, some steps normally only run on master branch.')
39
- booleanParam(name: 'doc_ci', defaultValue: true, description: 'Enable build docs.')
40
- booleanParam(name: 'bench_ci', defaultValue: true, description: 'Enable run benchmarks.')
41
- }
42
- stages {
43
- /**
44
- Checkout the code and stash it, to use it on other stages.
45
- */
46
- stage('Checkout') {
47
- agent { label 'master || immutable' }
48
- options { skipDefaultCheckout() }
49
- steps {
50
- deleteDir()
51
- gitCheckout(basedir: "${BASE_DIR}")
52
- stash allowEmpty: true, name: 'source', useDefaultExcludes: false
53
- }
54
- }
55
- /**
56
- Execute unit tests.
57
- */
58
- stage('Test') {
59
- agent { label 'linux && immutable' }
60
- options { skipDefaultCheckout() }
61
- steps {
62
- deleteDir()
63
- unstash "source"
64
- dir("${BASE_DIR}"){
65
- script {
66
- rubyTasksGen = new RubyParallelTaskGenerator(
67
- xKey: 'RUBY_VERSION',
68
- yKey: 'FRAMEWORK',
69
- xFile: "./spec/.jenkins_ruby.yml",
70
- yFile: "./spec/.jenkins_framework.yml",
71
- exclusionFile: "./spec/.jenkins_exclude.yml",
72
- tag: "Ruby",
73
- name: "Ruby",
74
- steps: this
75
- )
76
- def mapPatallelTasks = rubyTasksGen.generateParallelTests()
77
- parallel(mapPatallelTasks)
78
- }
79
- }
80
- }
81
- }
82
- stage('Benchmarks') {
83
- options { skipDefaultCheckout() }
84
- when {
85
- beforeAgent true
86
- allOf {
87
- anyOf {
88
- branch 'master'
89
- branch "\\d+\\.\\d+"
90
- branch "v\\d?"
91
- tag "v\\d+\\.\\d+\\.\\d+*"
92
- expression { return params.Run_As_Master_Branch }
93
- }
94
- expression { return params.bench_ci }
95
- }
96
- }
97
- stages {
98
- stage('Clean Workspace') {
99
- agent { label 'metal' }
100
- steps {
101
- echo "Cleaning Workspace"
102
- }
103
- post {
104
- always {
105
- cleanWs()
106
- }
107
- }
108
- }
109
- /**
110
- Run the benchmarks and store the results on ES.
111
- The result JSON files are also archive into Jenkins.
112
- */
113
- stage('Run Benchmarks') {
114
- agent { label 'linux && immutable' }
115
- steps {
116
- deleteDir()
117
- unstash 'source'
118
- dir("${BASE_DIR}"){
119
- script {
120
- def versions = readYaml(file: "./spec/.jenkins_ruby.yml")
121
- def benchmarkTask = [:]
122
- versions['RUBY_VERSION'].each{ v ->
123
- benchmarkTask[v] = runBenchmark(v)
124
- }
125
- parallel(benchmarkTask)
126
- }
127
- }
128
- }
129
- }
130
- }
131
- }
132
- /**
133
- Build the documentation.
134
- */
135
- stage('Documentation') {
136
- agent { label 'linux && immutable' }
137
- options { skipDefaultCheckout() }
138
- when {
139
- beforeAgent true
140
- allOf {
141
- anyOf {
142
- branch 'master'
143
- branch "\\d+\\.\\d+"
144
- branch "v\\d?"
145
- tag "v\\d+\\.\\d+\\.\\d+*"
146
- expression { return params.Run_As_Master_Branch }
147
- }
148
- expression { return params.doc_ci }
149
- }
150
- }
151
- steps {
152
- deleteDir()
153
- unstash 'source'
154
- buildDocs(docsDir: "${BASE_DIR}/docs", archive: true)
155
- }
156
- }
157
- }
158
- post {
159
- always{
160
- script{
161
- if(rubyTasksGen?.results){
162
- writeJSON(file: 'results.json', json: toJSON(rubyTasksGen.results), pretty: 2)
163
- def mapResults = ["Ruby": rubyTasksGen.results]
164
- def processor = new ResultsProcessor()
165
- processor.processResults(mapResults)
166
- archiveArtifacts allowEmptyArchive: true, artifacts: 'results.json,results.html', defaultExcludes: false
167
- }
168
- }
169
- }
170
- success {
171
- echoColor(text: '[SUCCESS]', colorfg: 'green', colorbg: 'default')
172
- }
173
- aborted {
174
- echoColor(text: '[ABORTED]', colorfg: 'magenta', colorbg: 'default')
175
- }
176
- failure {
177
- echoColor(text: '[FAILURE]', colorfg: 'red', colorbg: 'default')
178
- step([$class: 'Mailer', notifyEveryUnstableBuild: true, recipients: "${NOTIFY_TO}", sendToIndividuals: false])
179
- }
180
- unstable {
181
- echoColor(text: '[UNSTABLE]', colorfg: 'yellow', colorbg: 'default')
182
- }
183
- }
184
- }
185
-
186
- /**
187
- Parallel task generator for the integration tests.
188
- */
189
- class RubyParallelTaskGenerator extends DefaultParallelTaskGenerator {
190
-
191
- public RubyParallelTaskGenerator(Map params){
192
- super(params)
193
- }
194
-
195
- /**
196
- build a clousure that launch and agent and execute the corresponding test script,
197
- then store the results.
198
- */
199
- public Closure generateStep(x, y){
200
- return {
201
- steps.sleep steps.randomNumber(min:10, max: 30)
202
- steps.node('linux && immutable'){
203
- // Label is transformed to avoid using the internal docker registry in the x coordinate
204
- // TODO: def label = "${tag}:${x?.drop(x?.lastIndexOf('/')+1)}#${y}"
205
- def label = "${tag}:${x}#${y}"
206
- try {
207
- steps.runScript(label: label, ruby: x, framework: y)
208
- saveResult(x, y, 1)
209
- } catch(e){
210
- saveResult(x, y, 0)
211
- steps.error("${label} tests failed : ${e.toString()}\n")
212
- } finally {
213
- steps.junit(allowEmptyResults: false,
214
- keepLongStdio: true,
215
- testResults: "**/spec/ruby-agent-junit.xml")
216
- steps.codecov(repo: 'apm-agent-ruby', basedir: "${steps.env.BASE_DIR}",
217
- secret: "${steps.env.CODECOV_SECRET}")
218
- }
219
- }
220
- }
221
- }
222
- }
223
-
224
- /**
225
- Run tests for a Ruby version and framework version.
226
- */
227
- def runScript(Map params = [:]){
228
- def label = params.label
229
- def ruby = params.ruby
230
- def framework = params.framework
231
- log(level: 'INFO', text: "${label}")
232
- env.HOME = "${env.WORKSPACE}"
233
- env.PATH = "${env.PATH}:${env.WORKSPACE}/bin"
234
- deleteDir()
235
- unstash 'source'
236
- dir("${BASE_DIR}"){
237
- retry(2){
238
- sleep randomNumber(min:10, max: 30)
239
- dockerLogin(secret: "${DOCKER_SECRET}", registry: "${DOCKER_REGISTRY}")
240
- sh("./spec/scripts/spec.sh ${ruby} ${framework}")
241
- }
242
- }
243
- }
244
-
245
- /**
246
- Run benchmarks for a Ruby version, then report the results to the Elasticsearch server.
247
- */
248
- def runBenchmark(version){
249
- return {
250
- node('metal'){
251
- // Transform the versions like:
252
- // - docker.elastic.co/observability-ci/jruby:9.2-12-jdk to jruby-9.2-12-jdk
253
- // - jruby:9.1 to jruby-9.1
254
- def transformedVersion = version.replaceAll('.*/', '').replaceAll(':', '-')
255
- env.HOME = "${env.WORKSPACE}/${transformedVersion}"
256
- dir("${transformedVersion}"){
257
- deleteDir()
258
- unstash 'source'
259
- dir("${BASE_DIR}"){
260
- retry(2){
261
- sleep randomNumber(min:10, max: 30)
262
- dockerLogin(secret: "${DOCKER_SECRET}", registry: "${DOCKER_REGISTRY}")
263
- }
264
- try{
265
- sh "./spec/scripts/benchmarks.sh ${version}"
266
- } catch(e){
267
- throw e
268
- } finally {
269
- archiveArtifacts(
270
- allowEmptyArchive: true,
271
- artifacts: "**/benchmark-${transformedVersion}.raw,**/benchmark-${transformedVersion}.error",
272
- onlyIfSuccessful: false)
273
- sendBenchmarks(file: "benchmark-${transformedVersion}.bulk",
274
- index: "benchmark-ruby", archive: true)
275
- }
276
- }
277
- }
278
- }
279
- }
280
- }