Skip to content

Commit

Permalink
Merge branch 'main' into mvg/1.18-notice
Browse files Browse the repository at this point in the history
  • Loading branch information
dmathieu authored Feb 24, 2023
2 parents 36cf183 + 1d6704c commit 9e49e97
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ This release is the last to support go 1.18. The next release will require go 1.
- Add `bridgetSpanContext.IsSampled` to `go.opentelemetry.io/otel/bridget/opentracing` to expose whether span is sampled or not. (#3570)
- The `WithInstrumentationAttributes` option to `go.opentelemetry.io/otel/metric`. (#3738)
- The `WithInstrumentationAttributes` option to `go.opentelemetry.io/otel/trace`. (#3739)
- The following environment variables are supported by the `Reader`s in `go.opentelemetry.io/otel/sdk/metric`. (#3763)
- `OTEL_METRIC_EXPORT_INTERVAL`
- `OTEL_METRIC_EXPORT_TIMEOUT`

### Changed

Expand Down
50 changes: 50 additions & 0 deletions sdk/metric/env.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// 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 metric // import "go.opentelemetry.io/otel/sdk/metric"

import (
"os"
"strconv"
"time"

"go.opentelemetry.io/otel/internal/global"
)

// Environment variable names.
const (
// The time interval (in milliseconds) between the start of two export attempts.
envInterval = "OTEL_METRIC_EXPORT_INTERVAL"
// Maximum allowed time (in milliseconds) to export data.
envTimeout = "OTEL_METRIC_EXPORT_TIMEOUT"
)

// envDuration returns an environment variable's value as duration in milliseconds if it is exists,
// or the defaultValue if the environment variable is not defined or the value is not valid.
func envDuration(key string, defaultValue time.Duration) time.Duration {
v := os.Getenv(key)
if v == "" {
return defaultValue
}
d, err := strconv.Atoi(v)
if err != nil {
global.Error(err, "parse duration", "environment variable", key, "value", v)
return defaultValue
}
if d <= 0 {
global.Error(errNonPositiveDuration, "non-positive duration", "environment variable", key, "value", v)
return defaultValue
}
return time.Duration(d) * time.Millisecond
}
10 changes: 8 additions & 2 deletions sdk/metric/periodic_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ type periodicReaderConfig struct {
// options.
func newPeriodicReaderConfig(options []PeriodicReaderOption) periodicReaderConfig {
c := periodicReaderConfig{
interval: defaultInterval,
timeout: defaultTimeout,
interval: envDuration(envInterval, defaultInterval),
timeout: envDuration(envTimeout, defaultTimeout),
}
for _, o := range options {
c = o.applyPeriodic(c)
Expand All @@ -69,6 +69,9 @@ func (o periodicReaderOptionFunc) applyPeriodic(conf periodicReaderConfig) perio
// WithTimeout configures the time a PeriodicReader waits for an export to
// complete before canceling it.
//
// This option overrides any value set for the
// OTEL_METRIC_EXPORT_TIMEOUT environment variable.
//
// If this option is not used or d is less than or equal to zero, 30 seconds
// is used as the default.
func WithTimeout(d time.Duration) PeriodicReaderOption {
Expand All @@ -84,6 +87,9 @@ func WithTimeout(d time.Duration) PeriodicReaderOption {
// WithInterval configures the intervening time between exports for a
// PeriodicReader.
//
// This option overrides any value set for the
// OTEL_METRIC_EXPORT_INTERVAL environment variable.
//
// If this option is not used or d is less than or equal to zero, 60 seconds
// is used as the default.
func WithInterval(d time.Duration) PeriodicReaderOption {
Expand Down
96 changes: 96 additions & 0 deletions sdk/metric/periodic_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,54 @@ func TestWithTimeout(t *testing.T) {
assert.Equal(t, defaultTimeout, test(time.Duration(-1)), "invalid timeout should use default")
}

func TestTimeoutEnvVar(t *testing.T) {
testCases := []struct {
v string
want time.Duration
}{
{
// empty value
"",
defaultTimeout,
},
{
// positive value
"1",
time.Millisecond,
},
{
// non-positive value
"0",
defaultTimeout,
},
{
// value with unit (not supported)
"1ms",
defaultTimeout,
},
{
// NaN
"abc",
defaultTimeout,
},
}
for _, tc := range testCases {
t.Run(tc.v, func(t *testing.T) {
t.Setenv(envTimeout, tc.v)
got := newPeriodicReaderConfig(nil).timeout
assert.Equal(t, tc.want, got)
})
}
}

func TestTimeoutEnvAndOption(t *testing.T) {
want := 5 * time.Millisecond
t.Setenv(envTimeout, "999")
opts := []PeriodicReaderOption{WithTimeout(want)}
got := newPeriodicReaderConfig(opts).timeout
assert.Equal(t, want, got, "option should have precedence over env var")
}

func TestWithInterval(t *testing.T) {
test := func(d time.Duration) time.Duration {
opts := []PeriodicReaderOption{WithInterval(d)}
Expand All @@ -53,6 +101,54 @@ func TestWithInterval(t *testing.T) {
assert.Equal(t, defaultInterval, test(time.Duration(-1)), "invalid interval should use default")
}

func TestIntervalEnvVar(t *testing.T) {
testCases := []struct {
v string
want time.Duration
}{
{
// empty value
"",
defaultInterval,
},
{
// positive value
"1",
time.Millisecond,
},
{
// non-positive value
"0",
defaultInterval,
},
{
// value with unit (not supported)
"1ms",
defaultInterval,
},
{
// NaN
"abc",
defaultInterval,
},
}
for _, tc := range testCases {
t.Run(tc.v, func(t *testing.T) {
t.Setenv(envInterval, tc.v)
got := newPeriodicReaderConfig(nil).interval
assert.Equal(t, tc.want, got)
})
}
}

func TestIntervalEnvAndOption(t *testing.T) {
want := 5 * time.Millisecond
t.Setenv(envInterval, "999")
opts := []PeriodicReaderOption{WithInterval(want)}
got := newPeriodicReaderConfig(opts).interval
assert.Equal(t, want, got, "option should have precedence over env var")
}

type fnExporter struct {
temporalityFunc TemporalitySelector
aggregationFunc AggregationSelector
Expand Down
4 changes: 4 additions & 0 deletions sdk/metric/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ var ErrReaderNotRegistered = fmt.Errorf("reader is not registered")
// reader has been Shutdown once.
var ErrReaderShutdown = fmt.Errorf("reader is shutdown")

// errNonPositiveDuration is logged when an environmental variable
// has non-positive value.
var errNonPositiveDuration = fmt.Errorf("non-positive duration")

// Reader is the interface used between the SDK and an
// exporter. Control flow is bi-directional through the
// Reader, since the SDK initiates ForceFlush and Shutdown
Expand Down

0 comments on commit 9e49e97

Please sign in to comment.