Skip to content

Commit d1cea92

Browse files
authored
Add initial tracer API (#11)
This PR adds the tracing API package and proposes some conventions for the package structure, documentation, and style of the project. It borrows heavily from opentelemetry-java and opencensus-python.
1 parent a1c5ab4 commit d1cea92

File tree

3 files changed

+242
-0
lines changed

3 files changed

+242
-0
lines changed

opentelemetry/__init__.py

Whitespace-only changes.

opentelemetry/api/__init__.py

Whitespace-only changes.

opentelemetry/api/trace/__init__.py

+242
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
# Copyright 2019, OpenTelemetry Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""
16+
The OpenTelemetry tracing API describes the classes used to generate
17+
distributed traces.
18+
19+
The :class:`.Tracer` class controls access to the execution context, and
20+
manages span creation. Each operation in a trace is represented by a
21+
:class:`.Span`, which records the start, end time, and metadata associated with
22+
the operation.
23+
24+
This module provides abstract (i.e. unimplemented) classes required for
25+
tracing, and a concrete no-op ``BlankSpan`` that allows applications to use the
26+
API package alone without a supporting implementation.
27+
28+
The tracer supports creating spans that are "attached" or "detached" from the
29+
context. By default, new spans are "attached" to the context in that they are
30+
created as children of the currently active span, and the newly-created span
31+
becomes the new active span::
32+
33+
# TODO (#15): which module holds the global tracer?
34+
from opentelemetry.api.trace import tracer
35+
36+
# Create a new root span, set it as the current span in context
37+
with tracer.start_span("parent"):
38+
# Attach a new child and update the current span
39+
with tracer.start_span("child"):
40+
do_work():
41+
# Close child span, set parent as current
42+
# Close parent span, set default span as current
43+
44+
When creating a span that's "detached" from the context the active span doesn't
45+
change, and the caller is responsible for managing the span's lifetime::
46+
47+
from opentelemetry.api.trace import tracer
48+
49+
# Explicit parent span assignment
50+
span = tracer.create_span("child", parent=parent) as child:
51+
52+
# The caller is responsible for starting and ending the span
53+
span.start()
54+
try:
55+
do_work(span=child)
56+
finally:
57+
span.end()
58+
59+
Applications should generally use a single global tracer, and use either
60+
implicit or explicit context propagation consistently throughout.
61+
62+
.. versionadded:: 0.1.0
63+
"""
64+
65+
from __future__ import annotations
66+
67+
from contextlib import contextmanager
68+
from typing import Iterator
69+
70+
71+
class Tracer(object):
72+
"""Handles span creation and in-process context propagation.
73+
74+
This class provides methods for manipulating the context, creating spans,
75+
and controlling spans' lifecycles.
76+
"""
77+
78+
def get_current_span(self) -> Span:
79+
"""Gets the currently active span from the context.
80+
81+
If there is no current span, return a placeholder span with an invalid
82+
context.
83+
84+
Returns:
85+
The currently active :class:`.Span`, or a placeholder span with an
86+
invalid :class:`.SpanContext`.
87+
"""
88+
pass
89+
90+
91+
@contextmanager
92+
def start_span(self, name: str, parent: Span) -> Iterator[Span]:
93+
"""Context manager for span creation.
94+
95+
Create a new child of the current span, or create a root span if no
96+
current span exists. Start the span and set it as the current span in
97+
this tracer's context.
98+
99+
On exiting the context manager stop the span and set its parent as the
100+
current span.
101+
102+
Example::
103+
104+
with tracer.start_span("one") as parent:
105+
parent.add_event("parent's event")
106+
with tracer.start_span("two") as child:
107+
child.add_event("child's event")
108+
tracer.get_current_span() # returns child
109+
tracer.get_current_span() # returns parent
110+
tracer.get_current_span() # returns the previously active span
111+
112+
This is a convenience method for creating spans attached to the
113+
tracer's context. Applications that need more control over the span
114+
lifetime should use :meth:`create_span` instead. For example::
115+
116+
with tracer.start_span(name) as span:
117+
do_work()
118+
119+
is equivalent to::
120+
121+
span = tracer.create_span(name, parent=tracer.get_current_span())
122+
with tracer.use_span(span):
123+
do_work()
124+
125+
Args:
126+
name: The name of the span to be created.
127+
parent: The span's parent.
128+
129+
Yields:
130+
The newly-created span.
131+
"""
132+
pass
133+
134+
def create_span(self, name: str, parent: Span) -> Span:
135+
"""Creates a new child span of the given parent.
136+
137+
Creating the span does not start it, and should not affect the tracer's
138+
context. To start the span and update the tracer's context to make it
139+
the currently active span, see :meth:`use_span`.
140+
141+
Applications that need to explicitly set spans' parents or create spans
142+
detached from the tracer's context should use this method.
143+
144+
with tracer.start_span(name) as span:
145+
do_work()
146+
147+
This is equivalent to::
148+
149+
span = tracer.create_span(name, parent=tracer.get_current_span())
150+
with tracer.use_span(span):
151+
do_work()
152+
153+
Args:
154+
name: The name of the span to be created.
155+
parent: The span's parent.
156+
157+
Returns:
158+
The newly-created span.
159+
"""
160+
pass
161+
162+
@contextmanager
163+
def use_span(self, span: Span) -> Iterator[None]:
164+
"""Context manager for controlling a span's lifetime.
165+
166+
Start the given span and set it as the current span in this tracer's
167+
context.
168+
169+
On exiting the context manager stop the span and set its parent as the
170+
current span.
171+
172+
Args:
173+
span: The span to start and make current.
174+
"""
175+
pass
176+
177+
178+
class Span(object):
179+
"""A span represents a single operation within a trace."""
180+
181+
def start(self) -> None:
182+
"""Sets the current time as the span's start time.
183+
184+
Each span represents a single operation. The span's start time is the
185+
wall time at which the operation started.
186+
187+
Only the first call to ``start`` should modify the span, and
188+
implementations are free to ignore or raise on further calls.
189+
"""
190+
pass
191+
192+
def end(self) -> None:
193+
"""Sets the current time as the span's end time.
194+
195+
The span's end time is the wall time at which the operation finished.
196+
197+
Only the first call to ``end`` should modify the span, and
198+
implementations are free to ignore or raise on further calls.
199+
"""
200+
pass
201+
202+
def get_context(self) -> SpanContext:
203+
"""Gets the span's SpanContext.
204+
205+
Get an immutable, serializable identifier for this span that can be
206+
used to create new child spans.
207+
208+
Returns:
209+
A :class:`.SpanContext` with a copy of this span's immutable state.
210+
"""
211+
pass
212+
213+
214+
class SpanContext(object):
215+
"""The state of a Span to propagate between processes.
216+
217+
This class includes the immutable attributes of a :class:`.Span` that must
218+
be propagated to a span's children and across process boundaries.
219+
220+
Args:
221+
trace_id: The ID of the trace that this span belongs to.
222+
span_id: This span's ID.
223+
options: Trace options to propagate.
224+
state: Tracing-system-specific info to propagate.
225+
"""
226+
227+
def __init__(self,
228+
trace_id: str,
229+
span_id: str,
230+
options: TraceOptions,
231+
state: TraceState) -> None:
232+
pass
233+
234+
235+
# TODO
236+
class TraceOptions(int):
237+
pass
238+
239+
240+
# TODO
241+
class TraceState(dict):
242+
pass

0 commit comments

Comments
 (0)