Skip to content

Commit

Permalink
Add process runtime resource detector (#37)
Browse files Browse the repository at this point in the history
* Setup pytest

* sdk: introduce ProcessRuntimeResourceDetector

Add a process_runtime resource detector that only sets process runtime
related resource attributes.

* distro: enable process runtime resource detector by default

* ci: run unit tests on test matrix
  • Loading branch information
xrmx authored May 24, 2024
1 parent ad8df48 commit 25484fa
Show file tree
Hide file tree
Showing 11 changed files with 268 additions and 1 deletion.
21 changes: 21 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,24 @@ jobs:
- uses: actions/checkout@v4
- uses: ./.github/actions/env-install
- run: pip install -e .

unittest:
runs-on: ubuntu-latest
env:
py38: 3.8
py39: 3.9
py310: "3.10"
py311: "3.11"
strategy:
fail-fast: false
matrix:
python-version: [py38, py39, py310, py311]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ env[matrix.python-version] }}
uses: actions/setup-python@v5
with:
python-version: ${{ env[matrix.python-version] }}
architecture: "x64"
- run: pip install -r dev-requirements.txt
- run: pytest
113 changes: 113 additions & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile --extra=dev --output-file=dev-requirements.txt --strip-extras pyproject.toml
#
build==1.2.1
# via pip-tools
certifi==2024.2.2
# via requests
charset-normalizer==3.3.2
# via requests
click==8.1.7
# via pip-tools
deprecated==1.2.14
# via
# opentelemetry-api
# opentelemetry-exporter-otlp-proto-grpc
# opentelemetry-exporter-otlp-proto-http
exceptiongroup==1.2.1
# via pytest
googleapis-common-protos==1.63.0
# via
# opentelemetry-exporter-otlp-proto-grpc
# opentelemetry-exporter-otlp-proto-http
grpcio==1.64.0
# via opentelemetry-exporter-otlp-proto-grpc
idna==3.7
# via requests
importlib-metadata==7.0.0
# via opentelemetry-api
iniconfig==2.0.0
# via pytest
opentelemetry-api==1.24.0
# via
# elastic-opentelemetry (pyproject.toml)
# opentelemetry-exporter-otlp-proto-grpc
# opentelemetry-exporter-otlp-proto-http
# opentelemetry-instrumentation
# opentelemetry-instrumentation-system-metrics
# opentelemetry-sdk
opentelemetry-exporter-otlp==1.24.0
# via elastic-opentelemetry (pyproject.toml)
opentelemetry-exporter-otlp-proto-common==1.24.0
# via
# opentelemetry-exporter-otlp-proto-grpc
# opentelemetry-exporter-otlp-proto-http
opentelemetry-exporter-otlp-proto-grpc==1.24.0
# via opentelemetry-exporter-otlp
opentelemetry-exporter-otlp-proto-http==1.24.0
# via opentelemetry-exporter-otlp
opentelemetry-instrumentation==0.45b0
# via
# elastic-opentelemetry (pyproject.toml)
# opentelemetry-instrumentation-system-metrics
opentelemetry-instrumentation-system-metrics==0.45b0
# via elastic-opentelemetry (pyproject.toml)
opentelemetry-proto==1.24.0
# via
# opentelemetry-exporter-otlp-proto-common
# opentelemetry-exporter-otlp-proto-grpc
# opentelemetry-exporter-otlp-proto-http
opentelemetry-sdk==1.24.0
# via
# elastic-opentelemetry (pyproject.toml)
# opentelemetry-exporter-otlp-proto-grpc
# opentelemetry-exporter-otlp-proto-http
# opentelemetry-instrumentation-system-metrics
opentelemetry-semantic-conventions==0.45b0
# via opentelemetry-sdk
packaging==24.0
# via
# build
# pytest
pip-tools==7.4.1
# via elastic-opentelemetry (pyproject.toml)
pluggy==1.5.0
# via pytest
protobuf==4.25.3
# via
# googleapis-common-protos
# opentelemetry-proto
psutil==5.9.8
# via opentelemetry-instrumentation-system-metrics
pyproject-hooks==1.1.0
# via
# build
# pip-tools
pytest==8.2.1
# via elastic-opentelemetry (pyproject.toml)
requests==2.32.1
# via opentelemetry-exporter-otlp-proto-http
tomli==2.0.1
# via
# build
# pip-tools
# pytest
typing-extensions==4.11.0
# via opentelemetry-sdk
urllib3==2.2.1
# via requests
wheel==0.43.0
# via pip-tools
wrapt==1.16.0
# via
# deprecated
# opentelemetry-instrumentation
zipp==3.18.2
# via importlib-metadata

# The following packages are considered to be unsafe in a requirements file:
# pip
# setuptools
9 changes: 9 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,18 @@ dependencies = [
"opentelemetry-exporter-otlp == 1.24.0",
]

[project.optional-dependencies]
dev = ["pytest", "pip-tools"]

[project.entry-points.opentelemetry_configurator]
configurator = "elasticotel.distro:ElasticOpenTelemetryConfigurator"

[project.entry-points.opentelemetry_distro]
distro = "elasticotel.distro:ElasticOpenTelemetryDistro"

[project.entry-points.opentelemetry_resource_detector]
process_runtime = "elasticotel.sdk.resources:ProcessRuntimeResourceDetector"

