datadog-ci 0.1.1 → 0.2.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/CHANGELOG.md +14 -1
- data/LICENSE-3rdparty.csv +1 -0
- data/README.md +64 -0
- data/lib/datadog/ci/configuration/components.rb +51 -5
- data/lib/datadog/ci/configuration/settings.rb +36 -8
- data/lib/datadog/ci/contrib/cucumber/configuration/settings.rb +2 -3
- data/lib/datadog/ci/contrib/cucumber/formatter.rb +8 -10
- data/lib/datadog/ci/contrib/cucumber/integration.rb +3 -5
- data/lib/datadog/ci/contrib/integration.rb +149 -0
- data/lib/datadog/ci/contrib/minitest/configuration/settings.rb +2 -3
- data/lib/datadog/ci/contrib/minitest/hooks.rb +8 -4
- data/lib/datadog/ci/contrib/minitest/integration.rb +3 -5
- data/lib/datadog/ci/contrib/rspec/configuration/settings.rb +2 -3
- data/lib/datadog/ci/contrib/rspec/example.rb +5 -8
- data/lib/datadog/ci/contrib/rspec/integration.rb +3 -5
- data/lib/datadog/ci/contrib/settings.rb +33 -0
- data/lib/datadog/ci/ext/environment/providers/local_git.rb +7 -0
- data/lib/datadog/ci/ext/settings.rb +2 -0
- data/lib/datadog/ci/ext/transport.rb +19 -0
- data/lib/datadog/ci/{test.rb → recorder.rb} +6 -5
- data/lib/datadog/ci/test_visibility/flush.rb +40 -0
- data/lib/datadog/ci/test_visibility/serializers/base.rb +161 -0
- data/lib/datadog/ci/test_visibility/serializers/factories/test_level.rb +30 -0
- data/lib/datadog/ci/test_visibility/serializers/span.rb +51 -0
- data/lib/datadog/ci/test_visibility/serializers/test_v1.rb +60 -0
- data/lib/datadog/ci/test_visibility/transport.rb +169 -0
- data/lib/datadog/ci/transport/gzip.rb +20 -0
- data/lib/datadog/ci/transport/http.rb +153 -0
- data/lib/datadog/ci/version.rb +2 -2
- data/sig/datadog/ci/configuration/components.rbs +2 -0
- data/sig/datadog/ci/configuration/settings.rbs +2 -0
- data/sig/datadog/ci/contrib/cucumber/configuration/settings.rbs +1 -1
- data/sig/datadog/ci/contrib/cucumber/integration.rbs +2 -1
- data/sig/datadog/ci/contrib/integration.rbs +44 -0
- data/sig/datadog/ci/contrib/minitest/configuration/settings.rbs +1 -1
- data/sig/datadog/ci/contrib/minitest/integration.rbs +4 -3
- data/sig/datadog/ci/contrib/rspec/configuration/settings.rbs +1 -1
- data/sig/datadog/ci/contrib/rspec/integration.rbs +3 -2
- data/sig/datadog/ci/contrib/settings.rbs +25 -0
- data/sig/datadog/ci/ext/settings.rbs +2 -0
- data/sig/datadog/ci/ext/transport.rbs +21 -0
- data/sig/datadog/ci/{test.rbs → recorder.rbs} +1 -1
- data/sig/datadog/ci/test_visibility/flush.rbs +17 -0
- data/sig/datadog/ci/test_visibility/serializers/base.rbs +73 -0
- data/sig/datadog/ci/test_visibility/serializers/factories/test_level.rbs +13 -0
- data/sig/datadog/ci/test_visibility/serializers/span.rbs +18 -0
- data/sig/datadog/ci/test_visibility/serializers/test_v1.rbs +23 -0
- data/sig/datadog/ci/test_visibility/transport.rbs +39 -0
- data/sig/datadog/ci/transport/gzip.rbs +9 -0
- data/sig/datadog/ci/transport/http.rbs +61 -0
- metadata +41 -7
- data/lib/datadog/ci/flush.rb +0 -38
- data/sig/datadog/ci/flush.rbs +0 -15
@@ -0,0 +1,33 @@
|
|
1
|
+
require "datadog/core/configuration/base"
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module CI
|
5
|
+
module Contrib
|
6
|
+
# Common settings for all integrations
|
7
|
+
# @public_api
|
8
|
+
class Settings
|
9
|
+
include Core::Configuration::Base
|
10
|
+
|
11
|
+
option :enabled, default: true
|
12
|
+
option :service_name
|
13
|
+
option :operation_name
|
14
|
+
|
15
|
+
def configure(options = {})
|
16
|
+
self.class.options.each do |name, _value|
|
17
|
+
self[name] = options[name] if options.key?(name)
|
18
|
+
end
|
19
|
+
|
20
|
+
yield(self) if block_given?
|
21
|
+
end
|
22
|
+
|
23
|
+
def [](name)
|
24
|
+
respond_to?(name) ? send(name) : get_option(name)
|
25
|
+
end
|
26
|
+
|
27
|
+
def []=(name, value)
|
28
|
+
respond_to?("#{name}=") ? send("#{name}=", value) : set_option(name, value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -97,6 +97,13 @@ module Datadog
|
|
97
97
|
|
98
98
|
raise "Failed to run git command #{cmd}: #{out}" unless status.success?
|
99
99
|
|
100
|
+
# Sometimes Encoding.default_external is somehow set to US-ASCII which breaks
|
101
|
+
# commit messages with UTF-8 characters like emojis
|
102
|
+
# We force output's encoding to be UTF-8 in this case
|
103
|
+
# This is safe to do as UTF-8 is compatible with US-ASCII
|
104
|
+
if Encoding.default_external == Encoding::US_ASCII
|
105
|
+
out = out.force_encoding(Encoding::UTF_8)
|
106
|
+
end
|
100
107
|
out.strip! # There's always a "\n" at the end of the command output
|
101
108
|
|
102
109
|
return nil if out.empty?
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module CI
|
5
|
+
module Ext
|
6
|
+
module Transport
|
7
|
+
HEADER_DD_API_KEY = "DD-API-KEY"
|
8
|
+
HEADER_CONTENT_TYPE = "Content-Type"
|
9
|
+
HEADER_CONTENT_ENCODING = "Content-Encoding"
|
10
|
+
|
11
|
+
TEST_VISIBILITY_INTAKE_HOST_PREFIX = "citestcycle-intake"
|
12
|
+
TEST_VISIBILITY_INTAKE_PATH = "/api/v2/citestcycle"
|
13
|
+
|
14
|
+
CONTENT_TYPE_MESSAGEPACK = "application/msgpack"
|
15
|
+
CONTENT_ENCODING_GZIP = "gzip"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "datadog/tracing"
|
3
4
|
require "datadog/tracing/contrib/analytics"
|
4
5
|
|
5
6
|
require_relative "ext/app_types"
|
@@ -11,7 +12,7 @@ require "rbconfig"
|
|
11
12
|
module Datadog
|
12
13
|
module CI
|
13
14
|
# Common behavior for CI tests
|
14
|
-
module
|
15
|
+
module Recorder
|
15
16
|
# Creates a new span for a CI test
|
16
17
|
def self.trace(span_name, options = {})
|
17
18
|
span_options = {
|
@@ -19,13 +20,13 @@ module Datadog
|
|
19
20
|
}.merge(options[:span_options] || {})
|
20
21
|
|
21
22
|
if block_given?
|
22
|
-
Tracing.trace(span_name, **span_options) do |span, trace|
|
23
|
+
::Datadog::Tracing.trace(span_name, **span_options) do |span, trace|
|
23
24
|
set_tags!(trace, span, options)
|
24
25
|
yield(span, trace)
|
25
26
|
end
|
26
27
|
else
|
27
|
-
span = Tracing.trace(span_name, **span_options)
|
28
|
-
trace = Tracing.active_trace
|
28
|
+
span = ::Datadog::Tracing.trace(span_name, **span_options)
|
29
|
+
trace = ::Datadog::Tracing.active_trace
|
29
30
|
set_tags!(trace, span, options)
|
30
31
|
span
|
31
32
|
end
|
@@ -37,7 +38,7 @@ module Datadog
|
|
37
38
|
|
38
39
|
# Set default tags
|
39
40
|
trace.origin = Ext::Test::CONTEXT_ORIGIN if trace
|
40
|
-
Datadog::Tracing::Contrib::Analytics.set_measured(span)
|
41
|
+
::Datadog::Tracing::Contrib::Analytics.set_measured(span)
|
41
42
|
span.set_tag(Ext::Test::TAG_SPAN_KIND, Ext::AppTypes::TYPE_TEST)
|
42
43
|
|
43
44
|
# Set environment tags
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "datadog/tracing/metadata/ext"
|
4
|
+
require "datadog/tracing/flush"
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module CI
|
8
|
+
module TestVisibility
|
9
|
+
module Flush
|
10
|
+
# Common behavior for CI flushing
|
11
|
+
module Tagging
|
12
|
+
# Decorate a trace with CI tags
|
13
|
+
def get_trace(trace_op)
|
14
|
+
trace = trace_op.flush!
|
15
|
+
|
16
|
+
# Origin tag is required on every span
|
17
|
+
trace.spans.each do |span|
|
18
|
+
span.set_tag(
|
19
|
+
Tracing::Metadata::Ext::Distributed::TAG_ORIGIN,
|
20
|
+
trace.origin
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
trace
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Consumes only completed traces (where all spans have finished)
|
29
|
+
class Finished < Tracing::Flush::Finished
|
30
|
+
prepend Tagging
|
31
|
+
end
|
32
|
+
|
33
|
+
# Performs partial trace flushing to avoid large traces residing in memory for too long
|
34
|
+
class Partial < Tracing::Flush::Partial
|
35
|
+
prepend Tagging
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Datadog
|
4
|
+
module CI
|
5
|
+
module TestVisibility
|
6
|
+
module Serializers
|
7
|
+
class Base
|
8
|
+
MINIMUM_TIMESTAMP_NANO = 946684800000000000
|
9
|
+
MINIMUM_DURATION_NANO = 0
|
10
|
+
MAXIMUM_DURATION_NANO = 9223372036854775807
|
11
|
+
|
12
|
+
attr_reader :trace, :span
|
13
|
+
|
14
|
+
def initialize(trace, span)
|
15
|
+
@trace = trace
|
16
|
+
@span = span
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_msgpack(packer = nil)
|
20
|
+
packer ||= MessagePack::Packer.new
|
21
|
+
|
22
|
+
packer.write_map_header(3)
|
23
|
+
|
24
|
+
write_field(packer, "type")
|
25
|
+
write_field(packer, "version")
|
26
|
+
|
27
|
+
packer.write("content")
|
28
|
+
packer.write_map_header(content_map_size)
|
29
|
+
|
30
|
+
content_fields.each do |field|
|
31
|
+
if field.is_a?(Hash)
|
32
|
+
field.each do |field_name, method|
|
33
|
+
write_field(packer, field_name, method)
|
34
|
+
end
|
35
|
+
else
|
36
|
+
write_field(packer, field)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# validates according to citestcycle json schema
|
42
|
+
def valid?
|
43
|
+
required_fields_present? && valid_start_time? && valid_duration?
|
44
|
+
end
|
45
|
+
|
46
|
+
def content_fields
|
47
|
+
[]
|
48
|
+
end
|
49
|
+
|
50
|
+
def content_map_size
|
51
|
+
0
|
52
|
+
end
|
53
|
+
|
54
|
+
def runtime_id
|
55
|
+
@trace.runtime_id
|
56
|
+
end
|
57
|
+
|
58
|
+
def trace_id
|
59
|
+
@trace.id
|
60
|
+
end
|
61
|
+
|
62
|
+
def span_id
|
63
|
+
@span.id
|
64
|
+
end
|
65
|
+
|
66
|
+
def parent_id
|
67
|
+
@span.parent_id
|
68
|
+
end
|
69
|
+
|
70
|
+
def type
|
71
|
+
end
|
72
|
+
|
73
|
+
def version
|
74
|
+
1
|
75
|
+
end
|
76
|
+
|
77
|
+
def span_type
|
78
|
+
@span.type
|
79
|
+
end
|
80
|
+
|
81
|
+
def name
|
82
|
+
@span.name
|
83
|
+
end
|
84
|
+
|
85
|
+
def resource
|
86
|
+
@span.resource
|
87
|
+
end
|
88
|
+
|
89
|
+
def service
|
90
|
+
@span.service
|
91
|
+
end
|
92
|
+
|
93
|
+
def start
|
94
|
+
@start ||= time_nano(@span.start_time)
|
95
|
+
end
|
96
|
+
|
97
|
+
def duration
|
98
|
+
@duration ||= duration_nano(@span.duration)
|
99
|
+
end
|
100
|
+
|
101
|
+
def meta
|
102
|
+
@span.meta
|
103
|
+
end
|
104
|
+
|
105
|
+
def metrics
|
106
|
+
@span.metrics
|
107
|
+
end
|
108
|
+
|
109
|
+
def error
|
110
|
+
@span.status
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.calculate_content_map_size(fields_list)
|
114
|
+
fields_list.reduce(0) do |size, field|
|
115
|
+
if field.is_a?(Hash)
|
116
|
+
size + field.size
|
117
|
+
else
|
118
|
+
size + 1
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def valid_start_time?
|
126
|
+
!start.nil? && start >= MINIMUM_TIMESTAMP_NANO
|
127
|
+
end
|
128
|
+
|
129
|
+
def valid_duration?
|
130
|
+
!duration.nil? && duration >= MINIMUM_DURATION_NANO && duration <= MAXIMUM_DURATION_NANO
|
131
|
+
end
|
132
|
+
|
133
|
+
def required_fields_present?
|
134
|
+
required_fields.all? { |field| !send(field).nil? }
|
135
|
+
end
|
136
|
+
|
137
|
+
def required_fields
|
138
|
+
[]
|
139
|
+
end
|
140
|
+
|
141
|
+
def write_field(packer, field_name, method = nil)
|
142
|
+
method ||= field_name
|
143
|
+
|
144
|
+
packer.write(field_name)
|
145
|
+
packer.write(send(method))
|
146
|
+
end
|
147
|
+
|
148
|
+
# in nanoseconds since Epoch
|
149
|
+
def time_nano(time)
|
150
|
+
time.to_i * 1000000000 + time.nsec
|
151
|
+
end
|
152
|
+
|
153
|
+
# in nanoseconds
|
154
|
+
def duration_nano(duration)
|
155
|
+
(duration * 1e9).to_i
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../test_v1"
|
4
|
+
require_relative "../span"
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module CI
|
8
|
+
module TestVisibility
|
9
|
+
module Serializers
|
10
|
+
module Factories
|
11
|
+
# This factory takes care of creating citestcycle serializers when test-level visibility is enabled
|
12
|
+
# NOTE: citestcycle is a protocol Datadog uses to submit test execution tracing information to CI visibility
|
13
|
+
# backend
|
14
|
+
module TestLevel
|
15
|
+
module_function
|
16
|
+
|
17
|
+
def serializer(trace, span)
|
18
|
+
case span.type
|
19
|
+
when Datadog::CI::Ext::AppTypes::TYPE_TEST
|
20
|
+
Serializers::TestV1.new(trace, span)
|
21
|
+
else
|
22
|
+
Serializers::Span.new(trace, span)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module CI
|
7
|
+
module TestVisibility
|
8
|
+
module Serializers
|
9
|
+
class Span < Base
|
10
|
+
CONTENT_FIELDS = [
|
11
|
+
"trace_id", "span_id", "parent_id",
|
12
|
+
"name", "resource", "service",
|
13
|
+
"error", "start", "duration",
|
14
|
+
"meta", "metrics",
|
15
|
+
"type" => "span_type"
|
16
|
+
].freeze
|
17
|
+
|
18
|
+
CONTENT_MAP_SIZE = calculate_content_map_size(CONTENT_FIELDS)
|
19
|
+
|
20
|
+
REQUIRED_FIELDS = [
|
21
|
+
"trace_id",
|
22
|
+
"span_id",
|
23
|
+
"error",
|
24
|
+
"name",
|
25
|
+
"resource",
|
26
|
+
"start",
|
27
|
+
"duration"
|
28
|
+
].freeze
|
29
|
+
|
30
|
+
def content_fields
|
31
|
+
CONTENT_FIELDS
|
32
|
+
end
|
33
|
+
|
34
|
+
def content_map_size
|
35
|
+
CONTENT_MAP_SIZE
|
36
|
+
end
|
37
|
+
|
38
|
+
def type
|
39
|
+
"span"
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def required_fields
|
45
|
+
REQUIRED_FIELDS
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
require_relative "../../ext/test"
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module CI
|
8
|
+
module TestVisibility
|
9
|
+
module Serializers
|
10
|
+
class TestV1 < Base
|
11
|
+
CONTENT_FIELDS = [
|
12
|
+
"trace_id", "span_id",
|
13
|
+
"name", "resource", "service",
|
14
|
+
"error", "start", "duration",
|
15
|
+
"meta", "metrics",
|
16
|
+
"type" => "span_type"
|
17
|
+
].freeze
|
18
|
+
|
19
|
+
CONTENT_MAP_SIZE = calculate_content_map_size(CONTENT_FIELDS)
|
20
|
+
|
21
|
+
REQUIRED_FIELDS = [
|
22
|
+
"trace_id",
|
23
|
+
"span_id",
|
24
|
+
"error",
|
25
|
+
"name",
|
26
|
+
"resource",
|
27
|
+
"start",
|
28
|
+
"duration"
|
29
|
+
].freeze
|
30
|
+
|
31
|
+
def content_fields
|
32
|
+
CONTENT_FIELDS
|
33
|
+
end
|
34
|
+
|
35
|
+
def content_map_size
|
36
|
+
CONTENT_MAP_SIZE
|
37
|
+
end
|
38
|
+
|
39
|
+
def type
|
40
|
+
"test"
|
41
|
+
end
|
42
|
+
|
43
|
+
def name
|
44
|
+
"#{@span.get_tag(Ext::Test::TAG_FRAMEWORK)}.test"
|
45
|
+
end
|
46
|
+
|
47
|
+
def resource
|
48
|
+
"#{@span.get_tag(Ext::Test::TAG_SUITE)}.#{@span.get_tag(Ext::Test::TAG_NAME)}"
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def required_fields
|
54
|
+
REQUIRED_FIELDS
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "msgpack"
|
4
|
+
require "uri"
|
5
|
+
|
6
|
+
require "datadog/core/encoding"
|
7
|
+
require "datadog/core/environment/identity"
|
8
|
+
require "datadog/core/chunker"
|
9
|
+
|
10
|
+
require_relative "serializers/factories/test_level"
|
11
|
+
require_relative "../ext/transport"
|
12
|
+
require_relative "../transport/http"
|
13
|
+
|
14
|
+
module Datadog
|
15
|
+
module CI
|
16
|
+
module TestVisibility
|
17
|
+
class Transport
|
18
|
+
# CI test cycle intake's limit is 5.1MB uncompressed
|
19
|
+
# We will use a bit more conservative value 5MB
|
20
|
+
DEFAULT_MAX_PAYLOAD_SIZE = 5 * 1024 * 1024
|
21
|
+
|
22
|
+
attr_reader :serializers_factory,
|
23
|
+
:api_key,
|
24
|
+
:max_payload_size,
|
25
|
+
:http,
|
26
|
+
:env
|
27
|
+
|
28
|
+
def initialize(
|
29
|
+
api_key:,
|
30
|
+
url:,
|
31
|
+
env: nil,
|
32
|
+
serializers_factory: Datadog::CI::TestVisibility::Serializers::Factories::TestLevel,
|
33
|
+
max_payload_size: DEFAULT_MAX_PAYLOAD_SIZE
|
34
|
+
)
|
35
|
+
@serializers_factory = serializers_factory
|
36
|
+
@api_key = api_key
|
37
|
+
@max_payload_size = max_payload_size
|
38
|
+
@env = env
|
39
|
+
|
40
|
+
uri = URI.parse(url)
|
41
|
+
|
42
|
+
raise "Invalid agentless mode URL: #{url}" if uri.host.nil?
|
43
|
+
|
44
|
+
@http = Datadog::CI::Transport::HTTP.new(
|
45
|
+
host: uri.host,
|
46
|
+
port: uri.port,
|
47
|
+
ssl: uri.scheme == "https" || uri.port == 443,
|
48
|
+
compress: true
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def send_traces(traces)
|
53
|
+
return [] if traces.nil? || traces.empty?
|
54
|
+
|
55
|
+
Datadog.logger.debug { "Sending #{traces.count} traces..." }
|
56
|
+
|
57
|
+
encoded_events = encode_traces(traces)
|
58
|
+
if encoded_events.empty?
|
59
|
+
Datadog.logger.debug { "Empty encoded events list, skipping send" }
|
60
|
+
return []
|
61
|
+
end
|
62
|
+
|
63
|
+
responses = []
|
64
|
+
Datadog::Core::Chunker.chunk_by_size(encoded_events, max_payload_size).map do |chunk|
|
65
|
+
encoded_payload = pack_events(chunk)
|
66
|
+
Datadog.logger.debug do
|
67
|
+
"Send chunk of #{chunk.count} events; payload size #{encoded_payload.size}"
|
68
|
+
end
|
69
|
+
|
70
|
+
response = send_payload(encoded_payload)
|
71
|
+
|
72
|
+
Datadog.logger.debug do
|
73
|
+
"Received server response: #{response.inspect}"
|
74
|
+
end
|
75
|
+
|
76
|
+
responses << response
|
77
|
+
end
|
78
|
+
|
79
|
+
responses
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def send_payload(encoded_payload)
|
85
|
+
http.request(
|
86
|
+
path: Datadog::CI::Ext::Transport::TEST_VISIBILITY_INTAKE_PATH,
|
87
|
+
payload: encoded_payload,
|
88
|
+
headers: {
|
89
|
+
Ext::Transport::HEADER_DD_API_KEY => api_key,
|
90
|
+
Ext::Transport::HEADER_CONTENT_TYPE => Ext::Transport::CONTENT_TYPE_MESSAGEPACK
|
91
|
+
}
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
def encode_traces(traces)
|
96
|
+
traces.flat_map do |trace|
|
97
|
+
spans = trace.spans
|
98
|
+
# TODO: remove condition when 1.0 is released
|
99
|
+
if spans.respond_to?(:filter_map)
|
100
|
+
spans.filter_map { |span| encode_span(trace, span) }
|
101
|
+
else
|
102
|
+
trace.spans.map { |span| encode_span(trace, span) }.reject(&:nil?)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def encode_span(trace, span)
|
108
|
+
serializer = serializers_factory.serializer(trace, span)
|
109
|
+
|
110
|
+
if serializer.valid?
|
111
|
+
encoded = encoder.encode(serializer)
|
112
|
+
|
113
|
+
if encoded.size > max_payload_size
|
114
|
+
# This single event is too large, we can't flush it
|
115
|
+
Datadog.logger.debug { "Dropping test event. Payload too large: '#{span.inspect}'" }
|
116
|
+
Datadog.logger.debug { encoded }
|
117
|
+
|
118
|
+
return nil
|
119
|
+
end
|
120
|
+
|
121
|
+
encoded
|
122
|
+
else
|
123
|
+
Datadog.logger.debug { "Invalid span skipped: #{span}" }
|
124
|
+
nil
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def encoder
|
129
|
+
Datadog::Core::Encoding::MsgpackEncoder
|
130
|
+
end
|
131
|
+
|
132
|
+
def pack_events(encoded_events)
|
133
|
+
packer = MessagePack::Packer.new
|
134
|
+
|
135
|
+
packer.write_map_header(3) # Set header with how many elements in the map
|
136
|
+
|
137
|
+
packer.write("version")
|
138
|
+
packer.write(1)
|
139
|
+
|
140
|
+
packer.write("metadata")
|
141
|
+
packer.write_map_header(1)
|
142
|
+
|
143
|
+
packer.write("*")
|
144
|
+
metadata_fields_count = env ? 4 : 3
|
145
|
+
packer.write_map_header(metadata_fields_count)
|
146
|
+
|
147
|
+
if env
|
148
|
+
packer.write("env")
|
149
|
+
packer.write(env)
|
150
|
+
end
|
151
|
+
|
152
|
+
packer.write("runtime-id")
|
153
|
+
packer.write(Datadog::Core::Environment::Identity.id)
|
154
|
+
|
155
|
+
packer.write("language")
|
156
|
+
packer.write(Datadog::Core::Environment::Identity.lang)
|
157
|
+
|
158
|
+
packer.write("library_version")
|
159
|
+
packer.write(Datadog::CI::VERSION::STRING)
|
160
|
+
|
161
|
+
packer.write("events")
|
162
|
+
packer.write_array_header(encoded_events.size)
|
163
|
+
|
164
|
+
(packer.buffer.to_a + encoded_events).join
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "zlib"
|
4
|
+
require "stringio"
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module CI
|
8
|
+
module Transport
|
9
|
+
module Gzip
|
10
|
+
module_function
|
11
|
+
|
12
|
+
def compress(input)
|
13
|
+
gzip_writer = Zlib::GzipWriter.new(StringIO.new)
|
14
|
+
gzip_writer << input
|
15
|
+
gzip_writer.close.string
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|