Skip to content

Commit ae15d8c

Browse files
Add zstd compression to SAPM receiver and exporter (open-telemetry#23257)
- Updated github.com/signalfx/sapm-proto to v0.13.0 - Added "compression" config setting to sapm exporter - Added tests to verify various compression settings for sapm receiver and exporter.
1 parent c2658a7 commit ae15d8c

File tree

9 files changed

+270
-36
lines changed

9 files changed

+270
-36
lines changed

.chloggen/sapm-exporter-zstd.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Use this changelog template to create an entry for release notes.
2+
# If your change doesn't affect end users, such as a test fix or a tooling change,
3+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
4+
5+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
6+
change_type: enhancement
7+
8+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
9+
component: sapmexporter
10+
11+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
12+
note: sapm exporter now supports `compression` config option to specify either gzip or zstd compression to use.
13+
14+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
15+
issues: [23257]
16+
17+
# (Optional) One or more lines of additional information to render under the primary note.
18+
# These lines will be padded with 2 spaces and then inserted directly into the document.
19+
# Use pipe (|) for multiline entries.
20+
subtext:

.chloggen/sapm-receiver-zstd.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Use this changelog template to create an entry for release notes.
2+
# If your change doesn't affect end users, such as a test fix or a tooling change,
3+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
4+
5+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
6+
change_type: enhancement
7+
8+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
9+
component: sapmreceiver
10+
11+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
12+
note: sapm receiver now accepts requests in compressed with zstd.
13+
14+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
15+
issues: [23257]
16+
17+
# (Optional) One or more lines of additional information to render under the primary note.
18+
# These lines will be padded with 2 spaces and then inserted directly into the document.
19+
# Use pipe (|) for multiline entries.
20+
subtext:

exporter/sapmexporter/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ during final translation. Intended to be used in tandem with identical configur
4848
- `timeout` (default = 5s): Is the timeout for every attempt to send data to the backend.
4949
- `log_detailed_response` (default = `false`): Option to log detailed response from Splunk APM.
5050
In addition to setting this option to `true`, debug logging at the Collector level needs to be enabled.
51+
- `compression`: Compression method to use for outgoing SAPM requests. Can be one of
52+
"gzip", "zstd" or be unspecified. If unspecified then "gzip" compression is used unless
53+
`disable_compression` option is set to true.
54+
- `disable_compression` (default = `false`): If set to true the outgoing requests are not
55+
compressed and `compression` option is ignored.
5156

5257
In addition, this exporter offers queued retry which is enabled by default.
5358
Information about queued retry configuration parameters can be found

exporter/sapmexporter/config.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package sapmexporter // import "github.com/open-telemetry/opentelemetry-collecto
55

66
import (
77
"errors"
8+
"fmt"
89
"net/url"
910

1011
sapmclient "github.com/signalfx/sapm-proto/client"
@@ -35,9 +36,13 @@ type Config struct {
3536
// MaxConnections is used to set a limit to the maximum idle HTTP connection the exporter can keep open.
3637
MaxConnections uint `mapstructure:"max_connections"`
3738

38-
// Disable GZip compression.
39+
// Disable compression. If set to true then Compression field is ignored.
3940
DisableCompression bool `mapstructure:"disable_compression"`
4041

42+
// Compression method to use (gzip or zstd). Ignored if DisableCompression=true.
43+
// If unspecified defaults to gzip.
44+
Compression string `mapstructure:"compression"`
45+
4146
// Log detailed response from trace ingest.
4247
LogDetailedResponse bool `mapstructure:"log_detailed_response"`
4348

@@ -56,6 +61,17 @@ func (c *Config) Validate() error {
5661
if err != nil {
5762
return err
5863
}
64+
65+
switch c.Compression {
66+
// Valid compression methods.
67+
case "", // no compression
68+
string(sapmclient.CompressionMethodGzip),
69+
string(sapmclient.CompressionMethodZstd):
70+
71+
default:
72+
return fmt.Errorf("invalid compression %q", c.Compression)
73+
}
74+
5975
return nil
6076
}
6177

@@ -85,5 +101,9 @@ func (c *Config) clientOptions() []sapmclient.Option {
85101
opts = append(opts, sapmclient.WithDisabledCompression())
86102
}
87103

104+
if c.Compression != "" {
105+
opts = append(opts, sapmclient.WithCompressionMethod(sapmclient.CompressionMethod(c.Compression)))
106+
}
107+
88108
return opts
89109
}

exporter/sapmexporter/config_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ func TestInvalidConfig(t *testing.T) {
101101
invalidURLErr := invalid.Validate()
102102
require.Error(t, invalidURLErr)
103103

104+
invalid = Config{
105+
Endpoint: "http://localhost",
106+
Compression: "nosuchcompression",
107+
}
108+
assert.Error(t, invalid.Validate())
109+
104110
invalid = Config{
105111
Endpoint: "abcd1234",
106112
QueueSettings: exporterhelper.QueueSettings{

exporter/sapmexporter/exporter_test.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@
44
package sapmexporter
55

66
import (
7+
"compress/gzip"
78
"context"
89
"crypto/rand"
910
"fmt"
11+
"io"
1012
"net/http"
1113
"net/http/httptest"
1214
"testing"
1315

1416
"github.com/jaegertracing/jaeger/model"
17+
"github.com/klauspost/compress/zstd"
18+
splunksapm "github.com/signalfx/sapm-proto/gen"
1519
"github.com/stretchr/testify/assert"
1620
"github.com/stretchr/testify/require"
1721
"go.opentelemetry.io/collector/exporter/exportertest"
@@ -210,3 +214,115 @@ func TestSAPMClientTokenUsageAndErrorMarshalling(t *testing.T) {
210214
})
211215
}
212216
}
217+
218+
func decompress(body io.Reader, compression string) ([]byte, error) {
219+
switch compression {
220+
case "":
221+
return io.ReadAll(body)
222+
case "gzip":
223+
reader, err := gzip.NewReader(body)
224+
if err != nil {
225+
return nil, err
226+
}
227+
return io.ReadAll(reader)
228+
case "zstd":
229+
reader, err := zstd.NewReader(body)
230+
if err != nil {
231+
return nil, err
232+
}
233+
return io.ReadAll(reader)
234+
}
235+
return nil, fmt.Errorf("unknown compression %q", compression)
236+
}
237+
238+
func TestCompression(t *testing.T) {
239+
tests := []struct {
240+
name string
241+
configDisableCompression bool
242+
configCompression string
243+
receivedCompression string
244+
}{
245+
{
246+
name: "unspecified config",
247+
configCompression: "",
248+
configDisableCompression: false,
249+
receivedCompression: "gzip",
250+
},
251+
{
252+
name: "gzip",
253+
configCompression: "gzip",
254+
configDisableCompression: false,
255+
receivedCompression: "gzip",
256+
},
257+
{
258+
name: "zstd",
259+
configCompression: "zstd",
260+
configDisableCompression: false,
261+
receivedCompression: "zstd",
262+
},
263+
{
264+
name: "disable compression and unspecified method",
265+
configDisableCompression: true,
266+
configCompression: "",
267+
receivedCompression: "",
268+
},
269+
{
270+
name: "disable compression and specify gzip",
271+
configDisableCompression: true,
272+
configCompression: "gzip",
273+
receivedCompression: "",
274+
},
275+
{
276+
name: "disable compression and specify zstd",
277+
configDisableCompression: true,
278+
configCompression: "zstd",
279+
receivedCompression: "",
280+
},
281+
}
282+
for _, tt := range tests {
283+
tt := tt
284+
t.Run(
285+
tt.name, func(t *testing.T) {
286+
tracesReceived := false
287+
server := httptest.NewServer(
288+
http.HandlerFunc(
289+
func(w http.ResponseWriter, r *http.Request) {
290+
compression := r.Header.Get("Content-Encoding")
291+
assert.EqualValues(t, compression, tt.receivedCompression)
292+
293+
payload, err := decompress(r.Body, compression)
294+
require.NoError(t, err)
295+
296+
var sapm splunksapm.PostSpansRequest
297+
err = sapm.Unmarshal(payload)
298+
require.NoError(t, err)
299+
300+
w.WriteHeader(200)
301+
tracesReceived = true
302+
},
303+
),
304+
)
305+
defer func() {
306+
assert.True(t, tracesReceived, "Test server never received traces.")
307+
}()
308+
defer server.Close()
309+
310+
cfg := &Config{
311+
Endpoint: server.URL,
312+
DisableCompression: tt.configDisableCompression,
313+
Compression: tt.configCompression,
314+
}
315+
params := exportertest.NewNopCreateSettings()
316+
317+
se, err := newSAPMExporter(cfg, params)
318+
assert.Nil(t, err)
319+
assert.NotNil(t, se, "failed to create trace exporter")
320+
321+
trace, testTraceErr := buildTestTrace()
322+
require.NoError(t, testTraceErr)
323+
err = se.pushTraceData(context.Background(), trace)
324+
require.NoError(t, err)
325+
},
326+
)
327+
}
328+
}

exporter/sapmexporter/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.19
55
require (
66
github.com/cenkalti/backoff/v4 v4.2.1
77
github.com/jaegertracing/jaeger v1.41.0
8+
github.com/klauspost/compress v1.16.5
89
github.com/open-telemetry/opentelemetry-collector-contrib/internal/splunk v0.79.0
910
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/batchperresourceattr v0.79.0
1011
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger v0.79.0

receiver/sapmreceiver/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.19
55
require (
66
github.com/gorilla/mux v1.8.0
77
github.com/jaegertracing/jaeger v1.41.0
8+
github.com/klauspost/compress v1.16.5
89
github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.79.0
910
github.com/open-telemetry/opentelemetry-collector-contrib/internal/splunk v0.79.0
1011
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/translator/jaeger v0.79.0
@@ -31,7 +32,6 @@ require (
3132
github.com/golang/protobuf v1.5.3 // indirect
3233
github.com/golang/snappy v0.0.4 // indirect
3334
github.com/json-iterator/go v1.1.12 // indirect
34-
github.com/klauspost/compress v1.16.5 // indirect
3535
github.com/knadh/koanf v1.5.0 // indirect
3636
github.com/mitchellh/copystructure v1.2.0 // indirect
3737
github.com/mitchellh/mapstructure v1.5.0 // indirect

0 commit comments

Comments
 (0)