[project.readme]
file = "README.md"
content-type = "text/markdown"
Expand All @@ -47,6 +53,9 @@ content-type = "text/markdown"
Homepage = "https://github.com/elastic/elastic-otel-python"
"Bug Tracker" = "https://github.com/elastic/elastic-otel-python/issues"

[tool.pytest.ini_options]
pythonpath = ["src"]

[tool.setuptools]
include-package-data = true
package-dir = {"" = "src"}
Expand Down
6 changes: 5 additions & 1 deletion src/elasticotel/distro/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
)
from opentelemetry.instrumentation.distro import BaseDistro
from opentelemetry.sdk._configuration import _OTelSDKConfigurator
from opentelemetry.sdk.environment_variables import OTEL_EXPORTER_OTLP_PROTOCOL
from opentelemetry.sdk.environment_variables import (
OTEL_EXPERIMENTAL_RESOURCE_DETECTORS,
OTEL_EXPORTER_OTLP_PROTOCOL,
)


class ElasticOpenTelemetryConfigurator(_OTelSDKConfigurator):
Expand All @@ -32,3 +35,4 @@ def _configure(self, **kwargs):
os.environ.setdefault(OTEL_TRACES_EXPORTER, "otlp")
os.environ.setdefault(OTEL_METRICS_EXPORTER, "otlp")
os.environ.setdefault(OTEL_EXPORTER_OTLP_PROTOCOL, "grpc")
os.environ.setdefault(OTEL_EXPERIMENTAL_RESOURCE_DETECTORS, "process_runtime,otel")
Empty file added src/elasticotel/sdk/__init__.py
Empty file.
45 changes: 45 additions & 0 deletions src/elasticotel/sdk/resources/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Copyright Elasticsearch BV
#
# 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 sys

from opentelemetry.sdk.resources import (
Resource,
ResourceDetector,
PROCESS_RUNTIME_DESCRIPTION,
PROCESS_RUNTIME_NAME,
PROCESS_RUNTIME_VERSION,
)


class ProcessRuntimeResourceDetector(ResourceDetector):
"""Subset of upstream ProcessResourceDetector to only fill process runtime attributes"""

def detect(self) -> "Resource":
runtime_version = ".".join(
map(
str,
(
sys.version_info[:3]
if sys.version_info.releaselevel == "final" and not sys.version_info.serial
else sys.version_info
),
)
)
resource_info = {
PROCESS_RUNTIME_DESCRIPTION: sys.version,
PROCESS_RUNTIME_NAME: sys.implementation.name,
PROCESS_RUNTIME_VERSION: runtime_version,
}
return Resource(resource_info)
Empty file added tests/__init__.py
Empty file.
Empty file added tests/distro/__init__.py
Empty file.
40 changes: 40 additions & 0 deletions tests/distro/test_distro.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright Elasticsearch BV
#
# 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 os
from unittest import TestCase

from elasticotel.distro import ElasticOpenTelemetryDistro
from opentelemetry.environment_variables import (
OTEL_METRICS_EXPORTER,
OTEL_TRACES_EXPORTER,
)
from opentelemetry.sdk.environment_variables import (
OTEL_EXPERIMENTAL_RESOURCE_DETECTORS,
OTEL_EXPORTER_OTLP_PROTOCOL,
)


class TestDistribution(TestCase):
def test_default_configuration(self):
distro = ElasticOpenTelemetryDistro()
self.assertIsNone(os.environ.get(OTEL_TRACES_EXPORTER))
self.assertIsNone(os.environ.get(OTEL_METRICS_EXPORTER))
self.assertIsNone(os.environ.get(OTEL_EXPORTER_OTLP_PROTOCOL))
self.assertIsNone(os.environ.get(OTEL_EXPERIMENTAL_RESOURCE_DETECTORS))
distro.configure()
self.assertEqual("otlp", os.environ.get(OTEL_TRACES_EXPORTER))
self.assertEqual("otlp", os.environ.get(OTEL_METRICS_EXPORTER))
self.assertEqual("grpc", os.environ.get(OTEL_EXPORTER_OTLP_PROTOCOL))
self.assertEqual("process_runtime,otel", os.environ.get(OTEL_EXPERIMENTAL_RESOURCE_DETECTORS))
Empty file added tests/resources/__init__.py
Empty file.
35 changes: 35 additions & 0 deletions tests/resources/test_resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright Elasticsearch BV
#
# 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.

from unittest import TestCase

from elasticotel.sdk.resources import ProcessRuntimeResourceDetector
from opentelemetry.sdk.resources import (
PROCESS_RUNTIME_NAME,
PROCESS_RUNTIME_DESCRIPTION,
PROCESS_RUNTIME_VERSION,
Resource,
get_aggregated_resources,
)


class TestProcessRuntimeDetector(TestCase):
def test_process_runtime_detector(self):
initial_resource = Resource(attributes={})
aggregated_resource = get_aggregated_resources([ProcessRuntimeResourceDetector()], initial_resource)

self.assertEqual(
sorted(aggregated_resource.attributes.keys()),
[PROCESS_RUNTIME_DESCRIPTION, PROCESS_RUNTIME_NAME, PROCESS_RUNTIME_VERSION],
)

0 comments on commit 25484fa

Please sign in to comment.