elastic-apm 3.7.0 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.ci/Jenkinsfile +139 -96
- data/.ci/packer_cache.sh +12 -10
- data/.rspec +0 -1
- data/CHANGELOG.asciidoc +16 -0
- data/Gemfile +2 -1
- data/bin/run-tests +4 -1
- data/docker-compose.yml +2 -0
- data/docs/configuration.asciidoc +37 -0
- data/lib/elastic_apm/config.rb +4 -8
- data/lib/elastic_apm/grpc.rb +2 -2
- data/lib/elastic_apm/metadata/service_info.rb +5 -2
- data/lib/elastic_apm/opentracing.rb +47 -23
- data/lib/elastic_apm/spies.rb +16 -14
- data/lib/elastic_apm/spies/elasticsearch.rb +16 -2
- data/lib/elastic_apm/spies/mongo.rb +1 -1
- data/lib/elastic_apm/spies/net_http.rb +6 -2
- data/lib/elastic_apm/spies/sequel.rb +1 -1
- data/lib/elastic_apm/transport/filters/hash_sanitizer.rb +77 -0
- data/lib/elastic_apm/transport/filters/secrets_filter.rb +12 -56
- data/lib/elastic_apm/transport/serializers/metadata_serializer.rb +27 -20
- data/lib/elastic_apm/version.rb +1 -1
- metadata +3 -3
- data/.ci/downstreamTests.groovy +0 -192
@@ -17,75 +17,31 @@
|
|
17
17
|
|
18
18
|
# frozen_string_literal: true
|
19
19
|
|
20
|
+
require 'elastic_apm/transport/filters/hash_sanitizer'
|
21
|
+
|
20
22
|
module ElasticAPM
|
21
23
|
module Transport
|
22
24
|
module Filters
|
23
25
|
# @api private
|
24
26
|
class SecretsFilter
|
25
|
-
FILTERED = '[FILTERED]'
|
26
|
-
|
27
|
-
KEY_FILTERS = [
|
28
|
-
/passw(or)?d/i,
|
29
|
-
/auth/i,
|
30
|
-
/^pw$/,
|
31
|
-
/secret/i,
|
32
|
-
/token/i,
|
33
|
-
/api[-._]?key/i,
|
34
|
-
/session[-._]?id/i,
|
35
|
-
/(set[-_])?cookie/i
|
36
|
-
].freeze
|
37
|
-
|
38
|
-
VALUE_FILTERS = [
|
39
|
-
# (probably) credit card number
|
40
|
-
/^\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}$/
|
41
|
-
].freeze
|
42
|
-
|
43
27
|
def initialize(config)
|
44
28
|
@config = config
|
45
|
-
@
|
46
|
-
|
47
|
-
|
48
|
-
config.sanitize_field_names
|
29
|
+
@sanitizer = HashSanitizer.new
|
30
|
+
@sanitizer.key_filters += config.custom_key_filters +
|
31
|
+
config.sanitize_field_names
|
49
32
|
end
|
50
33
|
|
51
34
|
def call(payload)
|
52
|
-
strip_from! payload.dig(:transaction, :context, :request, :headers)
|
53
|
-
strip_from! payload.dig(:transaction, :context, :request, :env)
|
54
|
-
strip_from! payload.dig(:transaction, :context, :request, :cookies)
|
55
|
-
strip_from! payload.dig(:transaction, :context, :response, :headers)
|
56
|
-
strip_from! payload.dig(:error, :context, :request, :headers)
|
57
|
-
strip_from! payload.dig(:error, :context, :response, :headers)
|
58
|
-
strip_from! payload.dig(:transaction, :context, :request, :body)
|
35
|
+
@sanitizer.strip_from! payload.dig(:transaction, :context, :request, :headers)
|
36
|
+
@sanitizer.strip_from! payload.dig(:transaction, :context, :request, :env)
|
37
|
+
@sanitizer.strip_from! payload.dig(:transaction, :context, :request, :cookies)
|
38
|
+
@sanitizer.strip_from! payload.dig(:transaction, :context, :response, :headers)
|
39
|
+
@sanitizer.strip_from! payload.dig(:error, :context, :request, :headers)
|
40
|
+
@sanitizer.strip_from! payload.dig(:error, :context, :response, :headers)
|
41
|
+
@sanitizer.strip_from! payload.dig(:transaction, :context, :request, :body)
|
59
42
|
|
60
43
|
payload
|
61
44
|
end
|
62
|
-
|
63
|
-
def strip_from!(obj)
|
64
|
-
return unless obj&.is_a?(Hash)
|
65
|
-
|
66
|
-
obj.each do |k, v|
|
67
|
-
if filter_key?(k)
|
68
|
-
next obj[k] = FILTERED
|
69
|
-
end
|
70
|
-
|
71
|
-
case v
|
72
|
-
when Hash
|
73
|
-
strip_from!(v)
|
74
|
-
when String
|
75
|
-
if filter_value?(v)
|
76
|
-
obj[k] = FILTERED
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def filter_key?(key)
|
83
|
-
@key_filters.any? { |regex| regex.match(key) }
|
84
|
-
end
|
85
|
-
|
86
|
-
def filter_value?(value)
|
87
|
-
VALUE_FILTERS.any? { |regex| regex.match(value) }
|
88
|
-
end
|
89
45
|
end
|
90
46
|
end
|
91
47
|
end
|
@@ -36,27 +36,34 @@ module ElasticAPM
|
|
36
36
|
private
|
37
37
|
|
38
38
|
def build_service(service)
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
39
|
+
base =
|
40
|
+
{
|
41
|
+
name: keyword_field(service.name),
|
42
|
+
environment: keyword_field(service.environment),
|
43
|
+
version: keyword_field(service.version),
|
44
|
+
agent: {
|
45
|
+
name: keyword_field(service.agent.name),
|
46
|
+
version: keyword_field(service.agent.version)
|
47
|
+
},
|
48
|
+
framework: {
|
49
|
+
name: keyword_field(service.framework.name),
|
50
|
+
version: keyword_field(service.framework.version)
|
51
|
+
},
|
52
|
+
language: {
|
53
|
+
name: keyword_field(service.language.name),
|
54
|
+
version: keyword_field(service.language.version)
|
55
|
+
},
|
56
|
+
runtime: {
|
57
|
+
name: keyword_field(service.runtime.name),
|
58
|
+
version: keyword_field(service.runtime.version)
|
59
|
+
}
|
58
60
|
}
|
59
|
-
|
61
|
+
|
62
|
+
if node_name = service.node_name
|
63
|
+
base[:node] = { name: keyword_field(node_name) }
|
64
|
+
end
|
65
|
+
|
66
|
+
base
|
60
67
|
end
|
61
68
|
|
62
69
|
def build_process(process)
|
data/lib/elastic_apm/version.rb
CHANGED
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: 3.
|
4
|
+
version: 3.8.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: 2020-
|
11
|
+
date: 2020-06-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -59,7 +59,6 @@ files:
|
|
59
59
|
- ".ci/docker/jruby/README.md"
|
60
60
|
- ".ci/docker/jruby/run.sh"
|
61
61
|
- ".ci/docker/jruby/test.sh"
|
62
|
-
- ".ci/downstreamTests.groovy"
|
63
62
|
- ".ci/jobs/apm-agent-ruby-downstream.yml"
|
64
63
|
- ".ci/jobs/apm-agent-ruby-linting-mbp.yml"
|
65
64
|
- ".ci/jobs/apm-agent-ruby-mbp.yml"
|
@@ -220,6 +219,7 @@ files:
|
|
220
219
|
- lib/elastic_apm/transport/connection/http.rb
|
221
220
|
- lib/elastic_apm/transport/connection/proxy_pipe.rb
|
222
221
|
- lib/elastic_apm/transport/filters.rb
|
222
|
+
- lib/elastic_apm/transport/filters/hash_sanitizer.rb
|
223
223
|
- lib/elastic_apm/transport/filters/secrets_filter.rb
|
224
224
|
- lib/elastic_apm/transport/headers.rb
|
225
225
|
- lib/elastic_apm/transport/serializers.rb
|
data/.ci/downstreamTests.groovy
DELETED
@@ -1,192 +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 { label 'linux && immutable' }
|
15
|
-
environment {
|
16
|
-
REPO="git@github.com:elastic/apm-agent-ruby.git"
|
17
|
-
BASE_DIR="src/github.com/elastic/apm-agent-ruby"
|
18
|
-
PIPELINE_LOG_LEVEL='INFO'
|
19
|
-
NOTIFY_TO = credentials('notify-to')
|
20
|
-
JOB_GCS_BUCKET = credentials('gcs-bucket')
|
21
|
-
JOB_GIT_CREDENTIALS = "f6c7695a-671e-4f4f-a331-acdce44ff9ba"
|
22
|
-
DOCKER_REGISTRY = 'docker.elastic.co'
|
23
|
-
DOCKER_SECRET = 'secret/apm-team/ci/docker-registry/prod'
|
24
|
-
CODECOV_SECRET = 'secret/apm-team/ci/apm-agent-ruby-codecov'
|
25
|
-
}
|
26
|
-
options {
|
27
|
-
timeout(time: 2, unit: 'HOURS')
|
28
|
-
buildDiscarder(logRotator(numToKeepStr: '300', artifactNumToKeepStr: '20', daysToKeepStr: '30'))
|
29
|
-
timestamps()
|
30
|
-
ansiColor('xterm')
|
31
|
-
disableResume()
|
32
|
-
durabilityHint('PERFORMANCE_OPTIMIZED')
|
33
|
-
rateLimitBuilds(throttle: [count: 60, durationName: 'hour', userBoost: true])
|
34
|
-
quietPeriod(10)
|
35
|
-
}
|
36
|
-
parameters {
|
37
|
-
string(name: 'RUBY_VERSION', defaultValue: "ruby:2.6", description: "Ruby version to test")
|
38
|
-
string(name: 'BRANCH_SPECIFIER', defaultValue: "master", description: "Git branch/tag to use")
|
39
|
-
string(name: 'MERGE_TARGET', defaultValue: "master", description: "Git branch/tag where to merge this code")
|
40
|
-
}
|
41
|
-
stages {
|
42
|
-
/**
|
43
|
-
Checkout the code and stash it, to use it on other stages.
|
44
|
-
*/
|
45
|
-
stage('Checkout') {
|
46
|
-
options { skipDefaultCheckout() }
|
47
|
-
when {
|
48
|
-
beforeAgent true
|
49
|
-
not {
|
50
|
-
tag pattern: 'v\\d+.*', comparator: "REGEXP"
|
51
|
-
}
|
52
|
-
}
|
53
|
-
steps {
|
54
|
-
deleteDir()
|
55
|
-
gitCheckout(basedir: "${BASE_DIR}",
|
56
|
-
branch: "${params.BRANCH_SPECIFIER}",
|
57
|
-
repo: "${REPO}",
|
58
|
-
credentialsId: "${JOB_GIT_CREDENTIALS}",
|
59
|
-
mergeTarget: "${params.MERGE_TARGET}")
|
60
|
-
stash allowEmpty: true, name: 'source', useDefaultExcludes: false
|
61
|
-
}
|
62
|
-
}
|
63
|
-
stage('Checkout tag') {
|
64
|
-
options { skipDefaultCheckout() }
|
65
|
-
when {
|
66
|
-
beforeAgent true
|
67
|
-
tag pattern: 'v\\d+.*', comparator: "REGEXP"
|
68
|
-
}
|
69
|
-
steps {
|
70
|
-
deleteDir()
|
71
|
-
gitCheckout(basedir: "${BASE_DIR}")
|
72
|
-
stash allowEmpty: true, name: 'source', useDefaultExcludes: false
|
73
|
-
}
|
74
|
-
}
|
75
|
-
stage('Test') {
|
76
|
-
options { skipDefaultCheckout() }
|
77
|
-
steps {
|
78
|
-
runTests('.ci/.jenkins_framework.yml')
|
79
|
-
}
|
80
|
-
}
|
81
|
-
stage('Master Test') {
|
82
|
-
options { skipDefaultCheckout() }
|
83
|
-
steps {
|
84
|
-
catchError(buildResult: 'SUCCESS', stageResult: 'UNSTABLE', message: "The tests for the master framework have failed. Let's warn instead.") {
|
85
|
-
runTests('.ci/.jenkins_master_framework.yml')
|
86
|
-
}
|
87
|
-
}
|
88
|
-
}
|
89
|
-
}
|
90
|
-
post {
|
91
|
-
cleanup {
|
92
|
-
script{
|
93
|
-
if(rubyTasksGen?.results){
|
94
|
-
writeJSON(file: 'results.json', json: toJSON(rubyTasksGen.results), pretty: 2)
|
95
|
-
def mapResults = ["Ruby": rubyTasksGen.results]
|
96
|
-
def processor = new ResultsProcessor()
|
97
|
-
processor.processResults(mapResults)
|
98
|
-
archiveArtifacts allowEmptyArchive: true, artifacts: 'results.json,results.html', defaultExcludes: false
|
99
|
-
catchError(buildResult: 'SUCCESS') {
|
100
|
-
def datafile = readFile(file: "results.json")
|
101
|
-
def json = getVaultSecret(secret: 'secret/apm-team/ci/jenkins-stats-cloud')
|
102
|
-
sendDataToElasticsearch(es: json.data.url, data: datafile, restCall: '/jenkins-builds-ruby-test-results/_doc/')
|
103
|
-
}
|
104
|
-
}
|
105
|
-
}
|
106
|
-
notifyBuildResult(prComment: false)
|
107
|
-
}
|
108
|
-
}
|
109
|
-
}
|
110
|
-
|
111
|
-
/**
|
112
|
-
Parallel task generator for the integration tests.
|
113
|
-
*/
|
114
|
-
class RubyParallelTaskGenerator extends DefaultParallelTaskGenerator {
|
115
|
-
|
116
|
-
public RubyParallelTaskGenerator(Map params){
|
117
|
-
super(params)
|
118
|
-
}
|
119
|
-
|
120
|
-
/**
|
121
|
-
build a clousure that launch and agent and execute the corresponding test script,
|
122
|
-
then store the results.
|
123
|
-
*/
|
124
|
-
public Closure generateStep(x, y){
|
125
|
-
return {
|
126
|
-
steps.sleep steps.randomNumber(min:10, max: 30)
|
127
|
-
steps.node('linux && immutable'){
|
128
|
-
// Label is transformed to avoid using the internal docker registry in the x coordinate
|
129
|
-
// TODO: def label = "${tag}:${x?.drop(x?.lastIndexOf('/')+1)}#${y}"
|
130
|
-
def label = "${tag}:${x}#${y}"
|
131
|
-
try {
|
132
|
-
steps.runScript(label: label, ruby: x, framework: y)
|
133
|
-
saveResult(x, y, 1)
|
134
|
-
} catch(e){
|
135
|
-
saveResult(x, y, 0)
|
136
|
-
steps.error("${label} tests failed : ${e.toString()}\n")
|
137
|
-
} finally {
|
138
|
-
steps.junit(allowEmptyResults: true,
|
139
|
-
keepLongStdio: true,
|
140
|
-
testResults: "**/spec/junit-reports/**/ruby-agent-junit.xml")
|
141
|
-
}
|
142
|
-
}
|
143
|
-
}
|
144
|
-
}
|
145
|
-
}
|
146
|
-
/**
|
147
|
-
Run tests for a Ruby version and framework version.
|
148
|
-
*/
|
149
|
-
def runScript(Map params = [:]){
|
150
|
-
def label = params.label
|
151
|
-
def ruby = params.ruby
|
152
|
-
def framework = params.framework
|
153
|
-
log(level: 'INFO', text: "${label}")
|
154
|
-
env.HOME = "${env.WORKSPACE}"
|
155
|
-
env.PATH = "${env.PATH}:${env.WORKSPACE}/bin"
|
156
|
-
deleteDir()
|
157
|
-
unstash 'source'
|
158
|
-
dir("${BASE_DIR}"){
|
159
|
-
retry(2){
|
160
|
-
sleep randomNumber(min:10, max: 30)
|
161
|
-
dockerLogin(secret: "${DOCKER_SECRET}", registry: "${DOCKER_REGISTRY}")
|
162
|
-
sh("./spec/scripts/spec.sh ${ruby} ${framework}")
|
163
|
-
script{
|
164
|
-
archiveArtifacts(artifacts: "coverage/matrix_results/", defaultExcludes: false)
|
165
|
-
}
|
166
|
-
}
|
167
|
-
}
|
168
|
-
}
|
169
|
-
|
170
|
-
/**
|
171
|
-
Run all the tests for the given ruby version and file with the frameworks to test
|
172
|
-
*/
|
173
|
-
def runTests(frameworkFile) {
|
174
|
-
deleteDir()
|
175
|
-
unstash "source"
|
176
|
-
dir("${BASE_DIR}"){
|
177
|
-
script {
|
178
|
-
rubyTasksGen = new RubyParallelTaskGenerator(
|
179
|
-
xVersions: [ "${params.RUBY_VERSION}" ],
|
180
|
-
xKey: 'RUBY_VERSION',
|
181
|
-
yKey: 'FRAMEWORK',
|
182
|
-
yFile: frameworkFile,
|
183
|
-
exclusionFile: '.ci/.jenkins_exclude.yml',
|
184
|
-
tag: 'Ruby',
|
185
|
-
name: 'Ruby',
|
186
|
-
steps: this
|
187
|
-
)
|
188
|
-
def mapParallelTasks = rubyTasksGen.generateParallelTests()
|
189
|
-
parallel(mapParallelTasks)
|
190
|
-
}
|
191
|
-
}
|
192
|
-
}
|