Skip to content

Add receiver for sapm protocol #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/otelcontribcol/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter"
"github.com/open-telemetry/opentelemetry-collector-contrib/exporter/stackdriverexporter"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/collectdreceiver"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sapmreceiver"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinscribereceiver"
)

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

receivers := []receiver.Factory{
&collectdreceiver.Factory{},
&sapmreceiver.Factory{},
&zipkinscribereceiver.Factory{},
}
for _, rcv := range factories.Receivers {
Expand Down
15 changes: 7 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,21 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/exporter/azure

replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/collectdreceiver => ./receiver/collectdreceiver
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@owais I assume this is no longer needed. Can you please remove it in a separate PR?


replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sapmreceiver => ./receiver/sapmreceiver

require (
github.com/client9/misspell v0.3.4
github.com/google/addlicense v0.0.0-20190907113143-be125746c2c4
github.com/onsi/ginkgo v1.10.1 // indirect
github.com/onsi/gomega v1.7.0 // indirect
github.com/open-telemetry/opentelemetry-collector v0.2.1-0.20191126183205-e94dd19191e0
github.com/open-telemetry/opentelemetry-collector v0.2.1-0.20191205151336-8e2473c5e754
github.com/open-telemetry/opentelemetry-collector-contrib/exporter/azuremonitorexporter v0.0.0
github.com/open-telemetry/opentelemetry-collector-contrib/exporter/signalfxexporter v0.0.0-20191203211755-8ae89debd6c5
github.com/open-telemetry/opentelemetry-collector-contrib/exporter/stackdriverexporter v0.0.0-20191126142441-b2a048090ad6
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/collectdreceiver v0.0.0-00010101000000-000000000000
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/sapmreceiver v0.0.0
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinscribereceiver v0.0.0-20191126142441-b2a048090ad6
github.com/pavius/impi v0.0.0-20180302134524-c1cbdcb8df2b
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392 // indirect
golang.org/x/lint v0.0.0-20190930215403-16217165b5de
golang.org/x/tools v0.0.0-20191119175705-11e13f1c3fd7
gopkg.in/yaml.v2 v2.2.4 // indirect
github.com/pierrec/lz4 v2.0.5+incompatible // indirect
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f
golang.org/x/tools v0.0.0-20191205225056-3393d29bb9fe
honnef.co/go/tools v0.0.1-2019.2.3
)
192 changes: 190 additions & 2 deletions go.sum

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions receiver/sapmreceiver/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2019, OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sapmreceiver

import (
"github.com/open-telemetry/opentelemetry-collector/config/configmodels"
)

// Config defines configuration for SAPM receiver.
type Config struct {
configmodels.ReceiverSettings `mapstructure:",squash"`
}
54 changes: 54 additions & 0 deletions receiver/sapmreceiver/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2019, OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sapmreceiver

import (
"path"
"testing"

"github.com/open-telemetry/opentelemetry-collector/config"
"github.com/open-telemetry/opentelemetry-collector/config/configmodels"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestLoadConfig(t *testing.T) {
factories, err := config.ExampleComponents()
assert.Nil(t, err)

factory := &Factory{}
factories.Receivers[typeStr] = factory
cfg, err := config.LoadConfigFile(t, path.Join(".", "testdata", "config.yaml"), factories)

require.NoError(t, err)
require.NotNil(t, cfg)

// The receiver `sapm/disabled` doesn't count because disabled receivers
// are excluded from the final list.
assert.Equal(t, len(cfg.Receivers), 2)

r0 := cfg.Receivers["sapm"]
assert.Equal(t, r0, factory.CreateDefaultConfig())

r1 := cfg.Receivers["sapm/customname"].(*Config)
assert.Equal(t, r1,
&Config{
ReceiverSettings: configmodels.ReceiverSettings{
TypeVal: typeStr,
NameVal: "sapm/customname",
Endpoint: "0.0.0.0:7276",
},
})
}
17 changes: 17 additions & 0 deletions receiver/sapmreceiver/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2019, OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package sapmreceiver implements a receiver that can be used by the
// Opentelemetry collector to receive traces in the Splunk SAPM format.
package sapmreceiver
117 changes: 117 additions & 0 deletions receiver/sapmreceiver/factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright 2019, OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sapmreceiver

// This file implements factory for SAPM receiver.

import (
"context"
"fmt"
"net"
"strconv"

"github.com/open-telemetry/opentelemetry-collector/config/configerror"
"github.com/open-telemetry/opentelemetry-collector/config/configmodels"
"github.com/open-telemetry/opentelemetry-collector/consumer"
"github.com/open-telemetry/opentelemetry-collector/receiver"
"go.uber.org/zap"
)

const (
// The value of "type" key in configuration.
typeStr = "sapm"

// Default endpoints to bind to.
defaultEndpoint = ":7276"
)

// Factory is the factory for SAPM receiver.
type Factory struct {
}

// Type gets the type of the Receiver config created by this factory.
func (f *Factory) Type() string {
return typeStr
}

// CustomUnmarshaler returns nil because we don't need custom unmarshaling for this config.
func (f *Factory) CustomUnmarshaler() receiver.CustomUnmarshaler {
return nil
}

// CreateDefaultConfig creates the default configuration for SAPM receiver.
func (f *Factory) CreateDefaultConfig() configmodels.Receiver {
return &Config{
ReceiverSettings: configmodels.ReceiverSettings{
TypeVal: typeStr,
NameVal: typeStr,
Endpoint: defaultEndpoint,
},
}
}

// extract the port number from string in "address:port" format. If the
// port number cannot be extracted returns an error.
// TODO make this a utility function
func extractPortFromEndpoint(endpoint string) (int, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably make this a utility func available for all components. No need to change anything in this PR, maybe just a TODO note for future improvement.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a TODO

_, portStr, err := net.SplitHostPort(endpoint)
if err != nil {
return 0, fmt.Errorf("endpoint is not formatted correctly: %s", err.Error())
}
port, err := strconv.ParseInt(portStr, 10, 0)
if err != nil {
return 0, fmt.Errorf("endpoint port is not a number: %s", err.Error())
}
if port < 1 || port > 65535 {
return 0, fmt.Errorf("port number must be between 1 and 65535")
}
return int(port), nil
}

// CreateTraceReceiver creates a trace receiver based on provided config.
func (f *Factory) CreateTraceReceiver(
ctx context.Context,
logger *zap.Logger,
cfg configmodels.Receiver,
nextConsumer consumer.TraceConsumer,
) (receiver.TraceReceiver, error) {
// assert config is SAPM config
rCfg := cfg.(*Config)

port, err := extractPortFromEndpoint(rCfg.Endpoint)
if err != nil {
return nil, err
}

// verify that the configured port is not 0
if port == 0 {
err = fmt.Errorf("endpoint with non-zero port must be enabled for %s receiver",
rCfg.Name(),
)
return nil, err
}

// Create the receiver.
return New(ctx, logger, rCfg, nextConsumer)
}

// CreateMetricsReceiver creates a metrics receiver based on provided config.
func (f *Factory) CreateMetricsReceiver(
logger *zap.Logger,
cfg configmodels.Receiver,
consumer consumer.MetricsConsumer,
) (receiver.MetricsReceiver, error) {
return nil, configerror.ErrDataTypeIsNotSupported
}
75 changes: 75 additions & 0 deletions receiver/sapmreceiver/factory_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright 2019, OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sapmreceiver

import (
"context"
"testing"

"github.com/open-telemetry/opentelemetry-collector/config/configcheck"
"github.com/open-telemetry/opentelemetry-collector/config/configerror"
"github.com/stretchr/testify/assert"
"go.uber.org/zap"
)

func TestCreateDefaultConfig(t *testing.T) {
factory := Factory{}
cfg := factory.CreateDefaultConfig()
assert.NotNil(t, cfg, "failed to create default config")
assert.NoError(t, configcheck.ValidateConfig(cfg))
}

func TestCreateReceiver(t *testing.T) {
factory := Factory{}
cfg := factory.CreateDefaultConfig()

tReceiver, err := factory.CreateTraceReceiver(context.Background(), zap.NewNop(), cfg, nil)
assert.NoError(t, err, "receiver creation failed")
assert.NotNil(t, tReceiver, "receiver creation failed")

mReceiver, err := factory.CreateMetricsReceiver(zap.NewNop(), cfg, nil)
assert.Equal(t, err, configerror.ErrDataTypeIsNotSupported)
assert.Nil(t, mReceiver)
}

func TestCreateInvalidHTTPEndpoint(t *testing.T) {
factory := Factory{}
cfg := factory.CreateDefaultConfig()
rCfg := cfg.(*Config)

rCfg.Endpoint = ""
_, err := factory.CreateTraceReceiver(context.Background(), zap.NewNop(), cfg, nil)
assert.Error(t, err, "receiver creation with no endpoints must fail")
}

func TestCreateNoPort(t *testing.T) {
factory := Factory{}
cfg := factory.CreateDefaultConfig()
rCfg := cfg.(*Config)

rCfg.Endpoint = "localhost:"
_, err := factory.CreateTraceReceiver(context.Background(), zap.NewNop(), cfg, nil)
assert.Error(t, err, "receiver creation with no port number must fail")
}

func TestCreateLargePort(t *testing.T) {
factory := Factory{}
cfg := factory.CreateDefaultConfig()
rCfg := cfg.(*Config)

rCfg.Endpoint = "localhost:65536"
_, err := factory.CreateTraceReceiver(context.Background(), zap.NewNop(), cfg, nil)
assert.Error(t, err, "receiver creation with too large port number must fail")
}
32 changes: 32 additions & 0 deletions receiver/sapmreceiver/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module github.com/optelemetry-collector-contrib/receiver/sapmreceiver

go 1.12

require (
cloud.google.com/go v0.49.0 // indirect
github.com/census-instrumentation/opencensus-proto v0.2.1
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 // indirect
github.com/golang/protobuf v1.3.2
github.com/google/go-cmp v0.3.1
github.com/gorilla/mux v1.7.3
github.com/jaegertracing/jaeger v1.15.1
github.com/jstemmer/go-junit-report v0.9.1 // indirect
github.com/open-telemetry/opentelemetry-collector v0.2.1-0.20191205151336-8e2473c5e754
github.com/prometheus/client_model v0.0.0-20191202183732-d1d2010b5bee // indirect
github.com/signalfx/sapm-proto v0.0.2
github.com/stretchr/testify v1.4.0
go.opencensus.io v0.22.2
go.uber.org/zap v1.13.0
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd // indirect
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f // indirect
golang.org/x/net v0.0.0-20191206103017-1ddd1de85cb0 // indirect
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 // indirect
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
golang.org/x/tools v0.0.0-20191205225056-3393d29bb9fe // indirect
google.golang.org/appengine v1.6.5 // indirect
google.golang.org/genproto v0.0.0-20191205163323-51378566eb59 // indirect
google.golang.org/grpc v1.25.1 // indirect
gopkg.in/yaml.v2 v2.2.7 // indirect
)
Loading