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

[exporter/loadbalancing] Allow interval and timeout to be customized #10202

Merged
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
7 changes: 5 additions & 2 deletions exporter/loadbalancingexporter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@ Refer to [config.yaml](./testdata/config.yaml) for detailed examples on using th
* The `otlp` property configures the template used for building the OTLP exporter. Refer to the OTLP Exporter documentation for information on which options are available. Note that the `endpoint` property should not be set and will be overridden by this exporter with the backend endpoint.
* The `resolver` accepts either a `static` node, or a `dns`. If both are specified, `dns` takes precedence.
* The `hostname` property inside a `dns` node specifies the hostname to query in order to obtain the list of IP addresses.
* The `dns` node also accepts an optional property `port` to specify the port to be used for exporting the traces to the IP addresses resolved from `hostname`. If `port` is not specified, the default port 4317 is used.
* The `dns` node also accepts the following optional properties:
* `hostname` DNS hostname to resolve.
* `port` port to be used for exporting the traces to the IP addresses resolved from `hostname`. If `port` is not specified, the default port 4317 is used.
* `interval` resolver interval in go-Duration format, e.g. `5s`, `1d`, `30m`. If not specified, `5s` will be used.
* `timeout` resolver timeout in go-Duration format, e.g. `5s`, `1d`, `30m`. If not specified, `1s` will be used.
* The `routing_key` property is used to route spans to exporters based on different parameters. This functionality is currently enabled only for `trace` pipeline types. It supports one of the following values:
* `service`: exports spans based on their service name. This is useful when using processors like the span metrics, so all spans for each service are sent to consistent collector instances for metric collection. Otherwise, metrics for the same services are sent to different collectors, making aggregations inaccurate.
* `traceID` (default): exports spans based on their `traceID`.
* If not configured, defaults to `traceID` based routing.


