Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resources sdk #464

Merged
merged 5 commits into from
Mar 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 0 additions & 55 deletions opentelemetry-api/src/opentelemetry/resources/__init__.py

This file was deleted.

Empty file.
13 changes: 12 additions & 1 deletion opentelemetry-sdk/src/opentelemetry/sdk/metrics/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from opentelemetry import metrics as metrics_api
from opentelemetry.sdk.metrics.export.aggregate import Aggregator
from opentelemetry.sdk.metrics.export.batcher import Batcher, UngroupedBatcher
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.util.instrumentation import InstrumentationInfo
from opentelemetry.util import time_ns

Expand Down Expand Up @@ -289,12 +290,16 @@ class Meter(metrics_api.Meter):
"""

def __init__(
self, instrumentation_info: "InstrumentationInfo", stateful: bool,
self,
instrumentation_info: "InstrumentationInfo",
stateful: bool,
resource: Resource = Resource.create_empty(),
):
self.instrumentation_info = instrumentation_info
self.metrics = set()
self.observers = set()
self.batcher = UngroupedBatcher(stateful)
self.resource = resource

def collect(self) -> None:
"""Collects all the metrics created with this `Meter` for export.
Expand Down Expand Up @@ -400,6 +405,11 @@ def get_label_set(self, labels: Dict[str, str]):


class MeterProvider(metrics_api.MeterProvider):
def __init__(
self, resource: Resource = Resource.create_empty(),
):
self.resource = resource

def get_meter(
self,
instrumenting_module_name: str,
Expand All @@ -413,4 +423,5 @@ def get_meter(
instrumenting_module_name, instrumenting_library_version
),
stateful=stateful,
resource=self.resource,
)
41 changes: 25 additions & 16 deletions opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,42 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import opentelemetry.resources as resources
import typing

LabelValue = typing.Union[str, bool, int, float]
Labels = typing.Dict[str, LabelValue]

class Resource(resources.Resource):
def __init__(self, labels):
self._labels = labels

class Resource:
def __init__(self, labels: Labels):
self._labels = labels.copy()

@staticmethod
def create(labels):
def create(labels: Labels) -> "Resource":
if not labels:
return _EMPTY_RESOURCE
return Resource(labels)

@staticmethod
def create_empty() -> "Resource":
return _EMPTY_RESOURCE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one thing about Resource is it's not exactly immutable right now, since the labels property returns the underlying container as an optimization.

Since we don't know how labels will be used anyway, should we just create a copy of the labels for now? That'll make sure the code above works.

Otherwise, all the default references to the empty Resource should be replaced with a constructor for a blank resource.


@property
def labels(self):
return self._labels

def merge(self, other):
if other is None:
return self
if not self._labels:
return other
merged_labels = self.labels.copy()
for key, value in other.labels.items():
def labels(self) -> Labels:
return self._labels.copy()

def merge(self, other: "Resource") -> "Resource":
merged_labels = self.labels
# pylint: disable=protected-access
for key, value in other._labels.items():
if key not in merged_labels or merged_labels[key] == "":
merged_labels[key] = value
return Resource(merged_labels)

def __eq__(self, other: object) -> bool:
if not isinstance(other, Resource):
return False
return self.labels == other.labels
return self._labels == other._labels


