Skip to content

Commit ada53ff

Browse files
codebotenc24t
authored andcommitted
Separate no-op from interfaces (#311)
Fixes #66
1 parent f0ba817 commit ada53ff

File tree

9 files changed

+166
-38
lines changed

9 files changed

+166
-38
lines changed

ext/opentelemetry-ext-dbapi/tests/test_dbapi_integration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
class TestDBApiIntegration(unittest.TestCase):
2323
def setUp(self):
24-
self.tracer = trace_api.Tracer()
24+
self.tracer = trace_api.DefaultTracer()
2525
self.span = MockSpan()
2626
self.start_current_span_patcher = mock.patch.object(
2727
self.tracer,

ext/opentelemetry-ext-http-requests/tests/test_requests_integration.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ class TestRequestsIntegration(unittest.TestCase):
2929
# TODO: Copy & paste from test_wsgi_middleware
3030
def setUp(self):
3131
self.span_attrs = {}
32-
self.tracer_source = trace.TracerSource()
33-
self.tracer = trace.Tracer()
32+
self.tracer_source = trace.DefaultTracerSource()
33+
self.tracer = trace.DefaultTracer()
3434
self.get_tracer_patcher = mock.patch.object(
3535
self.tracer_source,
3636
"get_tracer",

ext/opentelemetry-ext-mysql/tests/test_mysql_integration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
class TestMysqlIntegration(unittest.TestCase):
2525
def test_trace_integration(self):
26-
tracer = trace_api.Tracer()
26+
tracer = trace_api.DefaultTracer()
2727
span = mock.create_autospec(trace_api.Span, spec_set=True)
2828
start_current_span_patcher = mock.patch.object(
2929
tracer,

opentelemetry-api/src/opentelemetry/metrics/__init__.py

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,15 @@ def record(self, label_set: LabelSet, value: ValueT) -> None:
184184

185185

186186
# pylint: disable=unused-argument
187-
class Meter:
187+
class Meter(abc.ABC):
188188
"""An interface to allow the recording of metrics.
189189
190190
`Metric` s are used for recording pre-defined aggregation (gauge and
191191
counter), or raw values (measure) in which the aggregation and labels
192192
for the exported metric are deferred.
193193
"""
194194

195+
@abc.abstractmethod
195196
def record_batch(
196197
self,
197198
label_set: LabelSet,
@@ -211,6 +212,7 @@ def record_batch(
211212
corresponding value to record for that metric.
212213
"""
213214

215+
@abc.abstractmethod
214216
def create_metric(
215217
self,
216218
name: str,
@@ -236,9 +238,8 @@ def create_metric(
236238
237239
Returns: A new ``metric_type`` metric with values of ``value_type``.
238240
"""
239-
# pylint: disable=no-self-use
240-
return DefaultMetric()
241241

242+
@abc.abstractmethod
242243
def get_label_set(self, labels: Dict[str, str]) -> "LabelSet":
243244
"""Gets a `LabelSet` with the given labels.
244245
@@ -247,6 +248,33 @@ def get_label_set(self, labels: Dict[str, str]) -> "LabelSet":
247248
248249
Returns: A `LabelSet` object canonicalized using the given input.
249250
"""
251+
252+
253+
class DefaultMeter(Meter):
254+
"""The default Meter used when no Meter implementation is available."""
255+
256+
def record_batch(
257+
self,
258+
label_set: LabelSet,
259+
record_tuples: Sequence[Tuple["Metric", ValueT]],
260+
) -> None:
261+
pass
262+
263+
def create_metric(
264+
self,
265+
name: str,
266+
description: str,
267+
unit: str,
268+
value_type: Type[ValueT],
269+
metric_type: Type[MetricT],
270+
label_keys: Sequence[str] = (),
271+
enabled: bool = True,
272+
monotonic: bool = False,
273+
) -> "Metric":
274+
# pylint: disable=no-self-use
275+
return DefaultMetric()
276+
277+
def get_label_set(self, labels: Dict[str, str]) -> "LabelSet":
250278
# pylint: disable=no-self-use
251279
return DefaultLabelSet()
252280

@@ -269,7 +297,7 @@ def meter() -> Meter:
269297

270298
if _METER is None:
271299
# pylint:disable=protected-access
272-
_METER = loader._load_impl(Meter, _METER_FACTORY)
300+
_METER = loader._load_impl(DefaultMeter, _METER_FACTORY)
273301
del _METER_FACTORY
274302

275303
return _METER

opentelemetry-api/src/opentelemetry/trace/__init__.py

Lines changed: 105 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
by `tracer_source`.
6767
"""
6868

69+
import abc
6970
import enum
7071
import types as python_types
7172
import typing
@@ -151,9 +152,10 @@ class SpanKind(enum.Enum):
151152
CONSUMER = 4
152153

153154

154-
class Span:
155+
class Span(abc.ABC):
155156
"""A span represents a single operation within a trace."""
156157

158+
@abc.abstractmethod
157159
def end(self, end_time: typing.Optional[int] = None) -> None:
158160
"""Sets the current time as the span's end time.
159161
@@ -163,6 +165,7 @@ def end(self, end_time: typing.Optional[int] = None) -> None:
163165
implementations are free to ignore or raise on further calls.
164166
"""
165167

168+
@abc.abstractmethod
166169
def get_context(self) -> "SpanContext":
167170
"""Gets the span's SpanContext.
168171
@@ -172,15 +175,15 @@ def get_context(self) -> "SpanContext":
172175
Returns:
173176
A :class:`.SpanContext` with a copy of this span's immutable state.
174177
"""
175-
# pylint: disable=no-self-use
176-
return INVALID_SPAN_CONTEXT
177178

179+
@abc.abstractmethod
178180
def set_attribute(self, key: str, value: types.AttributeValue) -> None:
179181
"""Sets an Attribute.
180182
181183
Sets a single Attribute with the key and value passed as arguments.
182184
"""
183185

186+
@abc.abstractmethod
184187
def add_event(
185188
self,
186189
name: str,
@@ -194,12 +197,14 @@ def add_event(
194197
timestamp if the `timestamp` argument is omitted.
195198
"""
196199

200+
@abc.abstractmethod
197201
def add_lazy_event(self, event: Event) -> None:
198202
"""Adds an `Event`.
199203
200204
Adds an `Event` that has previously been created.
201205
"""
202206

207+
@abc.abstractmethod
203208
def update_name(self, name: str) -> None:
204209
"""Updates the `Span` name.
205210
@@ -209,15 +214,15 @@ def update_name(self, name: str) -> None:
209214
on the implementation.
210215
"""
211216

217+
@abc.abstractmethod
212218
def is_recording_events(self) -> bool:
213219
"""Returns whether this span will be recorded.
214220
215221
Returns true if this Span is active and recording information like
216222
events with the add_event operation and attributes using set_attribute.
217223
"""
218-
# pylint: disable=no-self-use
219-
return False
220224

225+
@abc.abstractmethod
221226
def set_status(self, status: Status) -> None:
222227
"""Sets the Status of the Span. If used, this will override the default
223228
Span status, which is OK.
@@ -362,6 +367,29 @@ def get_context(self) -> "SpanContext":
362367
def is_recording_events(self) -> bool:
363368
return False
364369

370+
def end(self, end_time: typing.Optional[int] = None) -> None:
371+
pass
372+
373+
def set_attribute(self, key: str, value: types.AttributeValue) -> None:
374+
pass
375+
376+
def add_event(
377+
self,
378+
name: str,
379+
attributes: types.Attributes = None,
380+
timestamp: typing.Optional[int] = None,
381+
) -> None:
382+
pass
383+
384+
def add_lazy_event(self, event: Event) -> None:
385+
pass
386+
387+
def update_name(self, name: str) -> None:
388+
pass
389+
390+
def set_status(self, status: Status) -> None:
391+
pass
392+
365393

366394
INVALID_SPAN_ID = 0x0000000000000000
367395
INVALID_TRACE_ID = 0x00000000000000000000000000000000
@@ -374,8 +402,8 @@ def is_recording_events(self) -> bool:
374402
INVALID_SPAN = DefaultSpan(INVALID_SPAN_CONTEXT)
375403

376404

377-
class TracerSource:
378-
# pylint:disable=no-self-use,unused-argument
405+
class TracerSource(abc.ABC):
406+
@abc.abstractmethod
379407
def get_tracer(
380408
self,
381409
instrumenting_module_name: str,
@@ -402,10 +430,24 @@ def get_tracer(
402430
instrumenting library. Usually this should be the same as
403431
``pkg_resources.get_distribution(instrumenting_library_name).version``.
404432
"""
405-
return Tracer()
406433

407434

408-
class Tracer:
435+
class DefaultTracerSource(TracerSource):
436+
"""The default TracerSource, used when no implementation is available.
437+
438+
All operations are no-op.
439+
"""
440+
441+
def get_tracer(
442+
self,
443+
instrumenting_module_name: str,
444+
instrumenting_library_version: str = "",
445+
) -> "Tracer":
446+
# pylint:disable=no-self-use,unused-argument
447+
return DefaultTracer()
448+
449+
450+
class Tracer(abc.ABC):
409451
"""Handles span creation and in-process context propagation.
410452
411453
This class provides methods for manipulating the context, creating spans,
@@ -414,8 +456,9 @@ class Tracer:
414456

415457
# Constant used to represent the current span being used as a parent.
416458
# This is the default behavior when creating spans.
417-
CURRENT_SPAN = Span()
459+
CURRENT_SPAN = DefaultSpan(INVALID_SPAN_CONTEXT)
418460

461+
@abc.abstractmethod
419462
def get_current_span(self) -> "Span":
420463
"""Gets the currently active span from the context.
421464
@@ -426,9 +469,8 @@ def get_current_span(self) -> "Span":
426469
The currently active :class:`.Span`, or a placeholder span with an
427470
invalid :class:`.SpanContext`.
428471
"""
429-
# pylint: disable=no-self-use
430-
return INVALID_SPAN
431472

473+
@abc.abstractmethod
432474
def start_span(
433475
self,
434476
name: str,
@@ -478,10 +520,9 @@ def start_span(
478520
Returns:
479521
The newly-created span.
480522
"""
481-
# pylint: disable=unused-argument,no-self-use
482-
return INVALID_SPAN
483523

484524
@contextmanager # type: ignore
525+
@abc.abstractmethod
485526
def start_as_current_span(
486527
self,
487528
name: str,
@@ -531,10 +572,8 @@ def start_as_current_span(
531572
The newly-created span.
532573
"""
533574

534-
# pylint: disable=unused-argument,no-self-use
535-
yield INVALID_SPAN
536-
537575
@contextmanager # type: ignore
576+
@abc.abstractmethod
538577
def use_span(
539578
self, span: "Span", end_on_exit: bool = False
540579
) -> typing.Iterator[None]:
@@ -552,6 +591,47 @@ def use_span(
552591
end_on_exit: Whether to end the span automatically when leaving the
553592
context manager.
554593
"""
594+
595+
596+
class DefaultTracer(Tracer):
597+
"""The default Tracer, used when no Tracer implementation is available.
598+
599+
All operations are no-op.
600+
"""
601+
602+
def get_current_span(self) -> "Span":
603+
# pylint: disable=no-self-use
604+
return INVALID_SPAN
605+
606+
def start_span(
607+
self,
608+
name: str,
609+
parent: ParentSpan = Tracer.CURRENT_SPAN,
610+
kind: SpanKind = SpanKind.INTERNAL,
611+
attributes: typing.Optional[types.Attributes] = None,
612+
links: typing.Sequence[Link] = (),
613+
start_time: typing.Optional[int] = None,
614+
set_status_on_exception: bool = True,
615+
) -> "Span":
616+
# pylint: disable=unused-argument,no-self-use
617+
return INVALID_SPAN
618+
619+
@contextmanager # type: ignore
620+
def start_as_current_span(
621+
self,
622+
name: str,
623+
parent: ParentSpan = Tracer.CURRENT_SPAN,
624+
kind: SpanKind = SpanKind.INTERNAL,
625+
attributes: typing.Optional[types.Attributes] = None,
626+
links: typing.Sequence[Link] = (),
627+
) -> typing.Iterator["Span"]:
628+
# pylint: disable=unused-argument,no-self-use
629+
yield INVALID_SPAN
630+
631+
@contextmanager # type: ignore
632+
def use_span(
633+
self, span: "Span", end_on_exit: bool = False
634+
) -> typing.Iterator[None]:
555635
# pylint: disable=unused-argument,no-self-use
556636
yield
557637

@@ -576,9 +656,14 @@ def tracer_source() -> TracerSource:
576656

577657
if _TRACER_SOURCE is None:
578658
# pylint:disable=protected-access
579-
_TRACER_SOURCE = loader._load_impl(
580-
TracerSource, _TRACER_SOURCE_FACTORY
581-
)
659+
try:
660+
_TRACER_SOURCE = loader._load_impl(
661+
TracerSource, _TRACER_SOURCE_FACTORY # type: ignore
662+
)
663+
except TypeError:
664+
# if we raised an exception trying to instantiate an
665+
# abstract class, default to no-op tracer impl
666+
_TRACER_SOURCE = DefaultTracerSource()
582667
del _TRACER_SOURCE_FACTORY
583668

584669
return _TRACER_SOURCE

opentelemetry-api/tests/metrics/test_metrics.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
# pylint: disable=no-self-use
2121
class TestMeter(unittest.TestCase):
2222
def setUp(self):
23-
self.meter = metrics.Meter()
23+
self.meter = metrics.DefaultMeter()
2424

2525
def test_record_batch(self):
2626
counter = metrics.Counter()

0 commit comments

Comments
 (0)