Skip to content

Commit

Permalink
Add and use missing metrics environment variables
Browse files Browse the repository at this point in the history
Fixes #2967
  • Loading branch information
ocelotl committed Oct 7, 2022
1 parent 6e9af76 commit 45c59ff
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
from opentelemetry.exporter.otlp.proto.grpc.exporter import (
OTLPExporterMixin,
get_resource_data,
_get_credentials,
environ_to_compression,
)
from opentelemetry.proto.collector.metrics.v1.metrics_service_pb2 import (
ExportMetricsServiceRequest,
Expand All @@ -30,7 +32,12 @@
from opentelemetry.proto.common.v1.common_pb2 import InstrumentationScope
from opentelemetry.proto.metrics.v1 import metrics_pb2 as pb2
from opentelemetry.sdk.environment_variables import (
OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE,
OTEL_EXPORTER_OTLP_METRICS_COMPRESSION,
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT,
OTEL_EXPORTER_OTLP_METRICS_HEADERS,
OTEL_EXPORTER_OTLP_METRICS_INSECURE,
OTEL_EXPORTER_OTLP_METRICS_TIMEOUT,
OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE,
)
from opentelemetry.sdk.metrics import (
Expand Down Expand Up @@ -65,6 +72,7 @@ class OTLPMetricExporter(
"""OTLP metric exporter
Args:
endpoint: Target URL to which the exporter is going to send metrics
max_export_batch_size: Maximum number of data points to export in a single request. This is to deal with
gRPC's 4MB message size limit. If not set there is no limit to the number of data points in a request.
If it is set and the number of data points exceeds the max, the request will be split.
Expand All @@ -91,6 +99,25 @@ def __init__(
if insecure is not None:
insecure = insecure.lower() == "true"

if (
not insecure
and environ.get(OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE) is not None
):
credentials = _get_credentials(
credentials, OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE
)

environ_timeout = environ.get(OTEL_EXPORTER_OTLP_METRICS_TIMEOUT)
environ_timeout = (
int(environ_timeout) if environ_timeout is not None else None
)

compression = (
environ_to_compression(OTEL_EXPORTER_OTLP_METRICS_COMPRESSION)
if compression is None
else compression
)

instrument_class_temporality = {}
if (
environ.get(
Expand Down Expand Up @@ -125,13 +152,15 @@ def __init__(
preferred_temporality=instrument_class_temporality,
preferred_aggregation=preferred_aggregation,
)

OTLPExporterMixin.__init__(
self,
endpoint=endpoint,
endpoint=endpoint
or environ.get(OTEL_EXPORTER_OTLP_METRICS_ENDPOINT),
insecure=insecure,
credentials=credentials,
headers=headers,
timeout=timeout,
headers=headers or environ.get(OTEL_EXPORTER_OTLP_METRICS_HEADERS),
timeout=timeout or environ_timeout,
compression=compression,
)

Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@

# pylint: disable=too-many-lines
from concurrent.futures import ThreadPoolExecutor
from os.path import dirname
from typing import List
from unittest import TestCase
from unittest.mock import patch

from google.protobuf.duration_pb2 import Duration
from google.rpc.error_details_pb2 import RetryInfo
from grpc import StatusCode, server
from grpc import ChannelCredentials, Compression, StatusCode, server

from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import (
OTLPMetricExporter,
Expand All @@ -43,8 +44,14 @@
Resource as OTLPResource,
)
from opentelemetry.sdk.environment_variables import (
OTEL_EXPORTER_OTLP_COMPRESSION,
OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE,
OTEL_EXPORTER_OTLP_METRICS_COMPRESSION,
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT,
OTEL_EXPORTER_OTLP_METRICS_HEADERS,
OTEL_EXPORTER_OTLP_METRICS_INSECURE,
OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE,
OTEL_EXPORTER_OTLP_METRICS_TIMEOUT,
)
from opentelemetry.sdk.metrics import (
Counter,
Expand All @@ -71,6 +78,8 @@
)
from opentelemetry.test.metrictestutil import _generate_gauge, _generate_sum

THIS_DIR = dirname(__file__)


class MetricsServiceServicerUNAVAILABLEDelay(MetricsServiceServicer):
# pylint: disable=invalid-name,unused-argument,no-self-use
Expand Down Expand Up @@ -119,6 +128,8 @@ def Export(self, request, context):


class TestOTLPMetricExporter(TestCase):
# pylint: disable=too-many-public-methods

def setUp(self):

self.exporter = OTLPMetricExporter()
Expand Down Expand Up @@ -348,6 +359,33 @@ def test_preferred_temporality(self):
AggregationTemporality.CUMULATIVE,
)

@patch.dict(
"os.environ",
{
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT: "collector:4317",
OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE: THIS_DIR
+ "/fixtures/test.cert",
OTEL_EXPORTER_OTLP_METRICS_HEADERS: " key1=value1,KEY2 = value=2",
OTEL_EXPORTER_OTLP_METRICS_TIMEOUT: "10",
OTEL_EXPORTER_OTLP_METRICS_COMPRESSION: "gzip",
},
)
@patch(
"opentelemetry.exporter.otlp.proto.grpc.exporter.OTLPExporterMixin.__init__"
)
def test_env_variables(self, mock_exporter_mixin):
OTLPMetricExporter()

self.assertTrue(len(mock_exporter_mixin.call_args_list) == 1)
_, kwargs = mock_exporter_mixin.call_args_list[0]

self.assertEqual(kwargs["endpoint"], "collector:4317")
self.assertEqual(kwargs["headers"], " key1=value1,KEY2 = value=2")
self.assertEqual(kwargs["timeout"], 10)
self.assertEqual(kwargs["compression"], Compression.Gzip)
self.assertIsNotNone(kwargs["credentials"])
self.assertIsInstance(kwargs["credentials"], ChannelCredentials)

@patch(
"opentelemetry.exporter.otlp.proto.grpc.exporter.ssl_channel_credentials"
)
Expand All @@ -362,6 +400,36 @@ def test_no_credentials_error(
OTLPMetricExporter(insecure=False)
self.assertTrue(mock_ssl_channel.called)

@patch.dict(
"os.environ",
{OTEL_EXPORTER_OTLP_METRICS_HEADERS: " key1=value1,KEY2 = VALUE=2 "},
)
@patch(
"opentelemetry.exporter.otlp.proto.grpc.exporter.ssl_channel_credentials"
)
@patch("opentelemetry.exporter.otlp.proto.grpc.exporter.secure_channel")
# pylint: disable=unused-argument
def test_otlp_headers_from_env(self, mock_ssl_channel, mock_secure):
exporter = OTLPMetricExporter()
# pylint: disable=protected-access
self.assertEqual(
exporter._headers, (("key1", "value1"), ("key2", "VALUE=2"))
)
exporter = OTLPMetricExporter(
headers=(("key3", "value3"), ("key4", "value4"))
)
# pylint: disable=protected-access
self.assertEqual(
exporter._headers, (("key3", "value3"), ("key4", "value4"))
)
exporter = OTLPMetricExporter(
headers={"key5": "value5", "key6": "value6"}
)
# pylint: disable=protected-access
self.assertEqual(
exporter._headers, (("key5", "value5"), ("key6", "value6"))
)

@patch.dict(
"os.environ",
{OTEL_EXPORTER_OTLP_METRICS_INSECURE: "True"},
Expand Down Expand Up @@ -449,6 +517,42 @@ def test_otlp_exporter_endpoint(self, mock_secure, mock_insecure):
)
mock_method.reset_mock()

# pylint: disable=no-self-use
@patch("opentelemetry.exporter.otlp.proto.grpc.exporter.insecure_channel")
@patch.dict("os.environ", {OTEL_EXPORTER_OTLP_COMPRESSION: "gzip"})
def test_otlp_exporter_otlp_compression_envvar(
self, mock_insecure_channel
):
"""Just OTEL_EXPORTER_OTLP_COMPRESSION should work"""
OTLPMetricExporter(insecure=True)
mock_insecure_channel.assert_called_once_with(
"localhost:4317", compression=Compression.Gzip
)

# pylint: disable=no-self-use
@patch("opentelemetry.exporter.otlp.proto.grpc.exporter.insecure_channel")
@patch.dict("os.environ", {OTEL_EXPORTER_OTLP_COMPRESSION: "gzip"})
def test_otlp_exporter_otlp_compression_kwarg(self, mock_insecure_channel):
"""Specifying kwarg should take precedence over env"""
OTLPMetricExporter(
insecure=True, compression=Compression.NoCompression
)
mock_insecure_channel.assert_called_once_with(
"localhost:4317", compression=Compression.NoCompression
)

# pylint: disable=no-self-use
@patch("opentelemetry.exporter.otlp.proto.grpc.exporter.insecure_channel")
@patch.dict("os.environ", {})
def test_otlp_exporter_otlp_compression_unspecified(
self, mock_insecure_channel
):
"""No env or kwarg should be NoCompression"""
OTLPMetricExporter(insecure=True)
mock_insecure_channel.assert_called_once_with(
"localhost:4317", compression=Compression.NoCompression
)

@patch("opentelemetry.exporter.otlp.proto.grpc.exporter.expo")
@patch("opentelemetry.exporter.otlp.proto.grpc.exporter.sleep")
def test_unavailable(self, mock_sleep, mock_expo):
Expand Down
44 changes: 44 additions & 0 deletions opentelemetry-sdk/src/opentelemetry/sdk/environment_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,15 @@
A scheme of https indicates a secure connection and takes precedence over this configuration setting.
"""

OTEL_EXPORTER_OTLP_METRICS_ENDPOINT = "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT"
"""
.. envvar:: OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
The :envvar:`OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` target to which the metrics exporter is going to send metrics.
The endpoint MUST be a valid URL host, and MAY contain a scheme (http or https), port and path.
A scheme of https indicates a secure connection and takes precedence over this configuration setting.
"""

OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE = "OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE"
"""
.. envvar:: OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE
Expand All @@ -343,6 +352,16 @@
TLS credentials of gRPC client for traces. Should only be used for a secure connection for tracing.
"""

OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE = (
"OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE"
)
"""
.. envvar:: OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE
The :envvar:`OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE` stores the path to the certificate file for
TLS credentials of gRPC client for metrics. Should only be used for a secure connection for exporting metrics.
"""

OTEL_EXPORTER_OTLP_TRACES_HEADERS = "OTEL_EXPORTER_OTLP_TRACES_HEADERS"
"""
.. envvar:: OTEL_EXPORTER_OTLP_TRACES_HEADERS
Expand All @@ -351,6 +370,13 @@
associated with gRPC or HTTP requests.
"""

OTEL_EXPORTER_OTLP_METRICS_HEADERS = "OTEL_EXPORTER_OTLP_METRICS_HEADERS"
"""
.. envvar:: OTEL_EXPORTER_OTLP_METRICS_HEADERS
The :envvar:`OTEL_EXPORTER_OTLP_METRICS_HEADERS` contains the key-value pairs to be used as headers for metrics
associated with gRPC or HTTP requests.
"""

OTEL_EXPORTER_OTLP_TRACES_COMPRESSION = "OTEL_EXPORTER_OTLP_TRACES_COMPRESSION"
"""
Expand All @@ -360,6 +386,16 @@
exporter. If both are present, this takes higher precedence.
"""

OTEL_EXPORTER_OTLP_METRICS_COMPRESSION = (
"OTEL_EXPORTER_OTLP_METRICS_COMPRESSION"
)
"""
.. envvar:: OTEL_EXPORTER_OTLP_METRICS_COMPRESSION
Same as :envvar:`OTEL_EXPORTER_OTLP_COMPRESSION` but only for the metric
exporter. If both are present, this takes higher precedence.
"""

OTEL_EXPORTER_OTLP_TRACES_TIMEOUT = "OTEL_EXPORTER_OTLP_TRACES_TIMEOUT"
"""
.. envvar:: OTEL_EXPORTER_OTLP_TRACES_TIMEOUT
Expand All @@ -368,6 +404,14 @@
wait for each batch export for spans.
"""

OTEL_EXPORTER_OTLP_METRICS_TIMEOUT = "OTEL_EXPORTER_OTLP_METRICS_TIMEOUT"
"""
.. envvar:: OTEL_EXPORTER_OTLP_METRICS_TIMEOUT
The :envvar:`OTEL_EXPORTER_OTLP_METRICS_TIMEOUT` is the maximum time the OTLP exporter will
wait for each batch export for metrics.
"""

OTEL_EXPORTER_OTLP_METRICS_INSECURE = "OTEL_EXPORTER_OTLP_METRICS_INSECURE"
"""
.. envvar:: OTEL_EXPORTER_OTLP_METRICS_INSECURE
Expand Down

0 comments on commit 45c59ff

Please sign in to comment.