Skip to content

Commit

Permalink
Add config settings for Http client (#1186)
Browse files Browse the repository at this point in the history
Signed-off-by: Bogdan Drutu <bogdandrutu@gmail.com>
  • Loading branch information
bogdandrutu committed Jun 25, 2020
1 parent bd886e8 commit c8b812b
Show file tree
Hide file tree
Showing 12 changed files with 169 additions and 63 deletions.
48 changes: 48 additions & 0 deletions config/confighttp/confighttp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright The 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 confighttp

import (
"net/http"
"time"

"go.opentelemetry.io/collector/config/configtls"
)

type HTTPClientSettings struct {
// The target URL to send data to (e.g.: http://some.url:9411/v1/trace).
Endpoint string `mapstructure:"endpoint"`

// TLSSetting struct exposes TLS client configuration.
TLSSetting configtls.TLSClientSetting `mapstructure:",squash"`

// Timeout parameter configures `http.Client.Timeout`.
Timeout time.Duration `mapstructure:"timeout,omitempty"`
}

func (hcs *HTTPClientSettings) ToClient() (*http.Client, error) {
tlsCfg, err := hcs.TLSSetting.LoadTLSConfig()
if err != nil {
return nil, err
}
transport := http.DefaultTransport.(*http.Transport).Clone()
if tlsCfg != nil {
transport.TLSClientConfig = tlsCfg
}
return &http.Client{
Transport: transport,
Timeout: hcs.Timeout,
}, nil
}
63 changes: 63 additions & 0 deletions config/confighttp/confighttp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright The 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 confighttp

import (
"testing"

"github.com/stretchr/testify/assert"

"go.opentelemetry.io/collector/config/configtls"
)

func TestInvalidPemFile(t *testing.T) {
tests := []struct {
settings HTTPClientSettings
err string
}{
{
err: "^failed to load TLS config: failed to load CA CertPool: failed to load CA /doesnt/exist:",
settings: HTTPClientSettings{
Endpoint: "",
TLSSetting: configtls.TLSClientSetting{
TLSSetting: configtls.TLSSetting{
CAFile: "/doesnt/exist",
},
Insecure: false,
ServerName: "",
},
},
},
{
err: "^failed to load TLS config: for auth via TLS, either both certificate and key must be supplied, or neither",
settings: HTTPClientSettings{
Endpoint: "",
TLSSetting: configtls.TLSClientSetting{
TLSSetting: configtls.TLSSetting{
CertFile: "/doesnt/exist",
},
Insecure: false,
ServerName: "",
},
},
},
}
for _, test := range tests {
t.Run(test.err, func(t *testing.T) {
_, err := test.settings.ToClient()
assert.Regexp(t, test.err, err)
})
}
}
8 changes: 5 additions & 3 deletions exporter/zipkinexporter/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,18 @@
package zipkinexporter

import (
"go.opentelemetry.io/collector/config/confighttp"
"go.opentelemetry.io/collector/config/configmodels"
)

// Config defines configuration settings for the Zipkin exporter.
type Config struct {
configmodels.ExporterSettings `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct.

// The URL to send the Zipkin trace data to (e.g.:
// http://some.url:9411/api/v2/spans).
URL string `mapstructure:"url"`
// Configures the exporter client.
// The Endpoint to send the Zipkin trace data to (e.g.: http://some.url:9411/api/v2/spans).
confighttp.HTTPClientSettings `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct.

Format string `mapstructure:"format"`

DefaultServiceName string `mapstructure:"default_service_name"`
Expand Down
4 changes: 2 additions & 2 deletions exporter/zipkinexporter/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ func TestLoadConfig(t *testing.T) {

// URL doesn't have a default value so set it directly.
defaultCfg := factory.CreateDefaultConfig().(*Config)
defaultCfg.URL = "http://some.location.org:9411/api/v2/spans"
defaultCfg.Endpoint = "http://some.location.org:9411/api/v2/spans"
assert.Equal(t, defaultCfg, e0)
assert.Equal(t, "json", e0.(*Config).Format)

e1 := cfg.Exporters["zipkin/2"]
assert.Equal(t, "zipkin/2", e1.(*Config).Name())
assert.Equal(t, "https://somedest:1234/api/v2/spans", e1.(*Config).URL)
assert.Equal(t, "https://somedest:1234/api/v2/spans", e1.(*Config).Endpoint)
assert.Equal(t, "proto", e1.(*Config).Format)
_, err = factory.CreateTraceExporter(zap.NewNop(), e1)
require.NoError(t, err)
Expand Down
22 changes: 17 additions & 5 deletions exporter/zipkinexporter/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,25 @@ package zipkinexporter

import (
"errors"
"time"

"go.uber.org/zap"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/configerror"
"go.opentelemetry.io/collector/config/confighttp"
"go.opentelemetry.io/collector/config/configmodels"
)

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

defaultTimeout = time.Second * 5

defaultFormat = "json"

defaultServiceName string = "<missing service name>"
)

// Factory is the factory for OpenCensus exporter.
Expand All @@ -45,20 +53,24 @@ func (f *Factory) CreateDefaultConfig() configmodels.Exporter {
TypeVal: typeStr,
NameVal: typeStr,
},
Format: "json",
HTTPClientSettings: confighttp.HTTPClientSettings{
Timeout: defaultTimeout,
},
Format: defaultFormat,
DefaultServiceName: defaultServiceName,
}
}

