Repository: lightstep/otel-launcher-go
Pull request #13 (2020-08-13 06:03:59)

OTLP metrics exporter setup with runtime/host metrics plugins
**Description:** Adds an OTLP Metrics exporter. Metrics are disabled by default and can be configured by setting `OTEL_EXPORTER_OTLP_METRIC_ENDPOINT`.  This default will change to on by default after the LS SaaS has deployed the appropriate support.

**Testing:** New tests were added

**Documentation:** README.md has been updated to explain that metrics are off by default and that when configured, Host and Runtime metrics are started automatically.

codecov-commenter: # [Codecov](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=h1) Report
> Merging [#13](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=desc) into [main](https://codecov.io/gh/lightstep/otel-launcher-go/commit/8683ab3c34f654c4fd0b3220d21471d1382f7490?el=desc) will **decrease** coverage by `3.20%`.
> The diff coverage is `80.45%`.

[![Impacted file tree graph](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13/graphs/tree.svg?width=650&height=150&src=pr&token=bKAtQGZKIp)](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##             main      #13      +/-   ##
==========================================
- Coverage   94.28%   91.07%   -3.21%     
==========================================
  Files           2        3       +1     
  Lines         210      269      +59     
==========================================
+ Hits          198      245      +47     
- Misses          7       14       +7     
- Partials        5       10       +5     
```


| [Impacted Files](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [examples/tracing/trace.go](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13/diff?src=pr&el=tree#diff-ZXhhbXBsZXMvdHJhY2luZy90cmFjZS5nbw==) | `100.00% <ø> (ø)` | |
| [launcher/config.go](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13/diff?src=pr&el=tree#diff-bGF1bmNoZXIvY29uZmlnLmdv) | `88.34% <79.76%> (-3.66%)` | :arrow_down: |
| [examples/metrics/metrics.go](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13/diff?src=pr&el=tree#diff-ZXhhbXBsZXMvbWV0cmljcy9tZXRyaWNzLmdv) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=footer). Last update [8683ab3...fe99de1](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

jmacd: I will 💪 some tests.
codecov-commenter: # [Codecov](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=h1) Report
> Merging [#13](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=desc) into [main](https://codecov.io/gh/lightstep/otel-launcher-go/commit/8683ab3c34f654c4fd0b3220d21471d1382f7490?el=desc) will **decrease** coverage by `3.20%`.
> The diff coverage is `80.45%`.

[![Impacted file tree graph](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13/graphs/tree.svg?width=650&height=150&src=pr&token=bKAtQGZKIp)](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##             main      #13      +/-   ##
==========================================
- Coverage   94.28%   91.07%   -3.21%     
==========================================
  Files           2        3       +1     
  Lines         210      269      +59     
==========================================
+ Hits          198      245      +47     
- Misses          7       14       +7     
- Partials        5       10       +5     
```


| [Impacted Files](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [examples/tracing/trace.go](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13/diff?src=pr&el=tree#diff-ZXhhbXBsZXMvdHJhY2luZy90cmFjZS5nbw==) | `100.00% <ø> (ø)` | |
| [launcher/config.go](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13/diff?src=pr&el=tree#diff-bGF1bmNoZXIvY29uZmlnLmdv) | `88.34% <79.76%> (-3.66%)` | :arrow_down: |
| [examples/metrics/metrics.go](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13/diff?src=pr&el=tree#diff-ZXhhbXBsZXMvbWV0cmljcy9tZXRyaWNzLmdv) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=footer). Last update [8683ab3...a0ed935](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

codecov-commenter: # [Codecov](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=h1) Report
> Merging [#13](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=desc) into [main](https://codecov.io/gh/lightstep/otel-launcher-go/commit/8683ab3c34f654c4fd0b3220d21471d1382f7490?el=desc) will **decrease** coverage by `0.92%`.
> The diff coverage is `85.71%`.

[![Impacted file tree graph](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13/graphs/tree.svg?width=650&height=150&src=pr&token=bKAtQGZKIp)](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##             main      #13      +/-   ##
==========================================
- Coverage   94.28%   93.35%   -0.93%     
==========================================
  Files           2        3       +1     
  Lines         210      271      +61     
==========================================
+ Hits          198      253      +55     
- Misses          7       10       +3     
- Partials        5        8       +3     
```


| [Impacted Files](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [examples/tracing/trace.go](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13/diff?src=pr&el=tree#diff-ZXhhbXBsZXMvdHJhY2luZy90cmFjZS5nbw==) | `100.00% <ø> (ø)` | |
| [launcher/config.go](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13/diff?src=pr&el=tree#diff-bGF1bmNoZXIvY29uZmlnLmdv) | `91.34% <85.22%> (-0.66%)` | :arrow_down: |
| [examples/metrics/metrics.go](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13/diff?src=pr&el=tree#diff-ZXhhbXBsZXMvbWV0cmljcy9tZXRyaWNzLmdv) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=footer). Last update [8683ab3...8719bd5](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

codecov-commenter: # [Codecov](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=h1) Report
> Merging [#13](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=desc) into [main](https://codecov.io/gh/lightstep/otel-launcher-go/commit/8683ab3c34f654c4fd0b3220d21471d1382f7490?el=desc) will **decrease** coverage by `0.18%`.
> The diff coverage is `87.91%`.

[![Impacted file tree graph](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13/graphs/tree.svg?width=650&height=150&src=pr&token=bKAtQGZKIp)](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##             main      #13      +/-   ##
==========================================
- Coverage   94.28%   94.09%   -0.19%     
==========================================
  Files           2        3       +1     
  Lines         210      271      +61     
==========================================
+ Hits          198      255      +57     
- Misses          7        9       +2     
- Partials        5        7       +2     
```


| [Impacted Files](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [examples/tracing/trace.go](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13/diff?src=pr&el=tree#diff-ZXhhbXBsZXMvdHJhY2luZy90cmFjZS5nbw==) | `100.00% <ø> (ø)` | |
| [launcher/config.go](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13/diff?src=pr&el=tree#diff-bGF1bmNoZXIvY29uZmlnLmdv) | `92.30% <87.50%> (+0.30%)` | :arrow_up: |
| [examples/metrics/metrics.go](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13/diff?src=pr&el=tree#diff-ZXhhbXBsZXMvbWV0cmljcy9tZXRyaWNzLmdv) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=footer). Last update [8683ab3...86b1155](https://codecov.io/gh/lightstep/otel-launcher-go/pull/13?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

jmacd: None of the remaining un-covered code from launcher/config.go are easy to add tests for, since they depend on errors that are very difficult to trigger in the underlying setup and shutdown methods (that really shouldn't be failing). @codeboten PTAL.
jmacd: Will you merge? I think an owner can override the `codecov` status. 

Patch:
diff --git a/README.md b/README.md
index b0b8f0d..b5ea851 100644
--- a/README.md
+++ b/README.md
@@ -42,12 +42,15 @@ Additional options
 |WithServiceVersion         |LS_SERVICE_VERSION                 |n       |unknown                         |
 |WithSpanExporterEndpoint   |OTEL_EXPORTER_OTLP_SPAN_ENDPOINT   |n       |ingest.lightstep.com:443        |
 |WithSpanExporterInsecure   |OTEL_EXPORTER_OTLP_SPAN_INSECURE   |n       |false                           |
-|WithMetricExporterEndpoint |OTEL_EXPORTER_OTLP_METRIC_ENDPOINT |n       |ingest.lightstep.com:443/metrics|
+|WithMetricExporterEndpoint |OTEL_EXPORTER_OTLP_METRIC_ENDPOINT |n       |-                               |
 |WithMetricExporterInsecure |OTEL_EXPORTER_OTLP_METRIC_INSECURE |n       |false                           |
 |WithAccessToken            |LS_ACCESS_TOKEN                    |n       |-                               |
 |WithLogLevel               |OTEL_LOG_LEVEL                     |n       |info                            |
 |WithPropagators            |OTEL_PROPAGATORS                   |n       |b3                              |
 |WithResourceAttributes     |OTEL_RESOURCE_ATTRIBUTES           |n       |-                               |
+|WithMetricReportingPeriod  |OTEL_EXPORTER_OTLP_METRIC_PERIOD   |n       |30s                             |
+
+Note that metrics functionality is disabled by default.  Metrics funcionality can be enabled by setting OTEL_EXPORTER_OTLP_METRIC_ENDPOINT to a valid endpoint (e.g. ingest.lightstep.com:443/metrics).
 
 ### Principles behind Launcher
 
@@ -59,6 +62,8 @@ One of the key principles behind putting together Launcher is to make lives of O
 
 Although we understand that not all languages use the same format for configuration, we find this annoying. We decided that Launcher would allow users to use the same configuration file across all languages. In this case, we settled for `YAML` as the format, which was inspired by the OpenTelemetry Collector.
 
+When OpenTelemetry Metrics are enabled, Host and Runtime metrics instrumentation are started automatically.
+
 ##### Validation
 
 Another decision we made with launcher is to provide end users with a layer of validation of their configuration. This provides us the ability to give feedback to our users faster, so they can start collecting telemetry sooner.
diff --git a/examples/metrics/metrics.go b/examples/metrics/metrics.go
new file mode 100644
index 0000000..88b1993
--- /dev/null
+++ b/examples/metrics/metrics.go
@@ -0,0 +1,34 @@
+// Copyright Lightstep 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 main configures OpenTelemetry metrics and starts reporting
+// runtime and host metrics.  For example:
+//
+//   LS_SERVICE_NAME=foo \
+//   OTEL_EXPORTER_OTLP_SPAN_ENDPOINT=localhost:9999 \
+//   OTEL_EXPORTER_OTLP_METRIC_ENDPOINT=localhost:9999 \
+//   go run ./metrics.go
+
+package main
+
+import (
+	"time"
+
+	"github.com/lightstep/otel-launcher-go/launcher"
+)
+
+func main() {
+	defer launcher.ConfigureOpentelemetry().Shutdown()
+	time.Sleep(time.Second)
+}
diff --git a/examples/trace.go b/examples/tracing/trace.go
similarity index 100%
rename from examples/trace.go
rename to examples/tracing/trace.go
diff --git a/examples/trace_test.go b/examples/tracing/trace_test.go
similarity index 100%
rename from examples/trace_test.go
rename to examples/tracing/trace_test.go
diff --git a/go.mod b/go.mod
index bd62043..9e196b4 100644
--- a/go.mod
+++ b/go.mod
@@ -6,6 +6,8 @@ require (
 	github.com/sethvargo/go-envconfig v0.3.0
 	github.com/stretchr/testify v1.6.1
 	go.opentelemetry.io/collector v0.7.0
+	go.opentelemetry.io/contrib/instrumentation/host v0.11.0
+	go.opentelemetry.io/contrib/instrumentation/runtime v0.11.0
 	go.opentelemetry.io/otel v0.11.0
 	go.opentelemetry.io/otel/exporters/otlp v0.11.0
 	go.opentelemetry.io/otel/sdk v0.11.0
diff --git a/go.sum b/go.sum
index 36f1dbf..9d4d3f2 100644
--- a/go.sum
+++ b/go.sum
@@ -71,6 +71,8 @@ github.com/Shopify/sarama v1.26.4/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668A
 github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
 github.com/Songmu/retry v0.1.0/go.mod h1:7sXIW7eseB9fq0FUvigRcQMVLR9tuHI0Scok+rkpAuA=
 github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
+github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
+github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
 github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
 github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
 github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
@@ -209,6 +211,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
 github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
 github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
+github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
+github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
 github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
 github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
 github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
@@ -767,6 +771,8 @@ github.com/sethvargo/go-envconfig v0.3.0/go.mod h1:XZ2JRR7vhlBEO5zMmOpLgUhgYltqY
 github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs=
 github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc=
 github.com/shirou/gopsutil v0.0.0-20200517204708-c89193f22d93/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shirou/gopsutil v2.20.7+incompatible h1:Ymv4OD12d6zm+2yONe39VSmp2XooJe8za7ngOLW/o/w=
+github.com/shirou/gopsutil v2.20.7+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
 github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
 github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
 github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
@@ -875,10 +881,17 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opentelemetry.io/collector v0.7.0 h1:hZK0e2R/uvOrNe0bwqUzRygx3/4U4pkM0CcsfwFks8E=
 go.opentelemetry.io/collector v0.7.0/go.mod h1:E+8jXieKLiZHvPXt6/ZR5Arx6kVjS2RQrePN+lG+4fw=
+go.opentelemetry.io/contrib v0.11.0 h1:EQOdk+fxs7qp3wVIS5wCinwqNHfhD/DreQRY/VADO8s=
+go.opentelemetry.io/contrib v0.11.0/go.mod h1:ZE6zLnhbB+AmcDlcG57gEbtyUasUiaeppcDfBcrZabY=
+go.opentelemetry.io/contrib/instrumentation/host v0.11.0 h1:q2jTxxF1jTrf6D+Nu9WqBX5+x8EhPJxNAwy2YsqDMhM=
+go.opentelemetry.io/contrib/instrumentation/host v0.11.0/go.mod h1:PNuqJ0py7wLdZP3jpEbHRMqTFr3CK47ITXeyg2wDvMo=
+go.opentelemetry.io/contrib/instrumentation/runtime v0.11.0 h1:07+mIYsFFNEvRiEmeAl6ErKFDO48n3II4VMLTXbLH1o=
+go.opentelemetry.io/contrib/instrumentation/runtime v0.11.0/go.mod h1:DXWL4xDPxxl+Vd04sr8V6pH56HssOgF+ZUGX6pOO+Xo=
 go.opentelemetry.io/otel v0.11.0 h1:IN2tzQa9Gc4ZVKnTaMbPVcHjvzOdg5n9QfnmlqiET7E=
 go.opentelemetry.io/otel v0.11.0/go.mod h1:G8UCk+KooF2HLkgo8RHX9epABH/aRGYET7gQOqBVdB0=
 go.opentelemetry.io/otel/exporters/otlp v0.11.0 h1:lNOQd4CG+6ESHBzCZPAa+vX9HUS0hsWISM7rMAe568Q=
 go.opentelemetry.io/otel/exporters/otlp v0.11.0/go.mod h1:bn0EPKGl888/C1/mmjRPHpD3di0weFwwwIWcl0vk10Q=
+go.opentelemetry.io/otel/exporters/stdout v0.11.0/go.mod h1:XP4gbV2Ikc7/ZyTGtwrA7/FzrhWJr3nfRU+LRvhxY24=
 go.opentelemetry.io/otel/sdk v0.11.0 h1:bkDMymVj6gIkPfgC5ci5atq0OYbfUHSn8NvsmyfyMq4=
 go.opentelemetry.io/otel/sdk v0.11.0/go.mod h1:XbZ6MrzIZ+d+qr7pH0FwHIbCnANMvXYgkq4afL/IUMQ=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
diff --git a/launcher/config.go b/launcher/config.go
index 206fe02..0d41153 100644
--- a/launcher/config.go
+++ b/launcher/config.go
@@ -21,9 +21,12 @@ import (
 	"fmt"
 	"log"
 	"os"
+	"time"
 
 	"github.com/sethvargo/go-envconfig"
 	"go.opentelemetry.io/collector/translator/conventions"
+	hostMetrics "go.opentelemetry.io/contrib/instrumentation/host"
+	runtimeMetrics "go.opentelemetry.io/contrib/instrumentation/runtime"
 	"go.opentelemetry.io/otel"
 	"go.opentelemetry.io/otel/api/correlation"
 	"go.opentelemetry.io/otel/api/global"
@@ -31,6 +34,9 @@ import (
 	apitrace "go.opentelemetry.io/otel/api/trace"
 	"go.opentelemetry.io/otel/exporters/otlp"
 	"go.opentelemetry.io/otel/label"
+	controller "go.opentelemetry.io/otel/sdk/metric/controller/push"
+	processor "go.opentelemetry.io/otel/sdk/metric/processor/basic"
+	selector "go.opentelemetry.io/otel/sdk/metric/selector/simple"
 	"go.opentelemetry.io/otel/sdk/resource"
 	"go.opentelemetry.io/otel/sdk/trace"
 	"google.golang.org/grpc/credentials"
@@ -118,6 +124,14 @@ func WithErrorHandler(handler otel.ErrorHandler) Option {
 	}
 }
 
+// WithMetricReportingPeriod configures the metric reporting period,
+// how often the controller collects and exports metric data.
+func WithMetricReportingPeriod(p time.Duration) Option {
+	return func(c *Config) {
+		c.MetricReportingPeriod = fmt.Sprint(p)
+	}
+}
+
 type Logger interface {
 	Fatalf(format string, v ...interface{})
 	Debugf(format string, v ...interface{})
@@ -148,8 +162,13 @@ func (l *defaultHandler) Handle(err error) {
 	l.logger.Debugf("error: %v\n", err)
 }
 
-var (
-	defaultSpanExporterEndpoint = "ingest.lightstep.com:443"
+const (
+	// Note: these values should match the defaults used in `env` tags for Config fields.
+	// Note: the MetricExporterEndpoint currently defaults to "".  When LS is ready for OTLP metrics
+	// we'll set this to `DefaultMetricExporterEndpoint`.
+
+	DefaultSpanExporterEndpoint   = "ingest.lightstep.com:443"
+	DefaultMetricExporterEndpoint = "ingest.lightstep.com:443"
 )
 
 type Config struct {
@@ -157,17 +176,29 @@ type Config struct {
 	SpanExporterEndpointInsecure   bool     `env:"OTEL_EXPORTER_OTLP_SPAN_INSECURE,default=false"`
 	ServiceName                    string   `env:"LS_SERVICE_NAME"`
 	ServiceVersion                 string   `env:"LS_SERVICE_VERSION,default=unknown"`
-	MetricExporterEndpoint         string   `env:"OTEL_EXPORTER_OTLP_METRIC_ENDPOINT,default=ingest.lightstep.com:443/metrics"`
+	MetricExporterEndpoint         string   `env:"OTEL_EXPORTER_OTLP_METRIC_ENDPOINT"`
 	MetricExporterEndpointInsecure bool     `env:"OTEL_EXPORTER_OTLP_METRIC_INSECURE,default=false"`
 	AccessToken                    string   `env:"LS_ACCESS_TOKEN"`
 	LogLevel                       string   `env:"OTEL_LOG_LEVEL,default=info"`
 	Propagators                    []string `env:"OTEL_PROPAGATORS,default=b3"`
+	MetricReportingPeriod          string   `env:"OTEL_EXPORTER_OTLP_METRIC_PERIOD,default=30s"`
 	resourceAttributes             map[string]string
 	Resource                       *resource.Resource
 	logger                         Logger
 	errorHandler                   otel.ErrorHandler
 }
 
+func checkEndpointDefault(value, defValue string) error {
+	if value == "" {
+		// The endpoint is disabled.
+		return nil
+	}
+	if value == defValue {
+		return fmt.Errorf("invalid configuration: access token missing, must be set when reporting to %s. Set LS_ACCESS_TOKEN env var or configure WithAccessToken in code", value)
+	}
+	return nil
+}
+
 func validateConfiguration(c Config) error {
 	if len(c.ServiceName) == 0 {
 		serviceNameSet := false
@@ -185,8 +216,14 @@ func validateConfiguration(c Config) error {
 	}
 
 	accessTokenLen := len(c.AccessToken)
-	if accessTokenLen == 0 && c.SpanExporterEndpoint == defaultSpanExporterEndpoint {
-		return fmt.Errorf("invalid configuration: access token missing, must be set when reporting to %s. Set LS_ACCESS_TOKEN env var or configure WithAccessToken in code", c.SpanExporterEndpoint)
+	if accessTokenLen == 0 {
+		if err := checkEndpointDefault(c.SpanExporterEndpoint, DefaultSpanExporterEndpoint); err != nil {
+			return err
+		}
+
+		if err := checkEndpointDefault(c.MetricExporterEndpoint, DefaultMetricExporterEndpoint); err != nil {
+			return err
+		}
 	}
 
 	if accessTokenLen > 0 && (accessTokenLen != 32 && accessTokenLen != 84 && accessTokenLen != 104) {
@@ -197,9 +234,7 @@ func validateConfiguration(c Config) error {
 
 func newConfig(opts ...Option) Config {
 	var c Config
-	if err := envconfig.Process(context.Background(), &c); err != nil {
-		log.Fatal(err)
-	}
+	envError := envconfig.Process(context.Background(), &c)
 	c.logger = &DefaultLogger{}
 	c.errorHandler = &defaultHandler{logger: c.logger}
 	var defaultOpts []Option
@@ -209,11 +244,16 @@ func newConfig(opts ...Option) Config {
 	}
 	c.Resource = newResource(&c)
 
+	if envError != nil {
+		c.logger.Fatalf("environment error: %v", envError)
+	}
+
 	return c
 }
 
 type Launcher struct {
-	spanExporter *otlp.Exporter
+	config        Config
+	shutdownFuncs []func() error
 }
 
 // configurePropagators configures B3 propagation by default
@@ -278,65 +318,143 @@ func newResource(c *Config) *resource.Resource {
 	return resource.New(attributes...)
 }
 
-func ConfigureOpentelemetry(opts ...Option) Launcher {
-	c := newConfig(opts...)
-
-	if c.LogLevel == "debug" {
-		c.logger.Debugf("debug logging enabled")
-		c.logger.Debugf("configuration")
-		s, _ := json.MarshalIndent(c, "", "\t")
-		c.logger.Debugf(string(s))
-	}
-
-	err := validateConfiguration(c)
-	if err != nil {
-		c.logger.Fatalf(err.Error())
-	}
-
+func newExporter(accessToken, endpoint string, insecure bool) (*otlp.Exporter, error) {
 	headers := map[string]string{
-		"lightstep-access-token": c.AccessToken,
+		"lightstep-access-token": accessToken,
 	}
 
 	secureOption := otlp.WithTLSCredentials(credentials.NewClientTLSFromCert(nil, ""))
-	if c.SpanExporterEndpointInsecure {
+	if insecure {
 		secureOption = otlp.WithInsecure()
 	}
-	exporter, err := otlp.NewExporter(
+	return otlp.NewExporter(
 		secureOption,
-		otlp.WithAddress(c.SpanExporterEndpoint),
+		otlp.WithAddress(endpoint),
 		otlp.WithHeaders(headers),
 	)
+}
+
+func setupTracing(c Config) (func() error, error) {
+	if c.SpanExporterEndpoint == "" {
+		c.logger.Debugf("tracing is disabled by configuration: no endpoint set")
+		return nil, nil
+	}
+	spanExporter, err := newExporter(c.AccessToken, c.SpanExporterEndpoint, c.SpanExporterEndpointInsecure)
 	if err != nil {
-		c.logger.Fatalf("failed to create exporter: %v", err)
+		return nil, fmt.Errorf("failed to create span exporter: %v", err)
 	}
 
 	tp, err := trace.NewProvider(
 		trace.WithConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}),
-		trace.WithSyncer(exporter),
+		trace.WithSyncer(spanExporter),
 		trace.WithResource(c.Resource),
 	)
 	if err != nil {
-		c.logger.Fatalf(err.Error())
+		return nil, err
 	}
 
-	err = configurePropagators(&c)
-	if err != nil {
-		c.logger.Fatalf(err.Error())
+	if err = configurePropagators(&c); err != nil {
+		return nil, err
 	}
 
 	global.SetTraceProvider(tp)
 
+	return func() error {
+		return spanExporter.Stop()
+	}, nil
+}
+
+type setupFunc func(Config) (func() error, error)
+
+func setupMetrics(c Config) (func() error, error) {
+	if c.MetricExporterEndpoint == "" {
+		c.logger.Debugf("metrics are disabled by configuration: no endpoint set")
+		return nil, nil
+	}
+	metricExporter, err := newExporter(c.AccessToken, c.MetricExporterEndpoint, c.MetricExporterEndpointInsecure)
+	if err != nil {
+		return nil, fmt.Errorf("failed to create metric exporter: %v", err)
+	}
+
+	period := controller.DefaultPushPeriod
+	if c.MetricReportingPeriod != "" {
+		period, err = time.ParseDuration(c.MetricReportingPeriod)
+		if err != nil {
+			return nil, fmt.Errorf("invalid metric reporting period: %v", err)
+		}
+		if period <= 0 {
+
+			return nil, fmt.Errorf("invalid metric reporting period: %v", c.MetricReportingPeriod)
+		}
+	}
+	pusher := controller.New(
+		processor.New(
+			selector.NewWithInexpensiveDistribution(),
+			metricExporter,
+		),
+		metricExporter,
+		controller.WithResource(c.Resource),
+		controller.WithPeriod(period),
+	)
+
+	pusher.Start()
+
+	provider := pusher.Provider()
+
+	if err = runtimeMetrics.Start(runtimeMetrics.WithMeterProvider(provider)); err != nil {
+		return nil, fmt.Errorf("failed to start runtime metrics: %v", err)
+	}
+
+	if err = hostMetrics.Start(hostMetrics.WithMeterProvider(provider)); err != nil {
+		return nil, fmt.Errorf("failed to start host metrics: %v", err)
+	}
+
+	global.SetMeterProvider(provider)
+	return func() error {
+		pusher.Stop()
+		return metricExporter.Stop()
+	}, nil
+}
+
+func ConfigureOpentelemetry(opts ...Option) Launcher {
+	c := newConfig(opts...)
+
+	if c.LogLevel == "debug" {
+		c.logger.Debugf("debug logging enabled")
+		c.logger.Debugf("configuration")
+		s, _ := json.MarshalIndent(c, "", "\t")
+		c.logger.Debugf(string(s))
+	}
+
+	err := validateConfiguration(c)
+	if err != nil {
+		c.logger.Fatalf("configuration error: %v", err)
+	}
+
 	if c.errorHandler != nil {
 		global.SetErrorHandler(c.errorHandler)
 	}
-	return Launcher{
-		spanExporter: exporter,
+
+	ls := Launcher{
+		config: c,
 	}
+	for _, setup := range []setupFunc{setupTracing, setupMetrics} {
+		shutdown, err := setup(c)
+		if err != nil {
+			c.logger.Fatalf("setup error: %v", err)
+			continue
+		}
+		if shutdown != nil {
+			ls.shutdownFuncs = append(ls.shutdownFuncs, shutdown)
+		}
+	}
+	return ls
 }
 
-func (ls *Launcher) Shutdown() {
-	err := ls.spanExporter.Stop()
-	if err != nil {
-		log.Fatalf("failed to stop exporter: %v", err)
+func (ls Launcher) Shutdown() {
+	for _, shutdown := range ls.shutdownFuncs {
+		if err := shutdown(); err != nil {
+			ls.config.logger.Fatalf("failed to stop exporter: %v", err)
+		}
 	}
 }


Test patch:
diff --git a/examples/metrics/metrics_test.go b/examples/metrics/metrics_test.go
new file mode 100644
index 0000000..4447498
--- /dev/null
+++ b/examples/metrics/metrics_test.go
@@ -0,0 +1,29 @@
+// Copyright Lightstep 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 main
+
+import (
+	"os"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestMinimumConfiguration(t *testing.T) {
+	os.Setenv("LS_SERVICE_NAME", "test-service-name")
+	os.Setenv("OTEL_EXPORTER_OTLP_SPAN_ENDPOINT", "invalid-endpoint")
+	os.Setenv("OTEL_EXPORTER_OTLP_METRIC_ENDPOINT", "invalid-endpoint")
+	assert.NotPanics(t, main)
+}
diff --git a/launcher/config_test.go b/launcher/config_test.go
index e0298b4..66c05a0 100644
--- a/launcher/config_test.go
+++ b/launcher/config_test.go
@@ -19,6 +19,7 @@ import (
 	"os"
 	"strings"
 	"testing"
+	"time"
 
 	"github.com/stretchr/testify/assert"
 	"go.opentelemetry.io/otel/api/correlation"
@@ -28,20 +29,52 @@ import (
 	"go.opentelemetry.io/otel/sdk/resource"
 )
 
+const (
+	expectedAccessTokenLengthError  = "invalid configuration: access token length incorrect. Ensure token is set correctly"
+	expectedAccessTokenMissingError = "invalid configuration: access token missing, must be set when reporting to ingest.lightstep.com"
+	expectedTracingDisabledMessage  = "tracing is disabled by configuration: no endpoint set"
+	expectedMetricsDisabledMessage  = "metrics are disabled by configuration: no endpoint set"
+)
+
 type testLogger struct {
 	output []string
 }
 
-func (t *testLogger) addOutput(output string) {
-	t.output = append(t.output, output)
+func (logger *testLogger) addOutput(output string) {
+	logger.output = append(logger.output, output)
+}
+
+func (logger *testLogger) Fatalf(format string, v ...interface{}) {
+	logger.addOutput(fmt.Sprintf(format, v...))
+}
+
+func (logger *testLogger) Debugf(format string, v ...interface{}) {
+	logger.addOutput(fmt.Sprintf(format, v...))
 }
 
-func (t *testLogger) Fatalf(format string, v ...interface{}) {
-	t.addOutput(fmt.Sprintf(format, v...))
+func (logger *testLogger) requireContains(t *testing.T, expected string) {
+	t.Helper()
+	for _, output := range logger.output {
+		if strings.Contains(output, expected) {
+			return
+		}
+	}
+
+	t.Errorf("\nString unexpectedly not found: %v\nIn: %v", expected, logger.output)
+}
+
+func (logger *testLogger) requireNotContains(t *testing.T, expected string) {
+	t.Helper()
+	for _, output := range logger.output {
+		if strings.Contains(output, expected) {
+			t.Errorf("\nString unexpectedly found: %v\nIn: %v", expected, logger.output)
+			return
+		}
+	}
 }
 
-func (t *testLogger) Debugf(format string, v ...interface{}) {
-	t.addOutput(fmt.Sprintf(format, v...))
+func (logger *testLogger) reset() {
+	logger.output = nil
 }
 
 type testErrorHandler struct {
@@ -51,75 +84,187 @@ func (t *testErrorHandler) Handle(err error) {
 	fmt.Printf("test error handler handled error: %v\n", err)
 }
 
+func fakeAccessToken() string {
+	return strings.Repeat("1", 32)
+}
+
 func TestInvalidServiceName(t *testing.T) {
-	logger := &testLogger{output: []string{}}
+	logger := &testLogger{}
 	lsOtel := ConfigureOpentelemetry(WithLogger(logger))
 	defer lsOtel.Shutdown()
 
 	expected := "invalid configuration: service name missing"
-	if !strings.Contains(logger.output[0], expected) {
-		t.Errorf("\nString not found: %v\nIn: %v", expected, logger.output[0])
-	}
+	logger.requireContains(t, expected)
 }
 
-func TestInvalidMissingAccessToken(t *testing.T) {
-	logger := &testLogger{output: []string{}}
+func testInvalidMissingAccessToken(t *testing.T, opts ...Option) {
+	logger := &testLogger{}
 	lsOtel := ConfigureOpentelemetry(
-		WithLogger(logger),
-		WithServiceName("test-service"),
+		append(opts,
+			WithLogger(logger),
+			WithServiceName("test-service"),
+		)...,
 	)
 	defer lsOtel.Shutdown()
 
-	expected := "invalid configuration: access token missing, must be set when reporting to ingest.lightstep.com:443"
-	if !strings.Contains(logger.output[0], expected) {
-		t.Errorf("\nString not found: %v\nIn: %v", expected, logger.output[0])
-	}
+	logger.requireContains(t, expectedAccessTokenMissingError)
+}
+
+func TestInvalidMissingDefaultAccessToken(t *testing.T) {
+	testInvalidMissingAccessToken(
+		t,
+		WithAccessToken(""),
+	)
+}
+
+func TestInvalidTraceDefaultAccessToken(t *testing.T) {
+	testInvalidMissingAccessToken(t,
+		WithAccessToken(""),
+		WithSpanExporterEndpoint(DefaultSpanExporterEndpoint),
+		WithMetricExporterEndpoint("127.0.0.1:4000"),
+	)
+}
+
+func TestInvalidMetricDefaultAccessToken(t *testing.T) {
+	testInvalidMissingAccessToken(t,
+		WithAccessToken(""),
+		WithSpanExporterEndpoint("127.0.0.1:4000"),
+		WithMetricExporterEndpoint(DefaultMetricExporterEndpoint))
 }
 
-func TestInvalidAccessToken(t *testing.T) {
-	logger := &testLogger{output: []string{}}
+func testInvalidAccessToken(t *testing.T, opts ...Option) {
+	logger := &testLogger{}
 	lsOtel := ConfigureOpentelemetry(
-		WithLogger(logger),
-		WithServiceName("test-service"),
-		WithSpanExporterEndpoint("test123"),
+		append(opts,
+			WithLogger(logger),
+			WithServiceName("test-service"),
+		)...,
+	)
+	defer lsOtel.Shutdown()
+
+	logger.requireContains(t, expectedAccessTokenLengthError)
+}
+
+func TestInvalidTraceAccessTokenLength(t *testing.T) {
+	testInvalidAccessToken(t,
+		WithSpanExporterEndpoint("127.0.0.1:4000"),
+		WithAccessToken("1234"),
+	)
+}
+
+func TestInvalidMetricAccessTokenLength(t *testing.T) {
+	testInvalidAccessToken(t,
+		WithSpanExporterEndpoint(""),
+		WithMetricExporterEndpoint("127.0.0.1:4000"),
 		WithAccessToken("1234"),
 	)
+}
+
+func testEndpointDisabled(t *testing.T, expected string, opts ...Option) {
+	logger := &testLogger{}
+	lsOtel := ConfigureOpentelemetry(
+		append(opts,
+			WithLogger(logger),
+			WithServiceName("test-service"),
+		)...,
+	)
 	defer lsOtel.Shutdown()
 
-	expected := "invalid configuration: access token length incorrect. Ensure token is set correctly"
-	if !strings.Contains(logger.output[0], expected) {
-		t.Errorf("\nString not found: %v\nIn: %v", expected, logger.output[0])
-	}
+	logger.requireNotContains(t, expectedAccessTokenMissingError)
+	logger.requireContains(t, expected)
+}
+
+func TestTraceEndpointDisabled(t *testing.T) {
+	testEndpointDisabled(
+		t,
+		expectedTracingDisabledMessage,
+		WithAccessToken(fakeAccessToken()),
+		WithSpanExporterEndpoint(""),
+	)
+}
+
+func TestMetricEndpointDisabled(t *testing.T) {
+	testEndpointDisabled(
+		t,
+		expectedMetricsDisabledMessage,
+		WithAccessToken(fakeAccessToken()),
+		WithMetricExporterEndpoint(""),
+	)
 }
 
 func TestValidConfig(t *testing.T) {
-	logger := &testLogger{output: []string{}}
+	logger := &testLogger{}
 	lsOtel := ConfigureOpentelemetry(
 		WithLogger(logger),
 		WithServiceName("test-service"),
-		WithAccessToken(strings.Repeat("1", 32)),
+		WithAccessToken(fakeAccessToken()),
 		WithErrorHandler(&testErrorHandler{}),
 	)
 	defer lsOtel.Shutdown()
-	expected := 0
-	if len(logger.output) > expected {
-		t.Errorf("\nExpected: %v\ngot: %v", expected, len(logger.output))
-	}
+
+	logger.requireContains(t, expectedMetricsDisabledMessage)
+	logger.reset()
 
 	lsOtel = ConfigureOpentelemetry(
 		WithLogger(logger),
 		WithServiceName("test-service"),
+		WithMetricExporterEndpoint("localhost:443"),
 		WithSpanExporterEndpoint("localhost:443"),
 	)
 	defer lsOtel.Shutdown()
-	expected = 0
-	if len(logger.output) > expected {
-		t.Errorf("\nExpected: %v\ngot: %v", expected, len(logger.output))
+
+	if len(logger.output) > 0 {
+		t.Errorf("\nExpected: no logs\ngot: %v", logger.output)
 	}
 }
 
+func TestInvalidEnvironment(t *testing.T) {
+	os.Setenv("OTEL_EXPORTER_OTLP_METRIC_INSECURE", "bleargh")
+
+	logger := &testLogger{}
+	lsOtel := ConfigureOpentelemetry(
+		WithLogger(logger),
+		WithServiceName("test-service"),
+	)
+	defer lsOtel.Shutdown()
+
+	logger.requireContains(t, "environment error")
+	unsetEnvironment()
+}
+
+func TestInvalidMetricsPushIntervalEnv(t *testing.T) {
+	os.Setenv("OTEL_EXPORTER_OTLP_METRIC_PERIOD", "300million")
+
+	logger := &testLogger{}
+	lsOtel := ConfigureOpentelemetry(
+		WithLogger(logger),
+		WithServiceName("test-service"),
+		WithSpanExporterEndpoint("127.0.0.1:4000"),
+		WithMetricExporterEndpoint("127.0.0.1:4000"),
+	)
+	defer lsOtel.Shutdown()
+
+	logger.requireContains(t, "setup error: invalid metric reporting period")
+	unsetEnvironment()
+}
+
+func TestInvalidMetricsPushIntervalConfig(t *testing.T) {
+	logger := &testLogger{}
+	lsOtel := ConfigureOpentelemetry(
+		WithLogger(logger),
+		WithServiceName("test-service"),
+		WithSpanExporterEndpoint("127.0.0.1:4000"),
+		WithMetricExporterEndpoint("127.0.0.1:4000"),
+		WithMetricReportingPeriod(-time.Second),
+	)
+	defer lsOtel.Shutdown()
+
+	logger.requireContains(t, "setup error: invalid metric reporting period")
+	unsetEnvironment()
+}
+
 func TestDebugEnabled(t *testing.T) {
-	logger := &testLogger{output: []string{}}
+	logger := &testLogger{}
 	lsOtel := ConfigureOpentelemetry(
 		WithLogger(logger),
 		WithServiceName("test-service"),
@@ -160,8 +305,9 @@ func TestDefaultConfig(t *testing.T) {
 		ServiceVersion:                 "unknown",
 		SpanExporterEndpoint:           "ingest.lightstep.com:443",
 		SpanExporterEndpointInsecure:   false,
-		MetricExporterEndpoint:         "ingest.lightstep.com:443/metrics",
+		MetricExporterEndpoint:         "",
 		MetricExporterEndpointInsecure: false,
+		MetricReportingPeriod:          "30s",
 		AccessToken:                    "",
 		LogLevel:                       "info",
 		Propagators:                    []string{"b3"},
@@ -196,6 +342,7 @@ func TestEnvironmentVariables(t *testing.T) {
 		SpanExporterEndpointInsecure:   true,
 		MetricExporterEndpoint:         "metrics-url",
 		MetricExporterEndpointInsecure: true,
+		MetricReportingPeriod:          "30s",
 		AccessToken:                    "token",
 		LogLevel:                       "debug",
 		Propagators:                    []string{"b3", "w3c"},
@@ -241,6 +388,7 @@ func TestConfigurationOverrides(t *testing.T) {
 		SpanExporterEndpointInsecure:   false,
 		MetricExporterEndpoint:         "override-metrics-url",
 		MetricExporterEndpointInsecure: false,
+		MetricReportingPeriod:          "30s",
 		AccessToken:                    "override-access-token",
 		LogLevel:                       "info",
 		Propagators:                    []string{"b3"},
@@ -349,7 +497,7 @@ func TestConfigureResourcesAttributes(t *testing.T) {
 
 func TestServiceNameViaResourceAttributes(t *testing.T) {
 	os.Setenv("OTEL_RESOURCE_ATTRIBUTES", "service.name=test-service-b")
-	logger := &testLogger{output: []string{}}
+	logger := &testLogger{}
 	lsOtel := ConfigureOpentelemetry(WithLogger(logger))
 	defer lsOtel.Shutdown()
 
@@ -384,6 +532,7 @@ func unsetEnvironment() {
 		"OTEL_LOG_LEVEL",
 		"OTEL_PROPAGATORS",
 		"OTEL_RESOURCE_ATTRIBUTES",
+		"OTEL_EXPORTER_OTLP_METRIC_PERIOD",
 	}
 	for _, envvar := range vars {
 		os.Unsetenv(envvar)