_EMPTY_RESOURCE = Resource({})
8 changes: 6 additions & 2 deletions opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from opentelemetry import context as context_api
from opentelemetry import trace as trace_api
from opentelemetry.sdk import util
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.util import BoundedDict, BoundedList
from opentelemetry.sdk.util.instrumentation import InstrumentationInfo
from opentelemetry.trace import SpanContext, sampling
Expand Down Expand Up @@ -127,7 +128,7 @@ class Span(trace_api.Span):
remote, null if this is a root span
sampler: The sampler used to create this span
trace_config: TODO
resource: TODO
resource: Entity producing telemetry
attributes: The span's attributes to be exported
events: Timestamped events to be exported
links: Links to other spans to be exported
Expand All @@ -147,7 +148,7 @@ def __init__(
parent: trace_api.ParentSpan = None,
sampler: Optional[sampling.Sampler] = None,
trace_config: None = None, # TODO
resource: None = None, # TODO
resource: None = None,
attributes: types.Attributes = None, # TODO
events: Sequence[trace_api.Event] = None, # TODO
links: Sequence[trace_api.Link] = (),
Expand Down Expand Up @@ -486,6 +487,7 @@ def start_span( # pylint: disable=too-many-locals
context=context,
parent=parent,
sampler=self.source.sampler,
resource=self.source.resource,
attributes=span_attributes,
span_processor=self.source._active_span_processor, # pylint:disable=protected-access
kind=kind,
Expand Down Expand Up @@ -535,9 +537,11 @@ class TracerProvider(trace_api.TracerProvider):
def __init__(
self,
sampler: sampling.Sampler = trace_api.sampling.ALWAYS_ON,
resource: Resource = Resource.create_empty(),
shutdown_on_exit: bool = True,
):
self._active_span_processor = MultiSpanProcessor()
self.resource = resource
self.sampler = sampler
self._atexit_handler = None
if shutdown_on_exit:
Expand Down
21 changes: 19 additions & 2 deletions opentelemetry-sdk/tests/metrics/test_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,24 @@
from unittest import mock

from opentelemetry import metrics as metrics_api
from opentelemetry.sdk import metrics
from opentelemetry.sdk import metrics, resources
from opentelemetry.sdk.metrics import export


class TestMeterProvider(unittest.TestCase):
def test_resource(self):
resource = resources.Resource.create({})
meter_provider = metrics.MeterProvider(resource=resource)
meter = meter_provider.get_meter(__name__)
self.assertIs(meter.resource, resource)

def test_resource_empty(self):
meter_provider = metrics.MeterProvider()
meter = meter_provider.get_meter(__name__)
# pylint: disable=protected-access
self.assertIs(meter.resource, resources._EMPTY_RESOURCE)


class TestMeter(unittest.TestCase):
def test_extends_api(self):
meter = metrics.MeterProvider().get_meter(__name__)
Expand Down Expand Up @@ -126,13 +140,16 @@ def test_record_batch_exists(self):
self.assertEqual(handle.aggregator.current, 2.0)

def test_create_metric(self):
meter = metrics.MeterProvider().get_meter(__name__)
resource = mock.Mock(spec=resources.Resource)
mauriciovasquezbernal marked this conversation as resolved.
Show resolved Hide resolved
meter_provider = metrics.MeterProvider(resource=resource)
meter = meter_provider.get_meter(__name__)
counter = meter.create_metric(
"name", "desc", "unit", int, metrics.Counter, ()
)
self.assertIsInstance(counter, metrics.Counter)
self.assertEqual(counter.value_type, int)
self.assertEqual(counter.name, "name")
self.assertIs(counter.meter.resource, resource)

def test_create_measure(self):
meter = metrics.MeterProvider().get_meter(__name__)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,35 @@
# See the License for the specific language governing permissions and
# limitations under the License.

# pylint: disable=protected-access

import unittest

from opentelemetry.sdk import resources


class TestResources(unittest.TestCase):
def test_create(self):
labels = {
"service": "ui",
"version": 1,
"has_bugs": True,
"cost": 112.12,
}

resource = resources.Resource.create(labels)
self.assertIsInstance(resource, resources.Resource)
self.assertEqual(resource.labels, labels)

resource = resources.Resource.create_empty()
self.assertIs(resource, resources._EMPTY_RESOURCE)

resource = resources.Resource.create(None)
self.assertIs(resource, resources._EMPTY_RESOURCE)

resource = resources.Resource.create({})
self.assertIs(resource, resources._EMPTY_RESOURCE)

def test_resource_merge(self):
left = resources.Resource({"service": "ui"})
right = resources.Resource({"host": "service-host"})
Expand All @@ -41,3 +64,22 @@ def test_resource_merge_empty_string(self):
left.merge(right),
resources.Resource({"service": "ui", "host": "service-host"}),
)

def test_immutability(self):
labels = {
"service": "ui",
"version": 1,
"has_bugs": True,
"cost": 112.12,
}

labels_copy = labels.copy()

resource = resources.Resource.create(labels)
self.assertEqual(resource.labels, labels_copy)

resource.labels["has_bugs"] = False
self.assertEqual(resource.labels, labels_copy)

labels["cost"] = 999.91
self.assertEqual(resource.labels, labels_copy)
16 changes: 15 additions & 1 deletion opentelemetry-sdk/tests/trace/test_trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from unittest import mock

from opentelemetry import trace as trace_api
from opentelemetry.sdk import trace
from opentelemetry.sdk import resources, trace
from opentelemetry.sdk.util.instrumentation import InstrumentationInfo
from opentelemetry.trace import sampling
from opentelemetry.trace.status import StatusCanonicalCode
Expand Down Expand Up @@ -364,6 +364,20 @@ def test_start_as_current_span_explicit(self):
self.assertIs(tracer.get_current_span(), root)
self.assertIsNotNone(child.end_time)

def test_explicit_span_resource(self):
resource = resources.Resource.create({})
tracer_provider = trace.TracerProvider(resource=resource)
tracer = tracer_provider.get_tracer(__name__)
span = tracer.start_span("root")
self.assertIs(span.resource, resource)

def test_default_span_resource(self):
tracer_provider = trace.TracerProvider()
tracer = tracer_provider.get_tracer(__name__)
span = tracer.start_span("root")
# pylint: disable=protected-access
self.assertIs(span.resource, resources._EMPTY_RESOURCE)


class TestSpan(unittest.TestCase):
def setUp(self):
Expand Down