Simple example
```yaml
Expand Down
8 changes: 6 additions & 2 deletions exporter/loadbalancingexporter/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package loadbalancingexporter // import "github.com/open-telemetry/opentelemetry-collector-contrib/exporter/loadbalancingexporter"

import (
"time"

"go.opentelemetry.io/collector/config"
"go.opentelemetry.io/collector/exporter/otlpexporter"
)
Expand Down Expand Up @@ -52,6 +54,8 @@ type StaticResolver struct {

// DNSResolver defines the configuration for the DNS resolver
type DNSResolver struct {
Hostname string `mapstructure:"hostname"`
Port string `mapstructure:"port"`
Hostname string `mapstructure:"hostname"`
Port string `mapstructure:"port"`
Interval time.Duration `mapstructure:"interval"`
Timeout time.Duration `mapstructure:"timeout"`
}
2 changes: 1 addition & 1 deletion exporter/loadbalancingexporter/loadbalancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func newLoadBalancer(params component.ExporterCreateSettings, cfg config.Exporte
dnsLogger := params.Logger.With(zap.String("resolver", "dns"))

var err error
res, err = newDNSResolver(dnsLogger, oCfg.Resolver.DNS.Hostname, oCfg.Resolver.DNS.Port)
res, err = newDNSResolver(dnsLogger, oCfg.Resolver.DNS.Hostname, oCfg.Resolver.DNS.Port, oCfg.Resolver.DNS.Interval, oCfg.Resolver.DNS.Timeout)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion exporter/loadbalancingexporter/log_exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ func TestRollingUpdatesWhenConsumeLogs(t *testing.T) {

// simulate rolling updates, the dns resolver should resolve in the following order
// ["127.0.0.1"] -> ["127.0.0.1", "127.0.0.2"] -> ["127.0.0.2"]
res, err := newDNSResolver(zap.NewNop(), "service-1", "")
res, err := newDNSResolver(zap.NewNop(), "service-1", "", 5*time.Second, 1*time.Second)
require.NoError(t, err)

mu := sync.Mutex{}
Expand Down
17 changes: 14 additions & 3 deletions exporter/loadbalancingexporter/resolver_dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,24 @@ type netResolver interface {
LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error)
}

func newDNSResolver(logger *zap.Logger, hostname string, port string) (*dnsResolver, error) {
func newDNSResolver(logger *zap.Logger, hostname string, port string, interval time.Duration, timeout time.Duration) (*dnsResolver, error) {
if len(hostname) == 0 {
return nil, errNoHostname
}
if interval == 0 {
interval = defaultResInterval
}
if timeout == 0 {
timeout = defaultResTimeout
}

return &dnsResolver{
logger: logger,
hostname: hostname,
port: port,
resolver: &net.Resolver{},
resInterval: defaultResInterval,
resTimeout: defaultResTimeout,
resInterval: interval,
resTimeout: timeout,
stopCh: make(chan struct{}),
}, nil
}
Expand All @@ -82,6 +88,9 @@ func (r *dnsResolver) start(ctx context.Context) error {

go r.periodicallyResolve()

r.logger.Debug("DNS resolver started",
zap.String("hostname", r.hostname), zap.String("port", r.port),
zap.Duration("interval", r.resInterval), zap.Duration("timeout", r.resTimeout))
return nil
}

Expand All @@ -104,6 +113,8 @@ func (r *dnsResolver) periodicallyResolve() {
ctx, cancel := context.WithTimeout(context.Background(), r.resTimeout)
if _, err := r.resolve(ctx); err != nil {
r.logger.Warn("failed to resolve", zap.Error(err))
} else {
r.logger.Debug("resolved successfully")
TylerHelmuth marked this conversation as resolved.
Show resolved Hide resolved
}
cancel()
case <-r.stopCh:
Expand Down
18 changes: 8 additions & 10 deletions exporter/loadbalancingexporter/resolver_dns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (

func TestInitialDNSResolution(t *testing.T) {
// prepare
res, err := newDNSResolver(zap.NewNop(), "service-1", "")
res, err := newDNSResolver(zap.NewNop(), "service-1", "", 5*time.Second, 1*time.Second)
require.NoError(t, err)

res.resolver = &mockDNSResolver{
Expand Down Expand Up @@ -62,7 +62,7 @@ func TestInitialDNSResolution(t *testing.T) {

func TestInitialDNSResolutionWithPort(t *testing.T) {
// prepare
res, err := newDNSResolver(zap.NewNop(), "service-1", "55690")
res, err := newDNSResolver(zap.NewNop(), "service-1", "55690", 5*time.Second, 1*time.Second)
require.NoError(t, err)

res.resolver = &mockDNSResolver{
Expand Down Expand Up @@ -94,7 +94,7 @@ func TestInitialDNSResolutionWithPort(t *testing.T) {

func TestErrNoHostname(t *testing.T) {
// test
res, err := newDNSResolver(zap.NewNop(), "", "")
res, err := newDNSResolver(zap.NewNop(), "", "", 5*time.Second, 1*time.Second)

// verify
assert.Nil(t, res)
Expand All @@ -103,7 +103,7 @@ func TestErrNoHostname(t *testing.T) {

func TestCantResolve(t *testing.T) {
// prepare
res, err := newDNSResolver(zap.NewNop(), "service-1", "")
res, err := newDNSResolver(zap.NewNop(), "service-1", "", 5*time.Second, 1*time.Second)
require.NoError(t, err)

expectedErr := errors.New("some expected error")
Expand All @@ -122,7 +122,7 @@ func TestCantResolve(t *testing.T) {

func TestOnChange(t *testing.T) {
// prepare
res, err := newDNSResolver(zap.NewNop(), "service-1", "")
res, err := newDNSResolver(zap.NewNop(), "service-1", "", 5*time.Second, 1*time.Second)
require.NoError(t, err)

resolve := []net.IPAddr{
Expand Down Expand Up @@ -189,7 +189,7 @@ func TestEqualStringSlice(t *testing.T) {

func TestPeriodicallyResolve(t *testing.T) {
// prepare
res, err := newDNSResolver(zap.NewNop(), "service-1", "")
res, err := newDNSResolver(zap.NewNop(), "service-1", "", 10*time.Millisecond, 1*time.Second)
require.NoError(t, err)

counter := atomic.NewInt64(0)
Expand Down Expand Up @@ -224,7 +224,6 @@ func TestPeriodicallyResolve(t *testing.T) {
return resolve[0], nil
},
}
res.resInterval = 10 * time.Millisecond

wg := sync.WaitGroup{}
res.onChange(func(backends []string) {
Expand All @@ -248,7 +247,7 @@ func TestPeriodicallyResolve(t *testing.T) {

func TestPeriodicallyResolveFailure(t *testing.T) {
// prepare
res, err := newDNSResolver(zap.NewNop(), "service-1", "")
res, err := newDNSResolver(zap.NewNop(), "service-1", "", 10*time.Millisecond, 1*time.Second)
require.NoError(t, err)

expectedErr := errors.New("some expected error")
Expand All @@ -273,7 +272,6 @@ func TestPeriodicallyResolveFailure(t *testing.T) {
return resolve, nil
},
}
res.resInterval = 10 * time.Millisecond

// test
wg.Add(2)
Expand All @@ -292,7 +290,7 @@ func TestPeriodicallyResolveFailure(t *testing.T) {

func TestShutdownClearsCallbacks(t *testing.T) {
// prepare
res, err := newDNSResolver(zap.NewNop(), "service-1", "")
res, err := newDNSResolver(zap.NewNop(), "service-1", "", 5*time.Second, 1*time.Second)
require.NoError(t, err)

res.resolver = &mockDNSResolver{}
Expand Down
2 changes: 1 addition & 1 deletion exporter/loadbalancingexporter/trace_exporter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ func TestRollingUpdatesWhenConsumeTraces(t *testing.T) {

// simulate rolling updates, the dns resolver should resolve in the following order
// ["127.0.0.1"] -> ["127.0.0.1", "127.0.0.2"] -> ["127.0.0.2"]
res, err := newDNSResolver(zap.NewNop(), "service-1", "")
res, err := newDNSResolver(zap.NewNop(), "service-1", "", 5*time.Second, 1*time.Second)
require.NoError(t, err)

mu := sync.Mutex{}
Expand Down
16 changes: 16 additions & 0 deletions unreleased/add-dns-timer-configs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: loadbalancingexporter

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Added `interval` and `timeout` to the dns configuration in the loadbalancer exporter

# One or more tracking issues related to the change
issues: [10199]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext: