Skip to content

Commit e9cdcd5

Browse files
codesmith14Paulo Janotti
authored and
Paulo Janotti
committed
Add receiver for sapm protocol (#48)
1 parent 056258e commit e9cdcd5

File tree

13 files changed

+1991
-10
lines changed

13 files changed

+1991
-10
lines changed

cmd/otelcontribcol/components.go

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter"
2626
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/stackdriverexporter"
2727
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/collectdreceiver"
28+
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sapmreceiver"
2829
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinscribereceiver"
2930
)
3031

@@ -37,6 +38,7 @@ func components() (config.Factories, error) {
3738

3839
receivers := []receiver.Factory{
3940
&collectdreceiver.Factory{},
41+
&sapmreceiver.Factory{},
4042
&zipkinscribereceiver.Factory{},
4143
}
4244
for _, rcv := range factories.Receivers {

go.mod

+7-8
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,21 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/azure
66

77
replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/collectdreceiver => ./receiver/collectdreceiver
88

9+
replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sapmreceiver => ./receiver/sapmreceiver
10+
911
require (
1012
github.com/client9/misspell v0.3.4
1113
github.com/google/addlicense v0.0.0-20190907113143-be125746c2c4
12-
github.com/onsi/ginkgo v1.10.1 // indirect
13-
github.com/onsi/gomega v1.7.0 // indirect
14-
github.com/open-telemetry/opentelemetry-collector v0.2.1-0.20191126183205-e94dd19191e0
14+
github.com/open-telemetry/opentelemetry-collector v0.2.1-0.20191205151336-8e2473c5e754
1515
github.com/open-telemetry/opentelemetry-collector-contrib/exporter/azuremonitorexporter v0.0.0
1616
github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter v0.0.0-20191203211755-8ae89debd6c5
1717
github.com/open-telemetry/opentelemetry-collector-contrib/exporter/stackdriverexporter v0.0.0-20191126142441-b2a048090ad6
1818
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/collectdreceiver v0.0.0-00010101000000-000000000000
19+
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sapmreceiver v0.0.0
1920
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinscribereceiver v0.0.0-20191126142441-b2a048090ad6
2021
github.com/pavius/impi v0.0.0-20180302134524-c1cbdcb8df2b
21-
github.com/spf13/pflag v1.0.5 // indirect
22-
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392 // indirect
23-
golang.org/x/lint v0.0.0-20190930215403-16217165b5de
24-
golang.org/x/tools v0.0.0-20191119175705-11e13f1c3fd7
25-
gopkg.in/yaml.v2 v2.2.4 // indirect
22+
github.com/pierrec/lz4 v2.0.5+incompatible // indirect
23+
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f
24+
golang.org/x/tools v0.0.0-20191205225056-3393d29bb9fe
2625
honnef.co/go/tools v0.0.1-2019.2.3
2726
)

go.sum

+190-2
Large diffs are not rendered by default.

receiver/sapmreceiver/config.go

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2019, OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package sapmreceiver
16+
17+
import (
18+
"github.com/open-telemetry/opentelemetry-collector/config/configmodels"
19+
)
20+
21+
// Config defines configuration for SAPM receiver.
22+
type Config struct {
23+
configmodels.ReceiverSettings `mapstructure:",squash"`
24+
}

receiver/sapmreceiver/config_test.go

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2019, OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package sapmreceiver
16+
17+
import (
18+
"path"
19+
"testing"
20+
21+
"github.com/open-telemetry/opentelemetry-collector/config"
22+
"github.com/open-telemetry/opentelemetry-collector/config/configmodels"
23+
"github.com/stretchr/testify/assert"
24+
"github.com/stretchr/testify/require"
25+
)
26+
27+
func TestLoadConfig(t *testing.T) {
28+
factories, err := config.ExampleComponents()
29+
assert.Nil(t, err)
30+
31+
factory := &Factory{}
32+
factories.Receivers[typeStr] = factory
33+
cfg, err := config.LoadConfigFile(t, path.Join(".", "testdata", "config.yaml"), factories)
34+
35+
require.NoError(t, err)
36+
require.NotNil(t, cfg)
37+
38+
// The receiver `sapm/disabled` doesn't count because disabled receivers
39+
// are excluded from the final list.
40+
assert.Equal(t, len(cfg.Receivers), 2)
41+
42+
r0 := cfg.Receivers["sapm"]
43+
assert.Equal(t, r0, factory.CreateDefaultConfig())
44+
45+
r1 := cfg.Receivers["sapm/customname"].(*Config)
46+
assert.Equal(t, r1,
47+
&Config{
48+
ReceiverSettings: configmodels.ReceiverSettings{
49+
TypeVal: typeStr,
50+
NameVal: "sapm/customname",
51+
Endpoint: "0.0.0.0:7276",
52+
},
53+
})
54+
}

receiver/sapmreceiver/doc.go

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2019, OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Package sapmreceiver implements a receiver that can be used by the
16+
// Opentelemetry collector to receive traces in the Splunk SAPM format.
17+
package sapmreceiver

receiver/sapmreceiver/factory.go

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright 2019, OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package sapmreceiver
16+
17+
// This file implements factory for SAPM receiver.
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"net"
23+
"strconv"
24+
25+
"github.com/open-telemetry/opentelemetry-collector/config/configerror"
26+
"github.com/open-telemetry/opentelemetry-collector/config/configmodels"
27+
"github.com/open-telemetry/opentelemetry-collector/consumer"
28+
"github.com/open-telemetry/opentelemetry-collector/receiver"
29+
"go.uber.org/zap"
30+
)
31+
32+
const (
33+
// The value of "type" key in configuration.
34+
typeStr = "sapm"
35+
36+
// Default endpoints to bind to.
37+
defaultEndpoint = ":7276"
38+
)
39+
40+
// Factory is the factory for SAPM receiver.
41+
type Factory struct {
42+
}
43+
44+
// Type gets the type of the Receiver config created by this factory.
45+
func (f *Factory) Type() string {
46+
return typeStr
47+
}
48+
49+
// CustomUnmarshaler returns nil because we don't need custom unmarshaling for this config.
50+
func (f *Factory) CustomUnmarshaler() receiver.CustomUnmarshaler {
51+
return nil
52+
}
53+
54+
// CreateDefaultConfig creates the default configuration for SAPM receiver.
55+
func (f *Factory) CreateDefaultConfig() configmodels.Receiver {
56+
return &Config{
57+
ReceiverSettings: configmodels.ReceiverSettings{
58+
TypeVal: typeStr,
59+
NameVal: typeStr,
60+
Endpoint: defaultEndpoint,
61+
},
62+
}
63+
}
64+
65+
// extract the port number from string in "address:port" format. If the
66+
// port number cannot be extracted returns an error.
67+
// TODO make this a utility function
68+
func extractPortFromEndpoint(endpoint string) (int, error) {
69+
_, portStr, err := net.SplitHostPort(endpoint)
70+
if err != nil {
71+
return 0, fmt.Errorf("endpoint is not formatted correctly: %s", err.Error())
72+
}
73+
port, err := strconv.ParseInt(portStr, 10, 0)
74+
if err != nil {
75+
return 0, fmt.Errorf("endpoint port is not a number: %s", err.Error())
76+
}
77+
if port < 1 || port > 65535 {
78+
return 0, fmt.Errorf("port number must be between 1 and 65535")
79+
}
80+
return int(port), nil
81+
}
82+
83+
// CreateTraceReceiver creates a trace receiver based on provided config.
84+
func (f *Factory) CreateTraceReceiver(
85+
ctx context.Context,
86+
logger *zap.Logger,
87+
cfg configmodels.Receiver,
88+
nextConsumer consumer.TraceConsumer,
89+
) (receiver.TraceReceiver, error) {
90+
// assert config is SAPM config
91+
rCfg := cfg.(*Config)
92+
93+
port, err := extractPortFromEndpoint(rCfg.Endpoint)
94+
if err != nil {
95+
return nil, err
96+
}
97+
98+
// verify that the configured port is not 0
99+
if port == 0 {
100+
err = fmt.Errorf("endpoint with non-zero port must be enabled for %s receiver",
101+
rCfg.Name(),
102+
)
103+
return nil, err
104+
}
105+
106+
// Create the receiver.
107+
return New(ctx, logger, rCfg, nextConsumer)
108+
}
109+
110+
// CreateMetricsReceiver creates a metrics receiver based on provided config.
111+
func (f *Factory) CreateMetricsReceiver(
112+
logger *zap.Logger,
113+
cfg configmodels.Receiver,
114+
consumer consumer.MetricsConsumer,
115+
) (receiver.MetricsReceiver, error) {
116+
return nil, configerror.ErrDataTypeIsNotSupported
117+
}

receiver/sapmreceiver/factory_test.go

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright 2019, OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package sapmreceiver
16+
17+
import (
18+
"context"
19+
"testing"
20+
21+
"github.com/open-telemetry/opentelemetry-collector/config/configcheck"
22+
"github.com/open-telemetry/opentelemetry-collector/config/configerror"
23+
"github.com/stretchr/testify/assert"
24+
"go.uber.org/zap"
25+
)
26+
27+
func TestCreateDefaultConfig(t *testing.T) {
28+
factory := Factory{}
29+
cfg := factory.CreateDefaultConfig()
30+
assert.NotNil(t, cfg, "failed to create default config")
31+
assert.NoError(t, configcheck.ValidateConfig(cfg))
32+
}
33+
34+
func TestCreateReceiver(t *testing.T) {
35+
factory := Factory{}
36+
cfg := factory.CreateDefaultConfig()
37+
38+
tReceiver, err := factory.CreateTraceReceiver(context.Background(), zap.NewNop(), cfg, nil)
39+
assert.NoError(t, err, "receiver creation failed")
40+
assert.NotNil(t, tReceiver, "receiver creation failed")
41+
42+
mReceiver, err := factory.CreateMetricsReceiver(zap.NewNop(), cfg, nil)
43+
assert.Equal(t, err, configerror.ErrDataTypeIsNotSupported)
44+
assert.Nil(t, mReceiver)
45+
}
46+
47+
func TestCreateInvalidHTTPEndpoint(t *testing.T) {
48+
factory := Factory{}
49+
cfg := factory.CreateDefaultConfig()
50+
rCfg := cfg.(*Config)
51+
52+
rCfg.Endpoint = ""
53+
_, err := factory.CreateTraceReceiver(context.Background(), zap.NewNop(), cfg, nil)
54+
assert.Error(t, err, "receiver creation with no endpoints must fail")
55+
}
56+
57+
func TestCreateNoPort(t *testing.T) {
58+
factory := Factory{}
59+
cfg := factory.CreateDefaultConfig()
60+
rCfg := cfg.(*Config)
61+
62+
rCfg.Endpoint = "localhost:"
63+
_, err := factory.CreateTraceReceiver(context.Background(), zap.NewNop(), cfg, nil)
64+
assert.Error(t, err, "receiver creation with no port number must fail")
65+
}
66+
67+
func TestCreateLargePort(t *testing.T) {
68+
factory := Factory{}
69+
cfg := factory.CreateDefaultConfig()
70+
rCfg := cfg.(*Config)
71+
72+
rCfg.Endpoint = "localhost:65536"
73+
_, err := factory.CreateTraceReceiver(context.Background(), zap.NewNop(), cfg, nil)
74+
assert.Error(t, err, "receiver creation with too large port number must fail")
75+
}

receiver/sapmreceiver/go.mod

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
module github.com/optelemetry-collector-contrib/receiver/sapmreceiver
2+
3+
go 1.12
4+
5+
require (
6+
cloud.google.com/go v0.49.0 // indirect
7+
github.com/census-instrumentation/opencensus-proto v0.2.1
8+
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 // indirect
9+
github.com/golang/protobuf v1.3.2
10+
github.com/google/go-cmp v0.3.1
11+
github.com/gorilla/mux v1.7.3
12+
github.com/jaegertracing/jaeger v1.15.1
13+
github.com/jstemmer/go-junit-report v0.9.1 // indirect
14+
github.com/open-telemetry/opentelemetry-collector v0.2.1-0.20191205151336-8e2473c5e754
15+
github.com/prometheus/client_model v0.0.0-20191202183732-d1d2010b5bee // indirect
16+
github.com/signalfx/sapm-proto v0.0.2
17+
github.com/stretchr/testify v1.4.0
18+
go.opencensus.io v0.22.2
19+
go.uber.org/zap v1.13.0
20+
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd // indirect
21+
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f // indirect
22+
golang.org/x/net v0.0.0-20191206103017-1ddd1de85cb0 // indirect
23+
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 // indirect
24+
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
25+
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e // indirect
26+
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
27+
golang.org/x/tools v0.0.0-20191205225056-3393d29bb9fe // indirect
28+
google.golang.org/appengine v1.6.5 // indirect
29+
google.golang.org/genproto v0.0.0-20191205163323-51378566eb59 // indirect
30+
google.golang.org/grpc v1.25.1 // indirect
31+
gopkg.in/yaml.v2 v2.2.7 // indirect
32+
)

0 commit comments

Comments
 (0)