diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a276d606019..fa9272e9f4d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ env: # Otherwise, set variable to the commit of your branch on # opentelemetry-python-contrib which is compatible with these Core repo # changes. - CONTRIB_REPO_SHA: a67a23d0a0a4dd7c3c06c7050c220fa3b3689a77 + CONTRIB_REPO_SHA: f005d90ed3bc75ee6eb7297f9e3a6b55a55b22aa jobs: build: @@ -109,7 +109,7 @@ jobs: run: pip install -U tox - name: Cache tox environment # Preserves .tox directory between runs for faster installs - uses: actions/cache@v2 + uses: actions/cache@v1 with: path: .tox key: tox-cache-${{ matrix.tox-environment }}-${{ hashFiles('tox.ini', 'dev-requirements.txt') }}-core diff --git a/CHANGELOG.md b/CHANGELOG.md index a83dd049e92..3f05dd7e832 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Allow missing carrier headers to continue without raising AttributeError ([#1545](https://github.com/open-telemetry/opentelemetry-python/pull/1545)) +### Removed +- Remove Configuration + ([#1523](https://github.com/open-telemetry/opentelemetry-python/pull/1523)) + ## [0.17b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v0.17b0) - 2021-01-20 ### Added diff --git a/docs/api/api.rst b/docs/api/api.rst index ec6d8b03aa3..d132b78cf81 100644 --- a/docs/api/api.rst +++ b/docs/api/api.rst @@ -7,7 +7,7 @@ OpenTelemetry Python API :maxdepth: 1 baggage - configuration context metrics trace + environment_variables diff --git a/docs/api/configuration.rst b/docs/api/configuration.rst deleted file mode 100644 index 06ae4332776..00000000000 --- a/docs/api/configuration.rst +++ /dev/null @@ -1,10 +0,0 @@ -opentelemetry.configuration module -================================== - -Module contents ---------------- - -.. automodule:: opentelemetry.configuration - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/api/environment_variables.rst b/docs/api/environment_variables.rst new file mode 100644 index 00000000000..284675cf080 --- /dev/null +++ b/docs/api/environment_variables.rst @@ -0,0 +1,7 @@ +opentelemetry.environment_variables package +=========================================== + +Module contents +--------------- + +.. automodule:: opentelemetry.environment_variables diff --git a/docs/examples/auto-instrumentation/server_instrumented.py b/docs/examples/auto-instrumentation/server_instrumented.py index 6212ec33336..bc331de3ca4 100644 --- a/docs/examples/auto-instrumentation/server_instrumented.py +++ b/docs/examples/auto-instrumentation/server_instrumented.py @@ -15,13 +15,13 @@ from flask import Flask, request from opentelemetry import propagators, trace -from opentelemetry.instrumentation.wsgi import collect_request_attributes from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( ConsoleSpanExporter, SimpleExportSpanProcessor, ) from opentelemetry.trace.propagation.textmap import DictGetter +from opentelemetry.util.http.wsgi import collect_request_attributes app = Flask(__name__) diff --git a/docs/sdk/environment_variables.rst b/docs/sdk/environment_variables.rst new file mode 100644 index 00000000000..084a34b7bea --- /dev/null +++ b/docs/sdk/environment_variables.rst @@ -0,0 +1,12 @@ +opentelemetry.sdk.environment_variables +======================================= + +.. TODO: what is the SDK + +.. toctree:: + :maxdepth: 1 + +.. automodule:: opentelemetry.sdk.environment_variables + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sdk/sdk.rst b/docs/sdk/sdk.rst index e777aebac65..1c5653e1b30 100644 --- a/docs/sdk/sdk.rst +++ b/docs/sdk/sdk.rst @@ -10,3 +10,4 @@ OpenTelemetry Python SDK resources trace error_handler + environment_variables diff --git a/exporter/opentelemetry-exporter-jaeger/src/opentelemetry/exporter/jaeger/__init__.py b/exporter/opentelemetry-exporter-jaeger/src/opentelemetry/exporter/jaeger/__init__.py index 297c1e2b264..20b4bda3d9f 100644 --- a/exporter/opentelemetry-exporter-jaeger/src/opentelemetry/exporter/jaeger/__init__.py +++ b/exporter/opentelemetry-exporter-jaeger/src/opentelemetry/exporter/jaeger/__init__.py @@ -65,24 +65,14 @@ """ # pylint: disable=protected-access -import base64 import logging -import socket -from typing import Optional, Union - -from grpc import ( - ChannelCredentials, - insecure_channel, - secure_channel, - ssl_channel_credentials, -) -from thrift.protocol import TBinaryProtocol, TCompactProtocol -from thrift.transport import THttpClient, TTransport +from os import environ +from typing import Optional + +from grpc import ChannelCredentials, insecure_channel, secure_channel -from opentelemetry.configuration import Configuration from opentelemetry.exporter.jaeger import util from opentelemetry.exporter.jaeger.gen import model_pb2 -from opentelemetry.exporter.jaeger.gen.agent import Agent as agent from opentelemetry.exporter.jaeger.gen.collector_pb2 import PostSpansRequest from opentelemetry.exporter.jaeger.gen.collector_pb2_grpc import ( CollectorServiceStub, @@ -92,9 +82,14 @@ from opentelemetry.exporter.jaeger.translate import Translate from opentelemetry.exporter.jaeger.translate.protobuf import ProtobufTranslator from opentelemetry.exporter.jaeger.translate.thrift import ThriftTranslator -from opentelemetry.sdk.trace.export import Span, SpanExporter, SpanExportResult -from opentelemetry.trace import SpanKind -from opentelemetry.trace.status import StatusCode +from opentelemetry.sdk.environment_variables import ( + OTEL_EXPORTER_JAEGER_AGENT_HOST, + OTEL_EXPORTER_JAEGER_AGENT_PORT, + OTEL_EXPORTER_JAEGER_ENDPOINT, + OTEL_EXPORTER_JAEGER_PASSWORD, + OTEL_EXPORTER_JAEGER_USER, +) +from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult DEFAULT_AGENT_HOST_NAME = "localhost" DEFAULT_AGENT_PORT = 6831 @@ -142,12 +137,18 @@ def __init__( self.service_name = service_name self.agent_host_name = _parameter_setter( param=agent_host_name, - env_variable=Configuration().EXPORTER_JAEGER_AGENT_HOST, + env_variable=environ.get(OTEL_EXPORTER_JAEGER_AGENT_HOST), default=DEFAULT_AGENT_HOST_NAME, ) + + environ_agent_port = environ.get(OTEL_EXPORTER_JAEGER_AGENT_PORT) + environ_agent_port = ( + int(environ_agent_port) if environ_agent_port is not None else None + ) + self.agent_port = _parameter_setter( param=agent_port, - env_variable=Configuration().EXPORTER_JAEGER_AGENT_PORT, + env_variable=environ_agent_port, default=DEFAULT_AGENT_PORT, ) self._agent_client = AgentClientUDP( @@ -155,17 +156,17 @@ def __init__( ) self.collector_endpoint = _parameter_setter( param=collector_endpoint, - env_variable=Configuration().EXPORTER_JAEGER_ENDPOINT, + env_variable=environ.get(OTEL_EXPORTER_JAEGER_ENDPOINT), default=None, ) self.username = _parameter_setter( param=username, - env_variable=Configuration().EXPORTER_JAEGER_USER, + env_variable=environ.get(OTEL_EXPORTER_JAEGER_USER), default=None, ) self.password = _parameter_setter( param=password, - env_variable=Configuration().EXPORTER_JAEGER_PASSWORD, + env_variable=environ.get(OTEL_EXPORTER_JAEGER_PASSWORD), default=None, ) self._collector = None diff --git a/exporter/opentelemetry-exporter-jaeger/src/opentelemetry/exporter/jaeger/util.py b/exporter/opentelemetry-exporter-jaeger/src/opentelemetry/exporter/jaeger/util.py index 6be9d509ac8..4a72c1817c2 100644 --- a/exporter/opentelemetry-exporter-jaeger/src/opentelemetry/exporter/jaeger/util.py +++ b/exporter/opentelemetry-exporter-jaeger/src/opentelemetry/exporter/jaeger/util.py @@ -13,10 +13,14 @@ # limitations under the License. import logging +from os import environ from grpc import ChannelCredentials, ssl_channel_credentials -from opentelemetry.configuration import Configuration +from opentelemetry.sdk.environment_variables import ( + OTEL_EXPORTER_JAEGER_CERTIFICATE, + OTEL_EXPORTER_JAEGER_INSECURE, +) logger = logging.getLogger(__name__) @@ -26,7 +30,7 @@ def _get_insecure(param): if param is not None: return param - insecure_env = Configuration().get("EXPORTER_JAEGER_INSECURE", None) + insecure_env = environ.get(OTEL_EXPORTER_JAEGER_INSECURE) if insecure_env is not None: return insecure_env.lower() == "true" return DEFAULT_INSECURE @@ -45,7 +49,7 @@ def _load_credential_from_file(path) -> ChannelCredentials: def _get_credentials(param): if param is not None: return param - creds_env = Configuration().get("EXPORTER_JAEGER_CERTIFICATE", None) + creds_env = environ.get(OTEL_EXPORTER_JAEGER_CERTIFICATE) if creds_env: return _load_credential_from_file(creds_env) return ssl_channel_credentials() diff --git a/exporter/opentelemetry-exporter-jaeger/tests/test_jarget_exporter_protobuf.py b/exporter/opentelemetry-exporter-jaeger/tests/test_jaeger_exporter_protobuf.py similarity index 97% rename from exporter/opentelemetry-exporter-jaeger/tests/test_jarget_exporter_protobuf.py rename to exporter/opentelemetry-exporter-jaeger/tests/test_jaeger_exporter_protobuf.py index 2af228a6b78..26cfc41498e 100644 --- a/exporter/opentelemetry-exporter-jaeger/tests/test_jarget_exporter_protobuf.py +++ b/exporter/opentelemetry-exporter-jaeger/tests/test_jaeger_exporter_protobuf.py @@ -22,7 +22,6 @@ import opentelemetry.exporter.jaeger.gen.model_pb2 as model_pb2 import opentelemetry.exporter.jaeger.translate.protobuf as pb_translator from opentelemetry import trace as trace_api -from opentelemetry.configuration import Configuration from opentelemetry.exporter.jaeger import JaegerSpanExporter from opentelemetry.exporter.jaeger.translate import ( NAME_KEY, @@ -30,6 +29,10 @@ Translate, ) from opentelemetry.sdk import trace +from opentelemetry.sdk.environment_variables import ( + OTEL_EXPORTER_JAEGER_CERTIFICATE, + OTEL_EXPORTER_JAEGER_ENDPOINT, +) from opentelemetry.sdk.trace import Resource from opentelemetry.sdk.util.instrumentation import InstrumentationInfo from opentelemetry.trace.status import Status, StatusCode @@ -49,16 +52,10 @@ def setUp(self): self._test_span.start() self._test_span.end() # pylint: disable=protected-access - Configuration._reset() - - def tearDown(self): - # pylint: disable=protected-access - Configuration._reset() def test_constructor_by_environment_variables(self): """Test using Environment Variables.""" # pylint: disable=protected-access - Configuration._reset() service = "my-opentelemetry-jaeger" collector_endpoint = "localhost:14250" @@ -66,8 +63,8 @@ def test_constructor_by_environment_variables(self): env_patch = patch.dict( "os.environ", { - "OTEL_EXPORTER_JAEGER_ENDPOINT": collector_endpoint, - "OTEL_EXPORTER_JAEGER_CERTIFICATE": os.path.dirname(__file__) + OTEL_EXPORTER_JAEGER_ENDPOINT: collector_endpoint, + OTEL_EXPORTER_JAEGER_CERTIFICATE: os.path.dirname(__file__) + "/certs/cred.cert", }, ) diff --git a/exporter/opentelemetry-exporter-jaeger/tests/test_jaeger_exporter_thrift.py b/exporter/opentelemetry-exporter-jaeger/tests/test_jaeger_exporter_thrift.py index 379dd9a1e7d..947597ab469 100644 --- a/exporter/opentelemetry-exporter-jaeger/tests/test_jaeger_exporter_thrift.py +++ b/exporter/opentelemetry-exporter-jaeger/tests/test_jaeger_exporter_thrift.py @@ -20,11 +20,17 @@ # pylint:disable=import-error import opentelemetry.exporter.jaeger as jaeger_exporter from opentelemetry import trace as trace_api -from opentelemetry.configuration import Configuration from opentelemetry.exporter.jaeger.gen.jaeger import ttypes as jaeger from opentelemetry.exporter.jaeger.translate import Translate from opentelemetry.exporter.jaeger.translate.thrift import ThriftTranslator from opentelemetry.sdk import trace +from opentelemetry.sdk.environment_variables import ( + OTEL_EXPORTER_JAEGER_AGENT_HOST, + OTEL_EXPORTER_JAEGER_AGENT_PORT, + OTEL_EXPORTER_JAEGER_ENDPOINT, + OTEL_EXPORTER_JAEGER_PASSWORD, + OTEL_EXPORTER_JAEGER_USER, +) from opentelemetry.sdk.trace import Resource from opentelemetry.sdk.util.instrumentation import InstrumentationInfo from opentelemetry.trace import SpanKind @@ -44,11 +50,6 @@ def setUp(self): self._test_span.start() self._test_span.end() # pylint: disable=protected-access - Configuration._reset() - - def tearDown(self): - # pylint: disable=protected-access - Configuration._reset() def test_constructor_default(self): # pylint: disable=protected-access @@ -121,11 +122,11 @@ def test_constructor_by_environment_variables(self): environ_patcher = mock.patch.dict( "os.environ", { - "OTEL_EXPORTER_JAEGER_AGENT_HOST": agent_host_name, - "OTEL_EXPORTER_JAEGER_AGENT_PORT": agent_port, - "OTEL_EXPORTER_JAEGER_ENDPOINT": collector_endpoint, - "OTEL_EXPORTER_JAEGER_USER": username, - "OTEL_EXPORTER_JAEGER_PASSWORD": password, + OTEL_EXPORTER_JAEGER_AGENT_HOST: agent_host_name, + OTEL_EXPORTER_JAEGER_AGENT_PORT: agent_port, + OTEL_EXPORTER_JAEGER_ENDPOINT: collector_endpoint, + OTEL_EXPORTER_JAEGER_USER: username, + OTEL_EXPORTER_JAEGER_PASSWORD: password, }, ) diff --git a/exporter/opentelemetry-exporter-otlp/src/opentelemetry/exporter/otlp/exporter.py b/exporter/opentelemetry-exporter-otlp/src/opentelemetry/exporter/otlp/exporter.py index a4ae1edcfbb..6d54970f19f 100644 --- a/exporter/opentelemetry-exporter-otlp/src/opentelemetry/exporter/otlp/exporter.py +++ b/exporter/opentelemetry-exporter-otlp/src/opentelemetry/exporter/otlp/exporter.py @@ -18,6 +18,7 @@ import logging from abc import ABC, abstractmethod from collections.abc import Mapping, Sequence +from os import environ from time import sleep from typing import Any, Callable, Dict, Generic, List, Optional from typing import Sequence as TypingSequence @@ -35,9 +36,15 @@ ssl_channel_credentials, ) -from opentelemetry.configuration import Configuration from opentelemetry.proto.common.v1.common_pb2 import AnyValue, KeyValue from opentelemetry.proto.resource.v1.resource_pb2 import Resource +from opentelemetry.sdk.environment_variables import ( + OTEL_EXPORTER_OTLP_CERTIFICATE, + OTEL_EXPORTER_OTLP_ENDPOINT, + OTEL_EXPORTER_OTLP_HEADERS, + OTEL_EXPORTER_OTLP_INSECURE, + OTEL_EXPORTER_OTLP_TIMEOUT, +) from opentelemetry.sdk.resources import Resource as SDKResource logger = logging.getLogger(__name__) @@ -159,23 +166,23 @@ def __init__( endpoint = ( endpoint - or Configuration().EXPORTER_OTLP_ENDPOINT + or environ.get(OTEL_EXPORTER_OTLP_ENDPOINT) or "localhost:4317" ) if insecure is None: - insecure = Configuration().EXPORTER_OTLP_INSECURE + insecure = environ.get(OTEL_EXPORTER_OTLP_INSECURE) if insecure is None: insecure = False - self._headers = headers or Configuration().EXPORTER_OTLP_HEADERS + self._headers = headers or environ.get(OTEL_EXPORTER_OTLP_HEADERS) if isinstance(self._headers, str): self._headers = tuple( tuple(item.split("=")) for item in self._headers.split(",") ) self._timeout = ( timeout - or Configuration().EXPORTER_OTLP_TIMEOUT + or int(environ.get(OTEL_EXPORTER_OTLP_TIMEOUT, 0)) or 10 # default: 10 seconds ) self._collector_span_kwargs = None @@ -188,7 +195,7 @@ def __init__( ): compression_algorithm = Compression.Gzip else: - compression_str = Configuration().EXPORTER_OTLP_INSECURE or None + compression_str = environ.get(OTEL_EXPORTER_OTLP_INSECURE) if compression_str is None: compression_algorithm = Compression.NoCompression elif ( @@ -210,13 +217,13 @@ def __init__( # secure mode if ( credentials is None - and Configuration().EXPORTER_OTLP_CERTIFICATE is None + and environ.get(OTEL_EXPORTER_OTLP_CERTIFICATE) is None ): # use the default location chosen by gRPC runtime credentials = ssl_channel_credentials() else: credentials = credentials or _load_credential_from_file( - Configuration().EXPORTER_OTLP_CERTIFICATE + environ.get(OTEL_EXPORTER_OTLP_CERTIFICATE) ) self._client = self._stub( secure_channel( diff --git a/exporter/opentelemetry-exporter-otlp/src/opentelemetry/exporter/otlp/metrics_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp/src/opentelemetry/exporter/otlp/metrics_exporter/__init__.py index c371c177e9c..8e388e9f9e1 100644 --- a/exporter/opentelemetry-exporter-otlp/src/opentelemetry/exporter/otlp/metrics_exporter/__init__.py +++ b/exporter/opentelemetry-exporter-otlp/src/opentelemetry/exporter/otlp/metrics_exporter/__init__.py @@ -15,11 +15,11 @@ """OTLP Metrics Exporter""" import logging +from os import environ from typing import List, Optional, Sequence, Type, TypeVar from grpc import ChannelCredentials -from opentelemetry.configuration import Configuration from opentelemetry.exporter.otlp.exporter import ( OTLPExporterMixin, _get_resource_data, @@ -44,6 +44,13 @@ ) from opentelemetry.proto.metrics.v1.metrics_pb2 import Metric as OTLPMetric from opentelemetry.proto.metrics.v1.metrics_pb2 import ResourceMetrics +from opentelemetry.sdk.environment_variables import ( + OTEL_EXPORTER_OTLP_METRIC_CERTIFICATE, + OTEL_EXPORTER_OTLP_METRIC_ENDPOINT, + OTEL_EXPORTER_OTLP_METRIC_HEADERS, + OTEL_EXPORTER_OTLP_METRIC_INSECURE, + OTEL_EXPORTER_OTLP_METRIC_TIMEOUT, +) from opentelemetry.sdk.metrics import ( Counter, SumObserver, @@ -143,26 +150,30 @@ def __init__( timeout: Optional[int] = None, ): if insecure is None: - insecure = Configuration().EXPORTER_OTLP_METRIC_INSECURE + insecure = environ.get(OTEL_EXPORTER_OTLP_METRIC_INSECURE) if ( not insecure - and Configuration().EXPORTER_OTLP_METRIC_CERTIFICATE is not None + and environ.get(OTEL_EXPORTER_OTLP_METRIC_CERTIFICATE) is not None ): credentials = credentials or _load_credential_from_file( - Configuration().EXPORTER_OTLP_METRIC_CERTIFICATE + environ.get(OTEL_EXPORTER_OTLP_METRIC_CERTIFICATE) ) + environ_timeout = environ.get(OTEL_EXPORTER_OTLP_METRIC_TIMEOUT) + environ_timeout = ( + int(environ_timeout) if environ_timeout is not None else None + ) + super().__init__( **{ "endpoint": endpoint - or Configuration().EXPORTER_OTLP_METRIC_ENDPOINT, + or environ.get(OTEL_EXPORTER_OTLP_METRIC_ENDPOINT), "insecure": insecure, "credentials": credentials, "headers": headers - or Configuration().EXPORTER_OTLP_METRIC_HEADERS, - "timeout": timeout - or Configuration().EXPORTER_OTLP_METRIC_TIMEOUT, + or environ.get(OTEL_EXPORTER_OTLP_METRIC_HEADERS), + "timeout": timeout or environ_timeout, } ) diff --git a/exporter/opentelemetry-exporter-otlp/src/opentelemetry/exporter/otlp/trace_exporter/__init__.py b/exporter/opentelemetry-exporter-otlp/src/opentelemetry/exporter/otlp/trace_exporter/__init__.py index b872b624a1a..96dbbc084b8 100644 --- a/exporter/opentelemetry-exporter-otlp/src/opentelemetry/exporter/otlp/trace_exporter/__init__.py +++ b/exporter/opentelemetry-exporter-otlp/src/opentelemetry/exporter/otlp/trace_exporter/__init__.py @@ -14,11 +14,11 @@ """OTLP Span Exporter""" import logging +from os import environ from typing import Optional, Sequence from grpc import ChannelCredentials -from opentelemetry.configuration import Configuration from opentelemetry.exporter.otlp.exporter import ( OTLPExporterMixin, _get_resource_data, @@ -38,6 +38,13 @@ ) from opentelemetry.proto.trace.v1.trace_pb2 import Span as CollectorSpan from opentelemetry.proto.trace.v1.trace_pb2 import Status +from opentelemetry.sdk.environment_variables import ( + OTEL_EXPORTER_OTLP_SPAN_CERTIFICATE, + OTEL_EXPORTER_OTLP_SPAN_ENDPOINT, + OTEL_EXPORTER_OTLP_SPAN_HEADERS, + OTEL_EXPORTER_OTLP_SPAN_INSECURE, + OTEL_EXPORTER_OTLP_SPAN_TIMEOUT, +) from opentelemetry.sdk.trace import Span as SDKSpan from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult from opentelemetry.trace.status import StatusCode @@ -73,26 +80,30 @@ def __init__( timeout: Optional[int] = None, ): if insecure is None: - insecure = Configuration().EXPORTER_OTLP_SPAN_INSECURE + insecure = environ.get(OTEL_EXPORTER_OTLP_SPAN_INSECURE) if ( not insecure - and Configuration().EXPORTER_OTLP_SPAN_CERTIFICATE is not None + and environ.get(OTEL_EXPORTER_OTLP_SPAN_CERTIFICATE) is not None ): credentials = credentials or _load_credential_from_file( - Configuration().EXPORTER_OTLP_SPAN_CERTIFICATE + environ.get(OTEL_EXPORTER_OTLP_SPAN_CERTIFICATE) ) + environ_timeout = environ.get(OTEL_EXPORTER_OTLP_SPAN_TIMEOUT) + environ_timeout = ( + int(environ_timeout) if environ_timeout is not None else None + ) + super().__init__( **{ "endpoint": endpoint - or Configuration().EXPORTER_OTLP_SPAN_ENDPOINT, + or environ.get(OTEL_EXPORTER_OTLP_SPAN_ENDPOINT), "insecure": insecure, "credentials": credentials, "headers": headers - or Configuration().EXPORTER_OTLP_SPAN_HEADERS, - "timeout": timeout - or Configuration().EXPORTER_OTLP_SPAN_TIMEOUT, + or environ.get(OTEL_EXPORTER_OTLP_SPAN_HEADERS), + "timeout": timeout or environ_timeout, } ) diff --git a/exporter/opentelemetry-exporter-otlp/tests/test_otlp_metric_exporter.py b/exporter/opentelemetry-exporter-otlp/tests/test_otlp_metric_exporter.py index 946a313a440..841dcff03e4 100644 --- a/exporter/opentelemetry-exporter-otlp/tests/test_otlp_metric_exporter.py +++ b/exporter/opentelemetry-exporter-otlp/tests/test_otlp_metric_exporter.py @@ -19,7 +19,6 @@ from grpc import ChannelCredentials -from opentelemetry.configuration import Configuration from opentelemetry.exporter.otlp.metrics_exporter import OTLPMetricsExporter from opentelemetry.proto.collector.metrics.v1.metrics_service_pb2 import ( ExportMetricsServiceRequest, @@ -41,6 +40,12 @@ from opentelemetry.proto.resource.v1.resource_pb2 import ( Resource as OTLPResource, ) +from opentelemetry.sdk.environment_variables import ( + OTEL_EXPORTER_OTLP_METRIC_CERTIFICATE, + OTEL_EXPORTER_OTLP_METRIC_ENDPOINT, + OTEL_EXPORTER_OTLP_METRIC_HEADERS, + OTEL_EXPORTER_OTLP_METRIC_TIMEOUT, +) from opentelemetry.sdk.metrics import ( Counter, MeterProvider, @@ -62,19 +67,15 @@ def setUp(self): # pylint: disable=arguments-differ self.meter = MeterProvider(resource=self.resource,).get_meter( "name", "version" ) - Configuration._reset() # pylint: disable=protected-access - - def tearDown(self): - Configuration._reset() # pylint: disable=protected-access @patch.dict( "os.environ", { - "OTEL_EXPORTER_OTLP_METRIC_ENDPOINT": "collector:4317", - "OTEL_EXPORTER_OTLP_METRIC_CERTIFICATE": THIS_DIR + OTEL_EXPORTER_OTLP_METRIC_ENDPOINT: "collector:4317", + OTEL_EXPORTER_OTLP_METRIC_CERTIFICATE: THIS_DIR + "/fixtures/test.cert", - "OTEL_EXPORTER_OTLP_METRIC_HEADERS": "key1=value1,key2=value2", - "OTEL_EXPORTER_OTLP_METRIC_TIMEOUT": "10", + OTEL_EXPORTER_OTLP_METRIC_HEADERS: "key1=value1,key2=value2", + OTEL_EXPORTER_OTLP_METRIC_TIMEOUT: "10", }, ) @patch("opentelemetry.exporter.otlp.exporter.OTLPExporterMixin.__init__") @@ -104,7 +105,7 @@ def test_no_credentials_error( @patch.dict( "os.environ", - {"OTEL_EXPORTER_OTLP_METRIC_HEADERS": "key1=value1,key2=value2"}, + {OTEL_EXPORTER_OTLP_METRIC_HEADERS: "key1=value1,key2=value2"}, ) @patch("opentelemetry.exporter.otlp.exporter.ssl_channel_credentials") @patch("opentelemetry.exporter.otlp.exporter.secure_channel") diff --git a/exporter/opentelemetry-exporter-otlp/tests/test_otlp_trace_exporter.py b/exporter/opentelemetry-exporter-otlp/tests/test_otlp_trace_exporter.py index 5dde0c97722..a1dbcfbd63b 100644 --- a/exporter/opentelemetry-exporter-otlp/tests/test_otlp_trace_exporter.py +++ b/exporter/opentelemetry-exporter-otlp/tests/test_otlp_trace_exporter.py @@ -22,7 +22,6 @@ from google.rpc.error_details_pb2 import RetryInfo from grpc import ChannelCredentials, StatusCode, server -from opentelemetry.configuration import Configuration from opentelemetry.exporter.otlp.trace_exporter import OTLPSpanExporter from opentelemetry.proto.collector.trace.v1.trace_service_pb2 import ( ExportTraceServiceRequest, @@ -46,6 +45,12 @@ ) from opentelemetry.proto.trace.v1.trace_pb2 import Span as OTLPSpan from opentelemetry.proto.trace.v1.trace_pb2 import Status +from opentelemetry.sdk.environment_variables import ( + OTEL_EXPORTER_OTLP_SPAN_CERTIFICATE, + OTEL_EXPORTER_OTLP_SPAN_ENDPOINT, + OTEL_EXPORTER_OTLP_SPAN_HEADERS, + OTEL_EXPORTER_OTLP_SPAN_TIMEOUT, +) from opentelemetry.sdk.resources import Resource as SDKResource from opentelemetry.sdk.trace import Status as SDKStatus from opentelemetry.sdk.trace import StatusCode as SDKStatusCode @@ -160,20 +165,17 @@ def setUp(self): self.span.start() self.span.end() - Configuration._reset() # pylint: disable=protected-access - def tearDown(self): self.server.stop(None) - Configuration._reset() # pylint: disable=protected-access @patch.dict( "os.environ", { - "OTEL_EXPORTER_OTLP_SPAN_ENDPOINT": "collector:4317", - "OTEL_EXPORTER_OTLP_SPAN_CERTIFICATE": THIS_DIR + OTEL_EXPORTER_OTLP_SPAN_ENDPOINT: "collector:4317", + OTEL_EXPORTER_OTLP_SPAN_CERTIFICATE: THIS_DIR + "/fixtures/test.cert", - "OTEL_EXPORTER_OTLP_SPAN_HEADERS": "key1=value1,key2=value2", - "OTEL_EXPORTER_OTLP_SPAN_TIMEOUT": "10", + OTEL_EXPORTER_OTLP_SPAN_HEADERS: "key1=value1,key2=value2", + OTEL_EXPORTER_OTLP_SPAN_TIMEOUT: "10", }, ) @patch("opentelemetry.exporter.otlp.exporter.OTLPExporterMixin.__init__") @@ -201,7 +203,7 @@ def test_no_credentials_error( @patch.dict( "os.environ", - {"OTEL_EXPORTER_OTLP_SPAN_HEADERS": "key1=value1,key2=value2"}, + {OTEL_EXPORTER_OTLP_SPAN_HEADERS: "key1=value1,key2=value2"}, ) @patch("opentelemetry.exporter.otlp.exporter.ssl_channel_credentials") @patch("opentelemetry.exporter.otlp.exporter.secure_channel") diff --git a/exporter/opentelemetry-exporter-zipkin/src/opentelemetry/exporter/zipkin/__init__.py b/exporter/opentelemetry-exporter-zipkin/src/opentelemetry/exporter/zipkin/__init__.py index 3f1984b8a85..a7ea40180a3 100644 --- a/exporter/opentelemetry-exporter-zipkin/src/opentelemetry/exporter/zipkin/__init__.py +++ b/exporter/opentelemetry-exporter-zipkin/src/opentelemetry/exporter/zipkin/__init__.py @@ -73,13 +73,17 @@ import json import logging +from os import environ from typing import Optional, Sequence, Union from urllib.parse import urlparse import requests -from opentelemetry.configuration import Configuration from opentelemetry.exporter.zipkin.gen import zipkin_pb2 +from opentelemetry.sdk.environment_variables import ( + OTEL_EXPORTER_ZIPKIN_ENDPOINT, + OTEL_EXPORTER_ZIPKIN_TRANSPORT_FORMAT, +) from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult from opentelemetry.trace import Span, SpanContext, SpanKind from opentelemetry.trace.status import StatusCode @@ -142,7 +146,9 @@ def __init__( ): self.service_name = service_name if url is None: - self.url = Configuration().EXPORTER_ZIPKIN_ENDPOINT or DEFAULT_URL + self.url = ( + environ.get(OTEL_EXPORTER_ZIPKIN_ENDPOINT) or DEFAULT_URL + ) else: self.url = url @@ -155,7 +161,7 @@ def __init__( if transport_format is None: self.transport_format = ( - Configuration().EXPORTER_ZIPKIN_TRANSPORT_FORMAT + environ.get(OTEL_EXPORTER_ZIPKIN_TRANSPORT_FORMAT) or TRANSPORT_FORMAT_JSON ) else: diff --git a/exporter/opentelemetry-exporter-zipkin/tests/test_zipkin_exporter.py b/exporter/opentelemetry-exporter-zipkin/tests/test_zipkin_exporter.py index 30837106c1a..5c2e0e7e4d0 100644 --- a/exporter/opentelemetry-exporter-zipkin/tests/test_zipkin_exporter.py +++ b/exporter/opentelemetry-exporter-zipkin/tests/test_zipkin_exporter.py @@ -18,7 +18,6 @@ from unittest.mock import MagicMock, patch from opentelemetry import trace as trace_api -from opentelemetry.configuration import Configuration from opentelemetry.exporter.zipkin import ( NAME_KEY, SPAN_KIND_MAP_JSON, @@ -31,6 +30,10 @@ ) from opentelemetry.exporter.zipkin.gen import zipkin_pb2 from opentelemetry.sdk import trace +from opentelemetry.sdk.environment_variables import ( + OTEL_EXPORTER_ZIPKIN_ENDPOINT, + OTEL_EXPORTER_ZIPKIN_TRANSPORT_FORMAT, +) from opentelemetry.sdk.trace import Resource from opentelemetry.sdk.trace.export import SpanExportResult from opentelemetry.sdk.util.instrumentation import InstrumentationInfo @@ -58,18 +61,17 @@ def setUp(self): self._test_span.end() def tearDown(self): - if "OTEL_EXPORTER_ZIPKIN_ENDPOINT" in os.environ: - del os.environ["OTEL_EXPORTER_ZIPKIN_ENDPOINT"] - if "OTEL_EXPORTER_ZIPKIN_TRANSPORT_FORMAT" in os.environ: - del os.environ["OTEL_EXPORTER_ZIPKIN_TRANSPORT_FORMAT"] - Configuration()._reset() # pylint: disable=protected-access + if OTEL_EXPORTER_ZIPKIN_ENDPOINT in os.environ: + del os.environ[OTEL_EXPORTER_ZIPKIN_ENDPOINT] + if OTEL_EXPORTER_ZIPKIN_TRANSPORT_FORMAT in os.environ: + del os.environ[OTEL_EXPORTER_ZIPKIN_TRANSPORT_FORMAT] def test_constructor_env_var(self): """Test the default values assigned by constructor.""" url = "https://foo:9911/path" - os.environ["OTEL_EXPORTER_ZIPKIN_ENDPOINT"] = url + os.environ[OTEL_EXPORTER_ZIPKIN_ENDPOINT] = url os.environ[ - "OTEL_EXPORTER_ZIPKIN_TRANSPORT_FORMAT" + OTEL_EXPORTER_ZIPKIN_TRANSPORT_FORMAT ] = TRANSPORT_FORMAT_PROTOBUF service_name = "my-service-name" port = 9911 diff --git a/opentelemetry-api/src/opentelemetry/configuration/__init__.py b/opentelemetry-api/src/opentelemetry/configuration/__init__.py deleted file mode 100644 index 5e3d3667dc1..00000000000 --- a/opentelemetry-api/src/opentelemetry/configuration/__init__.py +++ /dev/null @@ -1,198 +0,0 @@ -# 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. - -""" -Simple configuration manager - -This is a configuration manager for OpenTelemetry. It reads configuration -values from environment variables prefixed with ``OTEL_`` (for environment -variables that apply to any OpenTelemetry implementation) or with -``OTEL_PYTHON_`` (for environment variables that are specific to the Python -implementation of OpenTelemetry) whose characters are only alphanumeric -characters and unserscores, except for the first character after ``OTEL_`` or -``OTEL_PYTHON_`` which must not be a number. - -For example, these environment variables will be read: - -1. ``OTEL_SOMETHING`` -2. ``OTEL_SOMETHING_ELSE_`` -3. ``OTEL_SOMETHING_ELSE_AND__ELSE`` -4. ``OTEL_SOMETHING_ELSE_AND_else`` -5. ``OTEL_SOMETHING_ELSE_AND_else2`` - -These won't: - -1. ``OPENTELEMETRY_PYTH_SOMETHING`` -2. ``OTEL_2_SOMETHING_AND__ELSE`` -3. ``OTEL_SOMETHING_%_ELSE`` - -The values stored in the environment variables can be found in an instance of -``opentelemetry.configuration.Configuration``. This class can be instantiated -freely because instantiating it returns always the same object. - -For example, if the environment variable -``OTEL_PYTHON_METER_PROVIDER`` value is ``my_meter_provider``, then -``Configuration().METER_PROVIDER == "my_meter_provider"`` would be ``True``. - -Non defined attributes will always return ``None``. This is intended to make it -easier to use the ``Configuration`` object in actual code, because it won't be -necessary to check for the attribute to be defined first. - -Environment variables used by OpenTelemetry -------------------------------------------- - -1. OTEL_PYTHON_METER_PROVIDER -2. OTEL_PYTHON_TRACER_PROVIDER - -The value of these environment variables should be the name of the entry point -that points to the class that implements either provider. This OpenTelemetry -API package provides one entry point for each, which can be found in the -setup.py file:: - - entry_points={ - ... - "opentelemetry_meter_provider": [ - "default_meter_provider = " - "opentelemetry.metrics:DefaultMeterProvider" - ], - "opentelemetry_tracer_provider": [ - "default_tracer_provider = " - "opentelemetry.trace:DefaultTracerProvider" - ], - } - -To use the meter provider above, then the -``OTEL_PYTHON_METER_PROVIDER`` should be set to -``"default_meter_provider"`` (this is not actually necessary since the -OpenTelemetry API provided providers are the default ones used if no -configuration is found in the environment variables). - -Configuration values that are exactly ``"True"`` or ``"False"`` will be -converted to its boolean values of ``True`` and ``False`` respectively. - -Configuration values that can be casted to integers or floats will be casted. - -This object can be used by any OpenTelemetry component, native or external. -For that reason, the ``Configuration`` object is designed to be immutable. -If a component would change the value of one of the ``Configuration`` object -attributes then another component that relied on that value may break, leading -to bugs that are very hard to debug. To avoid this situation, the preferred -approach for components that need a different value than the one provided by -the ``Configuration`` object is to implement a mechanism that allows the user -to override this value instead of changing it. -""" - -import re -from os import environ -from typing import ClassVar, Dict, List, Optional, Sequence, TypeVar, Union - -ConfigValue = Union[str, bool, int, float] -_T = TypeVar("_T", ConfigValue, Optional[ConfigValue]) - - -class ExcludeList: - """Class to exclude certain paths (given as a list of regexes) from tracing requests""" - - def __init__(self, excluded_urls: Sequence[str]): - self._non_empty = len(excluded_urls) > 0 - if self._non_empty: - self._regex = re.compile("|".join(excluded_urls)) - - def url_disabled(self, url: str) -> bool: - return bool(self._non_empty and re.search(self._regex, url)) - - -class Configuration: - _instance = None # type: ClassVar[Optional[Configuration]] - _config_map = {} # type: ClassVar[Dict[str, ConfigValue]] - - def __new__(cls) -> "Configuration": - if cls._instance is not None: - instance = cls._instance - else: - - instance = super().__new__(cls) - for key, value_str in environ.items(): - - match = re.fullmatch(r"OTEL_(PYTHON_)?([A-Za-z_][\w_]*)", key) - - if match is not None: - - key = match.group(2) - value = value_str # type: ConfigValue - - if value_str == "True": - value = True - elif value_str == "False": - value = False - else: - try: - value = int(value_str) - except ValueError: - try: - value = float(value_str) - except ValueError: - pass - - instance._config_map[key] = value - - cls._instance = instance - - return instance - - def __getattr__(self, name: str) -> Optional[ConfigValue]: - return self._config_map.get(name) - - def __setattr__(self, name: str, value: ConfigValue) -> None: - if name not in self._config_map.keys(): - self._config_map[name] = value - else: - raise AttributeError(name) - - def get(self, name: str, default: _T) -> _T: - """Use this typed method for dynamic access instead of `getattr` - - :rtype: str or bool or int or float or None - """ - return self._config_map.get(name, default) - - @classmethod - def _reset(cls) -> None: - """ - This method "resets" the global configuration attributes - - It is not intended to be used by production code but by testing code - only. - """ - - if cls._instance: - cls._instance._config_map.clear() # pylint: disable=protected-access - cls._instance = None - - def _traced_request_attrs(self, instrumentation: str) -> List[str]: - """Returns list of traced request attributes for instrumentation.""" - key = "{}_TRACED_REQUEST_ATTRS".format(instrumentation.upper()) - value = self._config_map.get(key, "") - - request_attrs = ( - [attr.strip() for attr in str.split(value, ",")] if value else [] # type: ignore - ) - return request_attrs - - def _excluded_urls(self, instrumentation: str) -> ExcludeList: - key = "{}_EXCLUDED_URLS".format(instrumentation.upper()) - value = self._config_map.get(key, "") - - urls = str.split(value, ",") if value else [] # type: ignore - return ExcludeList(urls) diff --git a/opentelemetry-api/src/opentelemetry/configuration/py.typed b/opentelemetry-api/src/opentelemetry/configuration/py.typed deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/opentelemetry-api/src/opentelemetry/context/__init__.py b/opentelemetry-api/src/opentelemetry/context/__init__.py index 22441c306b4..2f1249d4d03 100644 --- a/opentelemetry-api/src/opentelemetry/context/__init__.py +++ b/opentelemetry-api/src/opentelemetry/context/__init__.py @@ -21,6 +21,7 @@ from pkg_resources import iter_entry_points from opentelemetry.context.context import Context, RuntimeContext +from opentelemetry.environment_variables import OTEL_PYTHON_CONTEXT logger = logging.getLogger(__name__) _RUNTIME_CONTEXT = None # type: typing.Optional[RuntimeContext] @@ -50,7 +51,7 @@ def wrapper( default_context = "contextvars_context" configured_context = environ.get( - "OTEL_CONTEXT", default_context + OTEL_PYTHON_CONTEXT, default_context ) # type: str try: _RUNTIME_CONTEXT = next( diff --git a/opentelemetry-api/src/opentelemetry/environment_variables/__init__.py b/opentelemetry-api/src/opentelemetry/environment_variables/__init__.py new file mode 100644 index 00000000000..1bd5a6f46d2 --- /dev/null +++ b/opentelemetry-api/src/opentelemetry/environment_variables/__init__.py @@ -0,0 +1,21 @@ +# 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. + +OTEL_PROPAGATORS = "OTEL_PROPAGATORS" +OTEL_PYTHON_CONTEXT = "OTEL_PYTHON_CONTEXT" +OTEL_PYTHON_DISABLED_INSTRUMENTATIONS = "OTEL_PYTHON_DISABLED_INSTRUMENTATIONS" +OTEL_PYTHON_IDS_GENERATOR = "OTEL_PYTHON_IDS_GENERATOR" +OTEL_PYTHON_SERVICE_NAME = "OTEL_PYTHON_SERVICE_NAME" +OTEL_TRACE_EXPORTER = "OTEL_TRACE_EXPORTER" +OTEL_METRICS_EXPORTER = "OTEL_METRICS_EXPORTER" diff --git a/opentelemetry-api/src/opentelemetry/propagators/__init__.py b/opentelemetry-api/src/opentelemetry/propagators/__init__.py index 5c42075e3c1..6050b5f4ff8 100644 --- a/opentelemetry-api/src/opentelemetry/propagators/__init__.py +++ b/opentelemetry-api/src/opentelemetry/propagators/__init__.py @@ -70,11 +70,12 @@ def example_route(): import typing from logging import getLogger +from os import environ from pkg_resources import iter_entry_points -from opentelemetry.configuration import Configuration from opentelemetry.context.context import Context +from opentelemetry.environment_variables import OTEL_PROPAGATORS from opentelemetry.propagators import composite from opentelemetry.trace.propagation import textmap @@ -125,13 +126,15 @@ def inject( propagators = [] - for propagator in ( # type: ignore - Configuration().get("PROPAGATORS", "tracecontext,baggage").split(",") # type: ignore - ): + # Single use variable here to hack black and make lint pass + environ_propagators = environ.get( + OTEL_PROPAGATORS, "tracecontext,baggage", + ) + for propagator in environ_propagators.split(","): propagators.append( # type: ignore next( # type: ignore - iter_entry_points("opentelemetry_propagator", propagator) # type: ignore + iter_entry_points("opentelemetry_propagator", propagator) ).load()() ) diff --git a/opentelemetry-api/src/opentelemetry/util/__init__.py b/opentelemetry-api/src/opentelemetry/util/__init__.py index c1c5a77f098..c49ba1b353c 100644 --- a/opentelemetry-api/src/opentelemetry/util/__init__.py +++ b/opentelemetry-api/src/opentelemetry/util/__init__.py @@ -11,15 +11,14 @@ # 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. -import re + import time from logging import getLogger -from typing import TYPE_CHECKING, Sequence, Union, cast +from os import environ +from typing import TYPE_CHECKING, Union, cast from pkg_resources import iter_entry_points -from opentelemetry.configuration import Configuration - if TYPE_CHECKING: from opentelemetry.metrics import MeterProvider from opentelemetry.trace import TracerProvider @@ -47,7 +46,7 @@ def _load_provider(provider: str) -> Provider: "opentelemetry_{}".format(provider), name=cast( str, - Configuration().get( + environ.get( provider.upper(), "default_{}".format(provider), ), ), diff --git a/opentelemetry-api/tests/configuration/__init__.py b/opentelemetry-api/tests/configuration/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/opentelemetry-api/tests/configuration/test_configuration.py b/opentelemetry-api/tests/configuration/test_configuration.py deleted file mode 100644 index b36d93412b7..00000000000 --- a/opentelemetry-api/tests/configuration/test_configuration.py +++ /dev/null @@ -1,177 +0,0 @@ -# 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. -# pylint: disable-all - -from sys import platform -from unittest import TestCase -from unittest.mock import patch - -from opentelemetry.configuration import Configuration - - -class TestConfiguration(TestCase): - - # These calls reset the attributes of the Configuration class so that each - # test is executed in the same conditions. - def setUp(self) -> None: - Configuration._reset() - - def test_singleton(self) -> None: - self.assertIsInstance(Configuration(), Configuration) - self.assertIs(Configuration(), Configuration()) - - @patch.dict( - "os.environ", # type: ignore - { - "OTEL_PYTHON_METER_PROVIDER": "meter_provider", - "OTEL_PYTHON_TRACER_PROVIDER": "tracer_provider", - "OTEL_OTHER" if platform == "windows" else "OTEL_OThER": "other", - "OTEL_OTHER_7": "other_7", - "OPENTELEMETRY_PTHON_TRACEX_PROVIDER": "tracex_provider", - }, - ) - def test_environment_variables(self) -> None: - self.assertEqual( - Configuration().METER_PROVIDER, "meter_provider" - ) # pylint: disable=no-member - self.assertEqual( - Configuration().TRACER_PROVIDER, "tracer_provider" - ) # pylint: disable=no-member - self.assertEqual( - Configuration().OThER, "other" - ) # pylint: disable=no-member - self.assertEqual( - Configuration().OTHER_7, "other_7" - ) # pylint: disable=no-member - self.assertIsNone(Configuration().TRACEX_PROVIDER) - - @patch.dict( - "os.environ", # type: ignore - {"OTEL_PYTHON_TRACER_PROVIDER": "tracer_provider"}, - ) - def test_property(self) -> None: - with self.assertRaises(AttributeError): - Configuration().TRACER_PROVIDER = "new_tracer_provider" - - def test_set_once(self) -> None: - - Configuration().XYZ = "xyz" - - with self.assertRaises(AttributeError): - Configuration().XYZ = "abc" # pylint: disable=assigning-non-slot - - def test_getattr(self) -> None: - # literal access - self.assertIsNone(Configuration().XYZ) - - # dynamic access - self.assertIsNone(getattr(Configuration(), "XYZ")) - self.assertIsNone(Configuration().get("XYZ", None)) - - def test_reset(self) -> None: - environ_patcher = patch.dict( - "os.environ", {"OTEL_PYTHON_TRACER_PROVIDER": "tracer_provider"}, - ) - - environ_patcher.start() - - self.assertEqual( - Configuration().TRACER_PROVIDER, "tracer_provider" - ) # pylint: disable=no-member - - environ_patcher.stop() - - Configuration._reset() - - self.assertIsNone( - Configuration().TRACER_PROVIDER - ) # pylint: disable=no-member - - @patch.dict( - "os.environ", # type: ignore - {"OTEL_TRUE": "True", "OTEL_FALSE": "False"}, - ) - def test_boolean(self) -> None: - self.assertIsInstance( - Configuration().TRUE, bool - ) # pylint: disable=no-member - self.assertIsInstance( - Configuration().FALSE, bool - ) # pylint: disable=no-member - self.assertTrue(Configuration().TRUE) # pylint: disable=no-member - self.assertFalse(Configuration().FALSE) # pylint: disable=no-member - - @patch.dict( - "os.environ", # type: ignore - { - "OTEL_POSITIVE_INTEGER": "123", - "OTEL_NEGATIVE_INTEGER": "-123", - "OTEL_NON_INTEGER": "-12z3", - }, - ) - def test_integer(self) -> None: - # pylint: disable=no-member - self.assertIsInstance(Configuration().POSITIVE_INTEGER, int) - self.assertEqual(Configuration().POSITIVE_INTEGER, 123) - self.assertIsInstance(Configuration().NEGATIVE_INTEGER, int) - self.assertEqual(Configuration().NEGATIVE_INTEGER, -123) - self.assertEqual(Configuration().NON_INTEGER, "-12z3") - - @patch.dict( - "os.environ", # type: ignore - { - "OTEL_POSITIVE_FLOAT": "123.123", - "OTEL_NEGATIVE_FLOAT": "-123.123", - "OTEL_NON_FLOAT": "-12z3.123", - }, - ) - def test_float(self) -> None: - self.assertEqual( - Configuration().POSITIVE_FLOAT, 123.123 - ) # pylint: disable=no-member - self.assertEqual( - Configuration().NEGATIVE_FLOAT, -123.123 - ) # pylint: disable=no-member - self.assertEqual( - Configuration().NON_FLOAT, "-12z3.123" - ) # pylint: disable=no-member - - @patch.dict( - "os.environ", # type: ignore - { - "OTEL_PYTHON_WEBFRAMEWORK_TRACED_REQUEST_ATTRS": "content_type,keep_alive", - }, - ) - def test_traced_request_attrs(self) -> None: - cfg = Configuration() - request_attrs = cfg._traced_request_attrs("webframework") - self.assertEqual(len(request_attrs), 2) - self.assertIn("content_type", request_attrs) - self.assertIn("keep_alive", request_attrs) - self.assertNotIn("authorization", request_attrs) - - @patch.dict( - "os.environ", # type: ignore - { - "OTEL_PYTHON_WEBFRAMEWORK_EXCLUDED_URLS": "/healthzz,path,/issues/.*/view", - }, - ) - def test_excluded_urls(self) -> None: - cfg = Configuration() - excluded_urls = cfg._excluded_urls("webframework") - self.assertTrue(excluded_urls.url_disabled("/healthzz")) - self.assertTrue(excluded_urls.url_disabled("/path")) - self.assertTrue(excluded_urls.url_disabled("/issues/123/view")) - self.assertFalse(excluded_urls.url_disabled("/issues")) - self.assertFalse(excluded_urls.url_disabled("/hello")) diff --git a/opentelemetry-api/tests/configuration/test_exclude_list.py b/opentelemetry-api/tests/configuration/test_exclude_list.py deleted file mode 100644 index c7baf842ed7..00000000000 --- a/opentelemetry-api/tests/configuration/test_exclude_list.py +++ /dev/null @@ -1,60 +0,0 @@ -# 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. - -import unittest - -from opentelemetry.configuration import ExcludeList - - -class TestExcludeList(unittest.TestCase): - def test_basic(self): - regexes = ExcludeList(["path/123", "http://site.com/other_path"]) - self.assertTrue(regexes.url_disabled("http://site.com/path/123")) - self.assertTrue(regexes.url_disabled("http://site.com/path/123/abc")) - self.assertTrue( - regexes.url_disabled("https://site.com/path/123?arg=other") - ) - - self.assertFalse(regexes.url_disabled("https://site.com/path/abc/123")) - self.assertFalse(regexes.url_disabled("https://site.com/path")) - - self.assertTrue(regexes.url_disabled("http://site.com/other_path")) - self.assertTrue(regexes.url_disabled("http://site.com/other_path?abc")) - - self.assertFalse(regexes.url_disabled("https://site.com/other_path")) - self.assertFalse( - regexes.url_disabled("https://site.com/abc/other_path") - ) - - def test_regex(self): - regexes = ExcludeList( - [r"^https?://site\.com/path/123$", r"^http://.*\?arg=foo"] - ) - - self.assertTrue(regexes.url_disabled("http://site.com/path/123")) - self.assertTrue(regexes.url_disabled("https://site.com/path/123")) - - self.assertFalse(regexes.url_disabled("http://site.com/path/123/abc")) - self.assertFalse(regexes.url_disabled("http://site,com/path/123")) - - self.assertTrue( - regexes.url_disabled("http://site.com/path/123?arg=foo") - ) - self.assertTrue( - regexes.url_disabled("http://site.com/path/123?arg=foo,arg2=foo2") - ) - - self.assertFalse( - regexes.url_disabled("https://site.com/path/123?arg=foo") - ) diff --git a/opentelemetry-api/tests/propagators/test_propagators.py b/opentelemetry-api/tests/propagators/test_propagators.py index 70f4999dff7..9fceb91a0b7 100644 --- a/opentelemetry-api/tests/propagators/test_propagators.py +++ b/opentelemetry-api/tests/propagators/test_propagators.py @@ -18,7 +18,7 @@ from unittest.mock import Mock, patch from opentelemetry.baggage.propagation import BaggagePropagator -from opentelemetry.configuration import Configuration +from opentelemetry.environment_variables import OTEL_PROPAGATORS from opentelemetry.trace.propagation.tracecontext import ( TraceContextTextMapPropagator, ) @@ -44,15 +44,12 @@ def test_propagators(propagators): reload(opentelemetry.propagators) - @patch.dict(environ, {"OTEL_PROPAGATORS": "a,b,c"}) + @patch.dict(environ, {OTEL_PROPAGATORS: "a,b,c"}) @patch("opentelemetry.propagators.composite.CompositeHTTPPropagator") @patch("pkg_resources.iter_entry_points") def test_non_default_propagators( self, mock_iter_entry_points, mock_compositehttppropagator ): - - Configuration._reset() - def iter_entry_points_mock(_, propagator): return iter( [ diff --git a/opentelemetry-distro/src/opentelemetry/distro/__init__.py b/opentelemetry-distro/src/opentelemetry/distro/__init__.py index 8a48d256c7c..c4ac8f5e874 100644 --- a/opentelemetry-distro/src/opentelemetry/distro/__init__.py +++ b/opentelemetry-distro/src/opentelemetry/distro/__init__.py @@ -14,12 +14,18 @@ # import os from logging import getLogger +from os import environ from typing import Sequence, Tuple from pkg_resources import iter_entry_points from opentelemetry import trace -from opentelemetry.configuration import Configuration +from opentelemetry.environment_variables import ( + OTEL_METRICS_EXPORTER, + OTEL_PYTHON_IDS_GENERATOR, + OTEL_PYTHON_SERVICE_NAME, + OTEL_TRACE_EXPORTER, +) from opentelemetry.instrumentation.configurator import BaseConfigurator from opentelemetry.instrumentation.distro import BaseDistro from opentelemetry.sdk.metrics.export import MetricsExporter @@ -43,27 +49,47 @@ def _get_ids_generator() -> str: - return Configuration().IDS_GENERATOR or _DEFAULT_IDS_GENERATOR + return environ.get(OTEL_PYTHON_IDS_GENERATOR, _DEFAULT_IDS_GENERATOR) def _get_service_name() -> str: - return Configuration().SERVICE_NAME or "" + return environ.get(OTEL_PYTHON_SERVICE_NAME, "") def _get_exporter_names() -> Sequence[str]: - exporter = Configuration().EXPORTER or EXPORTER_OTLP - if exporter.lower().strip() == "none": - return [] - - names = [] - for exp in exporter.split(","): - name = exp.strip() - if name == EXPORTER_OTLP: - names.append(EXPORTER_OTLP_SPAN) - names.append(EXPORTER_OTLP_METRIC) - else: - names.append(name) - return names + trace_exporters = environ.get(OTEL_TRACE_EXPORTER) + metrics_exporters = environ.get(OTEL_METRICS_EXPORTER) + + exporters = set() + + if ( + trace_exporters is not None + or trace_exporters.lower().strip() != "none" + ): + exporters.update( + { + trace_exporter.strip() + for trace_exporter in trace_exporters.split(",") + } + ) + + if ( + metrics_exporters is not None + or metrics_exporters.lower().strip() != "none" + ): + exporters.update( + { + metrics_exporter.strip() + for metrics_exporter in metrics_exporters.split(",") + } + ) + + if EXPORTER_OTLP in exporters: + exporters.pop(EXPORTER_OTLP) + exporters.add(EXPORTER_OTLP_SPAN) + exporters.add(EXPORTER_OTLP_METRIC) + + return list(exporters) def _init_tracing( @@ -178,4 +204,5 @@ class OpenTelemetryDistro(BaseDistro): """ def _configure(self, **kwargs): - os.environ.setdefault("OTEL_EXPORTER", "otlp") + os.environ.setdefault(OTEL_TRACE_EXPORTER, "otlp_span") + os.environ.setdefault(OTEL_METRICS_EXPORTER, "otlp_metric") diff --git a/opentelemetry-distro/tests/test_configurator.py b/opentelemetry-distro/tests/test_configurator.py index 90ee7fe931f..e1a8cfc8ae0 100644 --- a/opentelemetry-distro/tests/test_configurator.py +++ b/opentelemetry-distro/tests/test_configurator.py @@ -17,12 +17,15 @@ from unittest import TestCase from unittest.mock import patch -from opentelemetry.configuration import Configuration from opentelemetry.distro import ( _get_ids_generator, _import_ids_generator, _init_tracing, ) +from opentelemetry.environment_variables import ( + OTEL_PYTHON_IDS_GENERATOR, + OTEL_PYTHON_SERVICE_NAME, +) from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace.ids_generator import ( IdsGenerator, @@ -99,8 +102,7 @@ def tearDown(self): # pylint: disable=protected-access def test_trace_init_default(self): - environ["OTEL_SERVICE_NAME"] = "my-test-service" - Configuration._reset() + environ[OTEL_PYTHON_SERVICE_NAME] = "my-test-service" _init_tracing({"zipkin": Exporter}, RandomIdsGenerator) self.assertEqual(self.set_provider_mock.call_count, 1) @@ -114,8 +116,7 @@ def test_trace_init_default(self): ) def test_trace_init_otlp(self): - environ["OTEL_SERVICE_NAME"] = "my-otlp-test-service" - Configuration._reset() + environ[OTEL_PYTHON_SERVICE_NAME] = "my-otlp-test-service" _init_tracing({"otlp": OTLPExporter}, RandomIdsGenerator) self.assertEqual(self.set_provider_mock.call_count, 1) @@ -129,9 +130,9 @@ def test_trace_init_otlp(self): provider.resource.attributes.get("service.name"), "my-otlp-test-service", ) - del environ["OTEL_SERVICE_NAME"] + del environ[OTEL_PYTHON_SERVICE_NAME] - @patch.dict(environ, {"OTEL_IDS_GENERATOR": "custom_ids_generator"}) + @patch.dict(environ, {OTEL_PYTHON_IDS_GENERATOR: "custom_ids_generator"}) @patch("opentelemetry.distro.IdsGenerator", new=IdsGenerator) @patch("opentelemetry.distro.iter_entry_points") def test_trace_init_custom_ids_generator(self, mock_iter_entry_points): @@ -140,7 +141,6 @@ def test_trace_init_custom_ids_generator(self, mock_iter_entry_points): IterEntryPoint("custom_ids_generator", CustomIdsGenerator) ] ) - Configuration._reset() ids_generator_name = _get_ids_generator() ids_generator = _import_ids_generator(ids_generator_name) _init_tracing({}, ids_generator) diff --git a/opentelemetry-distro/tests/test_distro.py b/opentelemetry-distro/tests/test_distro.py index 62d3a7e5e3f..109aead69e8 100644 --- a/opentelemetry-distro/tests/test_distro.py +++ b/opentelemetry-distro/tests/test_distro.py @@ -19,6 +19,10 @@ from pkg_resources import DistributionNotFound, require from opentelemetry.distro import OpenTelemetryDistro +from opentelemetry.environment_variables import ( + OTEL_METRICS_EXPORTER, + OTEL_TRACE_EXPORTER, +) class TestDistribution(TestCase): @@ -30,6 +34,8 @@ def test_package_available(self): def test_default_configuration(self): distro = OpenTelemetryDistro() - self.assertIsNone(os.environ.get("OTEL_EXPORTER")) + self.assertIsNone(os.environ.get(OTEL_TRACE_EXPORTER)) + self.assertIsNone(os.environ.get(OTEL_METRICS_EXPORTER)) distro.configure() - self.assertEqual("otlp", os.environ.get("OTEL_EXPORTER")) + self.assertEqual("otlp_span", os.environ.get(OTEL_TRACE_EXPORTER)) + self.assertEqual("otlp_metric", os.environ.get(OTEL_METRICS_EXPORTER)) diff --git a/opentelemetry-instrumentation/README.rst b/opentelemetry-instrumentation/README.rst index 97ebc5e7c49..1f6dd269e54 100644 --- a/opentelemetry-instrumentation/README.rst +++ b/opentelemetry-instrumentation/README.rst @@ -48,10 +48,11 @@ this can be overriden when needed. The command supports the following configuration options as CLI arguments and environment vars: -* ``--exporter`` or ``OTEL_EXPORTER`` +* ``--trace-exporter`` or ``OTEL_TRACE_EXPORTER`` +* ``--metrics-exporter`` or ``OTEL_METRICS_EXPORTER`` -Used to specify which trace exporter to use. Can be set to one or more -of the well-known exporter names (see below). +Used to specify which trace or metrics exporter to use. Can be set to one or +more of the well-known exporter names (see below). - Defaults to `otlp`. - Can be set to `none` to disable automatic tracer initialization. @@ -69,11 +70,11 @@ Well known trace exporter names: ``otlp`` is an alias for ``otlp_span,otlp_metric``. -* ``--service-name`` or ``OTEL_SERVICE_NAME`` +* ``--service-name`` or ``OTEL_PYTHON_SERVICE_NAME`` When present the value is passed on to the relevant exporter initializer as ``service_name`` argument. -* ``--ids-generator`` or ``OTEL_IDS_GENERATOR`` +* ``--ids-generator`` or ``OTEL_PYTHON_IDS_GENERATOR`` Used to specify which IDs Generator to use for the global Tracer Provider. By default, it will use the random IDs generator. diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py index 959708de964..7d827663cba 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/__init__.py @@ -20,6 +20,13 @@ from os.path import abspath, dirname, pathsep from shutil import which +from opentelemetry.environment_variables import ( + OTEL_METRICS_EXPORTER, + OTEL_PYTHON_IDS_GENERATOR, + OTEL_PYTHON_SERVICE_NAME, + OTEL_TRACE_EXPORTER, +) + logger = getLogger(__file__) @@ -32,18 +39,28 @@ def parse_args(): ) parser.add_argument( - "-e", - "--exporter", + "--metrics-exporter", + required=False, + help=""" + Uses the specified exporter to export metrics. + Accepts multiple exporters as comma separated values. + + Examples: + + --metrics-exporter=otlp_metric + """, + ) + + parser.add_argument( + "--trace-exporter", required=False, help=""" - Uses the specified exporter to export spans or metrics. + Uses the specified exporter to export spans. Accepts multiple exporters as comma separated values. Examples: - -e=otlp - -e=otlp_span,prometheus - -e=jaeger,otlp_metric + --trace-exporter=jaeger """, ) @@ -78,12 +95,14 @@ def parse_args(): def load_config_from_cli_args(args): - if args.exporter: - environ["OTEL_EXPORTER"] = args.exporter + if args.metrics_exporter: + environ[OTEL_METRICS_EXPORTER] = args.metrics_exporter + if args.trace_exporter: + environ[OTEL_TRACE_EXPORTER] = args.trace_exporter if args.service_name: - environ["OTEL_SERVICE_NAME"] = args.service_name + environ[OTEL_PYTHON_SERVICE_NAME] = args.service_name if args.ids_generator: - environ["OTEL_IDS_GENERATOR"] = args.ids_generator + environ[OTEL_PYTHON_IDS_GENERATOR] = args.ids_generator def run() -> None: diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py index 72be01fd18c..ba84bce5858 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py @@ -12,13 +12,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os import sys from logging import getLogger +from os import environ, path from pkg_resources import iter_entry_points -from opentelemetry.configuration import Configuration +from opentelemetry.environment_variables import ( + OTEL_PYTHON_DISABLED_INSTRUMENTATIONS, +) logger = getLogger(__file__) @@ -36,7 +38,7 @@ def _load_distros(): def _load_instrumentors(): - package_to_exclude = Configuration().get("DISABLED_INSTRUMENTATIONS", []) + package_to_exclude = environ.get(OTEL_PYTHON_DISABLED_INSTRUMENTATIONS, []) if isinstance(package_to_exclude, str): package_to_exclude = package_to_exclude.split(",") # to handle users entering "requests , flask" or "requests, flask" with spaces @@ -85,7 +87,7 @@ def initialize(): if ( hasattr(sys, "argv") - and sys.argv[0].split(os.path.sep)[-1] == "celery" + and sys.argv[0].split(path.sep)[-1] == "celery" and "worker" in sys.argv[1:] ): from celery.signals import worker_process_init # pylint:disable=E0401 diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py index 44487a77947..ff2d244aa8f 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py @@ -35,7 +35,6 @@ instrumentations = { "aiohttp-client": "opentelemetry-instrumentation-aiohttp-client>=0.15b0", "aiopg": "opentelemetry-instrumentation-aiopg>=0.15b0", - "asgi": "opentelemetry-instrumentation-asgi>=0.11b0", "asyncpg": "opentelemetry-instrumentation-asyncpg>=0.11b0", "boto": "opentelemetry-instrumentation-boto>=0.11b0", "botocore": "opentelemetry-instrumentation-botocore>=0.11b0", @@ -61,14 +60,12 @@ "sqlite3": "opentelemetry-instrumentation-sqlite3>=0.11b0", "starlette": "opentelemetry-instrumentation-starlette>=0.11b0", "tornado": "opentelemetry-instrumentation-tornado>=0.13b0", - "wsgi": "opentelemetry-instrumentation-wsgi>=0.8b0", } # relevant instrumentors and tracers to uninstall and check for conflicts for target libraries libraries = { "aiohttp-client": ("opentelemetry-instrumentation-aiohttp-client",), "aiopg": ("opentelemetry-instrumentation-aiopg",), - "asgi": ("opentelemetry-instrumentation-asgi",), "asyncpg": ("opentelemetry-instrumentation-asyncpg",), "boto": ("opentelemetry-instrumentation-boto",), "botocore": ("opentelemetry-instrumentation-botocore",), @@ -94,7 +91,6 @@ "sqlite3": ("opentelemetry-instrumentation-sqlite3",), "starlette": ("opentelemetry-instrumentation-starlette",), "tornado": ("opentelemetry-instrumentation-tornado",), - "wsgi": ("opentelemetry-instrumentation-wsgi",), } diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/instrumentor.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/instrumentor.py index dedeca20036..8cd77a8a5b7 100644 --- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/instrumentor.py +++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/instrumentor.py @@ -58,19 +58,11 @@ def instrument(self, **kwargs): """Instrument the library This method will be called without any optional arguments by the - ``opentelemetry-instrument`` command. The configuration of - the instrumentation when done in this way should be done by previously - setting the configuration (using environment variables or any other - mechanism) that will be used later by the code in the ``instrument`` - implementation via the global ``Configuration`` object. - - The ``instrument`` methods ``kwargs`` should default to values from the - ``Configuration`` object. + ``opentelemetry-instrument`` command. This means that calling this method directly without passing any optional values should do the very same thing that the - ``opentelemetry-instrument`` command does. This approach is - followed because the ``Configuration`` object is immutable. + ``opentelemetry-instrument`` command does. """ if not self._is_instrumented: diff --git a/opentelemetry-instrumentation/tests/test_run.py b/opentelemetry-instrumentation/tests/test_run.py index 9bff8514b14..6b8c097f068 100644 --- a/opentelemetry-instrumentation/tests/test_run.py +++ b/opentelemetry-instrumentation/tests/test_run.py @@ -18,6 +18,11 @@ from unittest import TestCase from unittest.mock import patch +from opentelemetry.environment_variables import ( + OTEL_METRICS_EXPORTER, + OTEL_PYTHON_SERVICE_NAME, + OTEL_TRACE_EXPORTER, +) from opentelemetry.instrumentation import auto_instrumentation @@ -107,18 +112,22 @@ class TestArgs(TestCase): def test_exporter(self, _): # pylint: disable=no-self-use with patch("sys.argv", ["instrument", "2"]): auto_instrumentation.run() - self.assertIsNone(environ.get("OTEL_EXPORTER")) + self.assertIsNone(environ.get(OTEL_METRICS_EXPORTER)) - with patch("sys.argv", ["instrument", "-e", "zipkin", "1", "2"]): + with patch( + "sys.argv", ["instrument", "--trace-exporter", "jaeger", "1", "2"] + ): auto_instrumentation.run() - self.assertEqual(environ.get("OTEL_EXPORTER"), "zipkin") + self.assertEqual(environ.get(OTEL_TRACE_EXPORTER), "jaeger") @patch("opentelemetry.instrumentation.auto_instrumentation.execl") def test_service_name(self, _): # pylint: disable=no-self-use with patch("sys.argv", ["instrument", "2"]): auto_instrumentation.run() - self.assertIsNone(environ.get("OTEL_SERVICE_NAME")) + self.assertIsNone(environ.get(OTEL_PYTHON_SERVICE_NAME)) with patch("sys.argv", ["instrument", "-s", "my-service", "1", "2"]): auto_instrumentation.run() - self.assertEqual(environ.get("OTEL_SERVICE_NAME"), "my-service") + self.assertEqual( + environ.get(OTEL_PYTHON_SERVICE_NAME), "my-service" + ) diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py new file mode 100644 index 00000000000..9ab85031b79 --- /dev/null +++ b/opentelemetry-sdk/src/opentelemetry/sdk/environment_variables/__init__.py @@ -0,0 +1,58 @@ +# 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. + +OTEL_RESOURCE_ATTRIBUTES = "OTEL_RESOURCE_ATTRIBUTES" +OTEL_LOG_LEVEL = "OTEL_LOG_LEVEL" +OTEL_TRACE_SAMPLER = "OTEL_TRACE_SAMPLER" +OTEL_TRACE_SAMPLER_ARG = "OTEL_TRACE_SAMPLER_ARG" +OTEL_BSP_SCHEDULE_DELAY = "OTEL_BSP_SCHEDULE_DELAY" +OTEL_BSP_EXPORT_TIMEOUT = "OTEL_BSP_EXPORT_TIMEOUT" +OTEL_BSP_MAX_QUEUE_SIZE = "OTEL_BSP_MAX_QUEUE_SIZE" +OTEL_BSP_MAX_EXPORT_BATCH_SIZE = "OTEL_BSP_MAX_EXPORT_BATCH_SIZE" +OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT = "OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT" +OTEL_SPAN_EVENT_COUNT_LIMIT = "OTEL_SPAN_EVENT_COUNT_LIMIT" +OTEL_SPAN_LINK_COUNT_LIMIT = "OTEL_SPAN_LINK_COUNT_LIMIT" +OTEL_EXPORTER_JAEGER_AGENT_HOST = "OTEL_EXPORTER_JAEGER_AGENT_HOST" +OTEL_EXPORTER_JAEGER_AGENT_PORT = "OTEL_EXPORTER_JAEGER_AGENT_PORT" +OTEL_EXPORTER_JAEGER_ENDPOINT = "OTEL_EXPORTER_JAEGER_ENDPOINT" +OTEL_EXPORTER_JAEGER_USER = "OTEL_EXPORTER_JAEGER_USER" +OTEL_EXPORTER_JAEGER_PASSWORD = "OTEL_EXPORTER_JAEGER_PASSWORD" +OTEL_EXPORTER_ZIPKIN_ENDPOINT = "OTEL_EXPORTER_ZIPKIN_ENDPOINT" +OTEL_EXPORTER_PROMETHEUS_HOST = "OTEL_EXPORTER_PROMETHEUS_HOST" +OTEL_EXPORTER_PROMETHEUS_PORT = "OTEL_EXPORTER_PROMETHEUS_PORT" +OTEL_EXPORTER_ENDPOINT = "OTEL_EXPORTER_ENDPOINT" +OTEL_EXPORTER_OTLP_PROTOCOL = "OTEL_EXPORTER_OTLP_PROTOCOL" +OTEL_EXPORTER_OTLP_CERTIFICATE = "OTEL_EXPORTER_OTLP_CERTIFICATE" +OTEL_EXPORTER_OTLP_HEADERS = "OTEL_EXPORTER_OTLP_HEADERS" +OTEL_EXPORTER_OTLP_COMPRESSION = "OTEL_EXPORTER_OTLP_COMPRESSION" +OTEL_EXPORTER_OTLP_TIMEOUT = "OTEL_EXPORTER_OTLP_TIMEOUT" +OTEL_EXPORTER_OTLP_ENDPOINT = "OTEL_EXPORTER_OTLP_ENDPOINT" +OTEL_EXPORTER_OTLP_SPAN_ENDPOINT = "OTEL_EXPORTER_OTLP_SPAN_ENDPOINT" +OTEL_EXPORTER_OTLP_METRIC_ENDPOINT = "OTEL_EXPORTER_OTLP_METRIC_ENDPOINT" +OTEL_EXPORTER_OTLP_SPAN_PROTOCOL = "OTEL_EXPORTER_OTLP_SPAN_PROTOCOL" +OTEL_EXPORTER_OTLP_METRIC_PROTOCOL = "OTEL_EXPORTER_OTLP_METRIC_PROTOCOL" +OTEL_EXPORTER_OTLP_SPAN_CERTIFICATE = "OTEL_EXPORTER_OTLP_SPAN_CERTIFICATE" +OTEL_EXPORTER_OTLP_METRIC_CERTIFICATE = "OTEL_EXPORTER_OTLP_METRIC_CERTIFICATE" +OTEL_EXPORTER_OTLP_SPAN_HEADERS = "OTEL_EXPORTER_OTLP_SPAN_HEADERS" +OTEL_EXPORTER_OTLP_METRIC_HEADERS = "OTEL_EXPORTER_OTLP_METRIC_HEADERS" +OTEL_EXPORTER_OTLP_SPAN_COMPRESSION = "OTEL_EXPORTER_OTLP_SPAN_COMPRESSION" +OTEL_EXPORTER_OTLP_METRIC_COMPRESSION = "OTEL_EXPORTER_OTLP_METRIC_COMPRESSION" +OTEL_EXPORTER_OTLP_SPAN_TIMEOUT = "OTEL_EXPORTER_OTLP_SPAN_TIMEOUT" +OTEL_EXPORTER_OTLP_METRIC_TIMEOUT = "OTEL_EXPORTER_OTLP_METRIC_TIMEOUT" +OTEL_EXPORTER_JAEGER_INSECURE = "OTEL_EXPORTER_JAEGER_INSECURE" +OTEL_EXPORTER_JAEGER_CERTIFICATE = "OTEL_EXPORTER_JAEGER_CERTIFICATE" +OTEL_EXPORTER_OTLP_INSECURE = "OTEL_EXPORTER_OTLP_INSECURE" +OTEL_EXPORTER_OTLP_SPAN_INSECURE = "OTEL_EXPORTER_OTLP_SPAN_INSECURE" +OTEL_EXPORTER_OTLP_METRIC_INSECURE = "OTEL_EXPORTER_OTLP_METRIC_INSECURE" +OTEL_EXPORTER_ZIPKIN_TRANSPORT_FORMAT = "OTEL_EXPORTER_ZIPKIN_TRANSPORT_FORMAT" diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py index 74d57439f31..aae838fe9e3 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py @@ -86,6 +86,8 @@ import pkg_resources +from opentelemetry.sdk.environment_variables import OTEL_RESOURCE_ATTRIBUTES + LabelValue = typing.Union[str, bool, int, float] Attributes = typing.Dict[str, LabelValue] logger = logging.getLogger(__name__) @@ -151,7 +153,6 @@ OPENTELEMETRY_SDK_VERSION = pkg_resources.get_distribution( "opentelemetry-sdk" ).version -OTEL_RESOURCE_ATTRIBUTES = "OTEL_RESOURCE_ATTRIBUTES" class Resource: diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py index adafedb3da0..2ecb82a0c3d 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py @@ -22,6 +22,7 @@ import traceback from collections import OrderedDict from contextlib import contextmanager +from os import environ from types import MappingProxyType, TracebackType from typing import ( Any, @@ -38,8 +39,12 @@ from opentelemetry import context as context_api from opentelemetry import trace as trace_api -from opentelemetry.configuration import Configuration from opentelemetry.sdk import util +from opentelemetry.sdk.environment_variables import ( + OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT, + OTEL_SPAN_EVENT_COUNT_LIMIT, + OTEL_SPAN_LINK_COUNT_LIMIT, +) from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import sampling from opentelemetry.sdk.trace.ids_generator import ( @@ -55,11 +60,12 @@ logger = logging.getLogger(__name__) -SPAN_ATTRIBUTE_COUNT_LIMIT = Configuration().get( - "SPAN_ATTRIBUTE_COUNT_LIMIT", 1000 +SPAN_ATTRIBUTE_COUNT_LIMIT = int( + environ.get(OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT, 1000) ) -SPAN_EVENT_COUNT_LIMIT = Configuration().get("SPAN_EVENT_COUNT_LIMIT", 1000) -SPAN_LINK_COUNT_LIMIT = Configuration().get("SPAN_LINK_COUNT_LIMIT", 1000) + +SPAN_EVENT_COUNT_LIMIT = int(environ.get(OTEL_SPAN_EVENT_COUNT_LIMIT, 1000)) +SPAN_LINK_COUNT_LIMIT = int(environ.get(OTEL_SPAN_LINK_COUNT_LIMIT, 1000)) VALID_ATTR_VALUE_TYPES = (bool, str, int, float) # pylint: disable=protected-access TRACE_SAMPLER = sampling._get_from_env_or_default() diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/export/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/export/__init__.py index ee63c84375f..4d4cc70224f 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/export/__init__.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/export/__init__.py @@ -13,17 +13,21 @@ # limitations under the License. import collections -import json import logging -import os import sys import threading import typing from enum import Enum +from os import environ, linesep from typing import Optional -from opentelemetry.configuration import Configuration from opentelemetry.context import Context, attach, detach, set_value +from opentelemetry.sdk.environment_variables import ( + OTEL_BSP_EXPORT_TIMEOUT, + OTEL_BSP_MAX_EXPORT_BATCH_SIZE, + OTEL_BSP_MAX_QUEUE_SIZE, + OTEL_BSP_SCHEDULE_DELAY, +) from opentelemetry.sdk.trace import Span, SpanProcessor from opentelemetry.util import time_ns @@ -123,21 +127,21 @@ def __init__( ): if max_queue_size is None: - max_queue_size = Configuration().get("BSP_MAX_QUEUE_SIZE", 2048) + max_queue_size = int(environ.get(OTEL_BSP_MAX_QUEUE_SIZE, 2048)) if schedule_delay_millis is None: - schedule_delay_millis = Configuration().get( - "BSP_SCHEDULE_DELAY_MILLIS", 5000 + schedule_delay_millis = int( + environ.get(OTEL_BSP_SCHEDULE_DELAY, 5000) ) if max_export_batch_size is None: - max_export_batch_size = Configuration().get( - "BSP_MAX_EXPORT_BATCH_SIZE", 512 + max_export_batch_size = int( + environ.get(OTEL_BSP_MAX_EXPORT_BATCH_SIZE, 512) ) if export_timeout_millis is None: - export_timeout_millis = Configuration().get( - "BSP_EXPORT_TIMEOUT_MILLIS", 30000 + export_timeout_millis = int( + environ.get(OTEL_BSP_EXPORT_TIMEOUT, 30000) ) if max_queue_size <= 0: @@ -375,7 +379,7 @@ def __init__( service_name: Optional[str] = None, out: typing.IO = sys.stdout, formatter: typing.Callable[[Span], str] = lambda span: span.to_json() - + os.linesep, + + linesep, ): self.out = out self.formatter = formatter diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py index bb174233542..17e90f78a94 100644 --- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py +++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py @@ -104,6 +104,10 @@ # pylint: disable=unused-import from opentelemetry.context import Context +from opentelemetry.sdk.environment_variables import ( + OTEL_TRACE_SAMPLER, + OTEL_TRACE_SAMPLER_ARG, +) from opentelemetry.trace import Link, get_current_span from opentelemetry.trace.span import TraceState from opentelemetry.util.types import Attributes @@ -366,7 +370,7 @@ def __init__(self, rate: float): def _get_from_env_or_default() -> Sampler: trace_sampler = os.getenv( - "OTEL_TRACE_SAMPLER", "parentbased_always_on" + OTEL_TRACE_SAMPLER, "parentbased_always_on" ).lower() if trace_sampler not in _KNOWN_SAMPLERS: _logger.warning("Couldn't recognize sampler %s.", trace_sampler) @@ -374,7 +378,7 @@ def _get_from_env_or_default() -> Sampler: if trace_sampler in ("traceidratio", "parentbased_traceidratio"): try: - rate = float(os.getenv("OTEL_TRACE_SAMPLER_ARG")) + rate = float(os.getenv(OTEL_TRACE_SAMPLER_ARG)) except ValueError: _logger.warning("Could not convert TRACE_SAMPLER_ARG to float.") rate = 1.0 diff --git a/opentelemetry-sdk/tests/conftest.py b/opentelemetry-sdk/tests/conftest.py index 5652fda036c..92fd7a734de 100644 --- a/opentelemetry-sdk/tests/conftest.py +++ b/opentelemetry-sdk/tests/conftest.py @@ -14,12 +14,14 @@ from os import environ +from opentelemetry.environment_variables import OTEL_PYTHON_CONTEXT + def pytest_sessionstart(session): # pylint: disable=unused-argument - environ["OTEL_CONTEXT"] = "contextvars_context" + environ[OTEL_PYTHON_CONTEXT] = "contextvars_context" def pytest_sessionfinish(session): # pylint: disable=unused-argument - environ.pop("OTEL_CONTEXT") + environ.pop(OTEL_PYTHON_CONTEXT) diff --git a/opentelemetry-sdk/tests/trace/export/test_export.py b/opentelemetry-sdk/tests/trace/export/test_export.py index 92d4f65d136..86cd990cca6 100644 --- a/opentelemetry-sdk/tests/trace/export/test_export.py +++ b/opentelemetry-sdk/tests/trace/export/test_export.py @@ -21,9 +21,14 @@ from unittest import mock from opentelemetry import trace as trace_api -from opentelemetry.configuration import Configuration from opentelemetry.context import Context from opentelemetry.sdk import trace +from opentelemetry.sdk.environment_variables import ( + OTEL_BSP_EXPORT_TIMEOUT, + OTEL_BSP_MAX_EXPORT_BATCH_SIZE, + OTEL_BSP_MAX_QUEUE_SIZE, + OTEL_BSP_SCHEDULE_DELAY, +) from opentelemetry.sdk.trace import export @@ -155,18 +160,13 @@ def _create_start_and_end_span(name, span_processor): class TestBatchExportSpanProcessor(unittest.TestCase): - def tearDown(self) -> None: - # reset global state of configuration object - # pylint: disable=protected-access - Configuration._reset() - @mock.patch.dict( "os.environ", { - "OTEL_BSP_MAX_QUEUE_SIZE": "10", - "OTEL_BSP_SCHEDULE_DELAY_MILLIS": "2", - "OTEL_BSP_MAX_EXPORT_BATCH_SIZE": "3", - "OTEL_BSP_EXPORT_TIMEOUT_MILLIS": "4", + OTEL_BSP_MAX_QUEUE_SIZE: "10", + OTEL_BSP_SCHEDULE_DELAY: "2", + OTEL_BSP_MAX_EXPORT_BATCH_SIZE: "3", + OTEL_BSP_EXPORT_TIMEOUT: "4", }, ) def test_batch_span_processor_environment_variables(self): diff --git a/opentelemetry-sdk/tests/trace/test_trace.py b/opentelemetry-sdk/tests/trace/test_trace.py index b507bc54399..66a5a82c309 100644 --- a/opentelemetry-sdk/tests/trace/test_trace.py +++ b/opentelemetry-sdk/tests/trace/test_trace.py @@ -24,9 +24,15 @@ import pytest from opentelemetry import trace as trace_api -from opentelemetry.configuration import Configuration from opentelemetry.context import Context from opentelemetry.sdk import resources, trace +from opentelemetry.sdk.environment_variables import ( + OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT, + OTEL_SPAN_EVENT_COUNT_LIMIT, + OTEL_SPAN_LINK_COUNT_LIMIT, + OTEL_TRACE_SAMPLER, + OTEL_TRACE_SAMPLER_ARG, +) from opentelemetry.sdk.trace import Resource, sampling from opentelemetry.sdk.trace.ids_generator import RandomIdsGenerator from opentelemetry.sdk.util import ns_to_iso_str @@ -188,7 +194,7 @@ def test_sampler_no_sampling(self): trace_api.TraceFlags.DEFAULT, ) - @mock.patch.dict("os.environ", {"OTEL_TRACE_SAMPLER": "always_off"}) + @mock.patch.dict("os.environ", {OTEL_TRACE_SAMPLER: "always_off"}) def test_sampler_with_env(self): # pylint: disable=protected-access reload(trace) @@ -207,8 +213,8 @@ def test_sampler_with_env(self): @mock.patch.dict( "os.environ", { - "OTEL_TRACE_SAMPLER": "parentbased_traceidratio", - "OTEL_TRACE_SAMPLER_ARG": "0.25", + OTEL_TRACE_SAMPLER: "parentbased_traceidratio", + OTEL_TRACE_SAMPLER_ARG: "0.25", }, ) def test_ratio_sampler_with_env(self): @@ -1282,22 +1288,12 @@ def test_attributes_to_json(self): class TestSpanLimits(unittest.TestCase): - def setUp(self): - # reset global state of configuration object - # pylint: disable=protected-access - Configuration._reset() - - def tearDown(self): - # reset global state of configuration object - # pylint: disable=protected-access - Configuration._reset() - @mock.patch.dict( "os.environ", { - "OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT": "10", - "OTEL_SPAN_EVENT_COUNT_LIMIT": "20", - "OTEL_SPAN_LINK_COUNT_LIMIT": "30", + OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT: "10", + OTEL_SPAN_EVENT_COUNT_LIMIT: "20", + OTEL_SPAN_LINK_COUNT_LIMIT: "30", }, ) def test_span_environment_limits(self): diff --git a/scripts/coverage.sh b/scripts/coverage.sh index 2b36a3f863d..00d98a0ca82 100755 --- a/scripts/coverage.sh +++ b/scripts/coverage.sh @@ -36,7 +36,7 @@ cov instrumentation/opentelemetry-instrumentation-flask cov instrumentation/opentelemetry-instrumentation-requests cov exporter/opentelemetry-exporter-jaeger cov instrumentation/opentelemetry-instrumentation-opentracing-shim -cov instrumentation/opentelemetry-instrumentation-wsgi +cov util/opentelemetry-util-http cov exporter/opentelemetry-exporter-zipkin # aiohttp is only supported on Python 3.5+. diff --git a/tests/w3c_tracecontext_validation_server.py b/tests/w3c_tracecontext_validation_server.py index f2fb14f206d..2d8246c7a06 100644 --- a/tests/w3c_tracecontext_validation_server.py +++ b/tests/w3c_tracecontext_validation_server.py @@ -25,12 +25,12 @@ from opentelemetry import trace from opentelemetry.instrumentation.requests import RequestsInstrumentor -from opentelemetry.instrumentation.wsgi import OpenTelemetryMiddleware from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import ( ConsoleSpanExporter, SimpleExportSpanProcessor, ) +from opentelemetry.util.http.wsgi import OpenTelemetryMiddleware # FIXME This could likely be avoided by integrating this script into the # standard test running mechanisms. diff --git a/tox.ini b/tox.ini index 6f27fa0dcb4..ef5f3f5a65c 100644 --- a/tox.ini +++ b/tox.ini @@ -105,7 +105,7 @@ commands_pre = distro: pip install {toxinidir}/opentelemetry-distro {toxinidir}/opentelemetry-distro instrumentation: pip install {toxinidir}/opentelemetry-instrumentation - getting-started: pip install -e {toxinidir}/opentelemetry-instrumentation -e {toxinidir}/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-requests -e {toxinidir}/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-wsgi -e {toxinidir}/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-flask + getting-started: pip install -e {toxinidir}/opentelemetry-instrumentation -e {toxinidir}/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-requests {toxinidir}/opentelemetry-python-contrib/util/opentelemetry-util-http -e {toxinidir}/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-flask opencensus: pip install {toxinidir}/exporter/opentelemetry-exporter-opencensus @@ -202,7 +202,7 @@ commands_pre = -e {toxinidir}/opentelemetry-instrumentation \ -e {toxinidir}/opentelemetry-sdk \ -e {toxinidir}/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-requests \ - -e {toxinidir}/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-wsgi + -e {toxinidir}/opentelemetry-python-contrib/util/opentelemetry-util-http commands = {toxinidir}/scripts/tracecontext-integration-test.sh