Skip to content
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

Add receiver for sapm protocol #48

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)
pjanotti marked this conversation as resolved.
Show resolved Hide resolved
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