// CreateTraceExporter creates a trace exporter based on this config.
func (f *Factory) CreateTraceExporter(_ *zap.Logger, config configmodels.Exporter) (component.TraceExporterOld, error) {
zc := config.(*Config)

if zc.URL == "" {
// TODO https://go.opentelemetry.io/collector/issues/215
return nil, errors.New("exporter config requires a non-empty 'url'")
if zc.Endpoint == "" {
// TODO https://github.com/open-telemetry/opentelemetry-collector/issues/215
return nil, errors.New("exporter config requires a non-empty 'endpoint'")
}

return NewTraceExporter(config)
return newTraceExporter(zc)
}

// CreateMetricsExporter creates a metrics exporter based on this config.
Expand Down
10 changes: 3 additions & 7 deletions exporter/zipkinexporter/factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,14 @@ func TestCreateInstanceViaFactory(t *testing.T) {

// Default config doesn't have default endpoint so creating from it should
// fail.
ze, err := factory.CreateTraceExporter(
zap.NewNop(),
cfg)
ze, err := factory.CreateTraceExporter(zap.NewNop(), cfg)
assert.Error(t, err)
assert.Nil(t, ze)

// URL doesn't have a default value so set it directly.
zeCfg := cfg.(*Config)
zeCfg.URL = "http://some.location.org:9411/api/v2/spans"
ze, err = factory.CreateTraceExporter(
zap.NewNop(),
cfg)
zeCfg.Endpoint = "http://some.location.org:9411/api/v2/spans"
ze, err = factory.CreateTraceExporter(zap.NewNop(), cfg)
assert.NoError(t, err)
assert.NotNil(t, ze)
}
4 changes: 2 additions & 2 deletions exporter/zipkinexporter/testdata/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ processors:

exporters:
zipkin:
url: "http://some.location.org:9411/api/v2/spans"
endpoint: "http://some.location.org:9411/api/v2/spans"
zipkin/2:
url: "https://somedest:1234/api/v2/spans"
endpoint: "https://somedest:1234/api/v2/spans"
format: proto
default_service_name: test_name

Expand Down
37 changes: 12 additions & 25 deletions exporter/zipkinexporter/zipkin.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,13 @@ import (
"context"
"fmt"
"net/http"
"time"

resourcepb "github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1"
zipkinmodel "github.com/openzipkin/zipkin-go/model"
zipkinproto "github.com/openzipkin/zipkin-go/proto/v2"
zipkinreporter "github.com/openzipkin/zipkin-go/reporter"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/configmodels"
"go.opentelemetry.io/collector/consumer/consumerdata"
"go.opentelemetry.io/collector/consumer/consumererror"
"go.opentelemetry.io/collector/exporter/exporterhelper"
Expand All @@ -47,50 +45,39 @@ type zipkinExporter struct {
serializer zipkinreporter.SpanSerializer
}

// Default values for Zipkin endpoint.
const (
defaultTimeout = time.Second * 5

defaultServiceName string = "<missing service name>"
)

// NewTraceExporter creates an zipkin trace exporter.
func NewTraceExporter(config configmodels.Exporter) (component.TraceExporterOld, error) {
// newTraceExporter creates an zipkin trace exporter.
func newTraceExporter(config *Config) (component.TraceExporterOld, error) {
ze, err := createZipkinExporter(config)
if err != nil {
return nil, err
}
zexp, err := exporterhelper.NewTraceExporterOld(
config,
ze.PushTraceData)
zexp, err := exporterhelper.NewTraceExporterOld(config, ze.PushTraceData)
if err != nil {
return nil, err
}

return zexp, nil
}

func createZipkinExporter(config configmodels.Exporter) (*zipkinExporter, error) {
zCfg := config.(*Config)

serviceName := defaultServiceName
if zCfg.DefaultServiceName != "" {
serviceName = zCfg.DefaultServiceName
func createZipkinExporter(cfg *Config) (*zipkinExporter, error) {
client, err := cfg.HTTPClientSettings.ToClient()
if err != nil {
return nil, err
}

ze := &zipkinExporter{
defaultServiceName: serviceName,
url: zCfg.URL,
client: &http.Client{Timeout: defaultTimeout},
defaultServiceName: cfg.DefaultServiceName,
url: cfg.Endpoint,
client: client,
}

switch zCfg.Format {
switch cfg.Format {
case "json":
ze.serializer = zipkinreporter.JSONSerializer{}
case "proto":
ze.serializer = zipkinproto.SpanSerializer{}
default:
return nil, fmt.Errorf("%s is not one of json or proto", zCfg.Format)
return nil, fmt.Errorf("%s is not one of json or proto", cfg.Format)
}

return ze, nil
Expand Down
17 changes: 12 additions & 5 deletions exporter/zipkinexporter/zipkin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"go.uber.org/zap"

"go.opentelemetry.io/collector/component/componenttest"
"go.opentelemetry.io/collector/config/confighttp"
"go.opentelemetry.io/collector/consumer"
"go.opentelemetry.io/collector/processor"
"go.opentelemetry.io/collector/receiver/zipkinreceiver"
Expand All @@ -59,10 +60,12 @@ func TestZipkinExporter_roundtripJSON(t *testing.T) {
defer cst.Close()

config := &Config{
URL: cst.URL,
HTTPClientSettings: confighttp.HTTPClientSettings{
Endpoint: cst.URL,
},
Format: "json",
}
tes, err := NewTraceExporter(config)
tes, err := newTraceExporter(config)
assert.NoError(t, err)
require.NotNil(t, tes)

Expand Down Expand Up @@ -267,7 +270,9 @@ const zipkinSpansJSONJavaLibrary = `

func TestZipkinExporter_invalidFormat(t *testing.T) {
config := &Config{
URL: "1.2.3.4",
HTTPClientSettings: confighttp.HTTPClientSettings{
Endpoint: "1.2.3.4",
},
Format: "foobar",
}
f := &Factory{}
Expand All @@ -287,10 +292,12 @@ func TestZipkinExporter_roundtripProto(t *testing.T) {
defer cst.Close()

config := &Config{
URL: cst.URL,
HTTPClientSettings: confighttp.HTTPClientSettings{
Endpoint: cst.URL,
},
Format: "proto",
}
tes, err := NewTraceExporter(config)
tes, err := newTraceExporter(config)
require.NoError(t, err)

// The test requires the spans from zipkinSpansJSONJavaLibrary to be sent in a single batch, use
Expand Down
8 changes: 2 additions & 6 deletions receiver/zipkinreceiver/trace_receiver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ import (
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/component/componenterror"
"go.opentelemetry.io/collector/component/componenttest"
"go.opentelemetry.io/collector/config/configmodels"
"go.opentelemetry.io/collector/consumer"
"go.opentelemetry.io/collector/consumer/consumerdata"
"go.opentelemetry.io/collector/exporter/exportertest"
Expand Down Expand Up @@ -318,11 +317,8 @@ func TestConversionRoundtrip(t *testing.T) {
defer backend.Close()

factory := &zipkinexporter.Factory{}
config := &zipkinexporter.Config{
ExporterSettings: configmodels.ExporterSettings{},
URL: backend.URL,
Format: "json",
}
config := factory.CreateDefaultConfig().(*zipkinexporter.Config)
config.Endpoint = backend.URL
ze, err := factory.CreateTraceExporter(zap.NewNop(), config)
require.NoError(t, err)
require.NotNil(t, ze)
Expand Down
2 changes: 1 addition & 1 deletion testbed/testbed/receivers.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ func (zr *ZipkinDataReceiver) GenConfigYAMLStr() string {
// Note that this generates an exporter config for agent.
return fmt.Sprintf(`
zipkin:
url: http://localhost:%d/api/v2/spans
endpoint: http://localhost:%d/api/v2/spans
format: json`, zr.Port)
}

Expand Down
Loading

0 comments on commit c8b812b

Please sign in to comment.