1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
|
# ------------------------------------
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# ------------------------------------
"""Fake implementation of AbstractSpan for tests. Copied from `azure-core/tests`."""
from contextlib import contextmanager
from typing import Union, Sequence, Optional, Dict
import uuid
from azure.core.tracing import HttpSpanMixin, SpanKind
AttributeValue = Union[
str,
bool,
int,
float,
Sequence[str],
Sequence[bool],
Sequence[int],
Sequence[float],
]
Attributes = Optional[Dict[str, AttributeValue]]
class FakeSpan(HttpSpanMixin, object):
# Keep a fake context of the current one
CONTEXT = []
def __init__(self, span=None, name="span", kind=None, *, links=[], **kwargs):
# type: (Optional[Span], Optional[str]) -> None
"""
If a span is not passed in, creates a new tracer. If the instrumentation key for Azure Exporter is given, will
configure the azure exporter else will just create a new tracer.
:param span: The OpenTelemetry span to wrap
:type span: :class: OpenTelemetry.trace.Span
:param name: The name of the OpenTelemetry span to create if a new span is needed
:type name: str
"""
self._span = span
self.name = name
self._kind = kind or SpanKind.UNSPECIFIED
self.attributes = {}
self.children = []
self.status = None
self.links = links
self.traceparent = uuid.uuid4().hex
def __str__(self):
buffer = "Name: {}\n".format(self.name)
buffer += "Children:\n"
subchildren = "\n".join(str(child) for child in self.children)
buffer += "\n".join("\t{}".format(line) for line in subchildren.splitlines())
return buffer
@property
def span_instance(self):
# type: () -> Span
"""
:return: The OpenTelemetry span that is being wrapped.
"""
return self._span
def span(self, name="span", kind=None, links=[]):
# type: (Optional[str]) -> OpenCensusSpan
"""
Create a child span for the current span and append it to the child spans list in the span instance.
:param name: Name of the child span
:type name: str
:return: The OpenCensusSpan that is wrapping the child span instance
"""
return self.__class__(name=name, kind=kind, links=links)
@property
def kind(self):
# type: () -> Optional[SpanKind]
"""Get the span kind of this span."""
return self._kind
@kind.setter
def kind(self, value):
# type: (SpanKind) -> None
"""Set the span kind of this span."""
self._kind = value
def __enter__(self):
"""Start a span."""
if self.CONTEXT:
self.CONTEXT[-1].children.append(self)
self.CONTEXT.append(self)
return self
def __exit__(self, exception_type, exception_value, traceback):
"""Finish a span."""
if exception_value:
self.status = exception_value.args[0]
if self.CONTEXT and len(self.CONTEXT) > 0:
self.CONTEXT.pop()
def start(self):
# type: () -> None
"""Set the start time for a span."""
pass
def finish(self):
# type: () -> None
"""Set the end time for a span."""
self.CONTEXT.pop()
def to_header(self):
# type: () -> Dict[str, str]
"""
Returns a dictionary with the header labels and values.
:return: A key value pair dictionary
"""
return {"traceparent": self.traceparent}
def add_attribute(self, key, value):
# type: (str, Union[str, int]) -> None
"""
Add attribute (key value pair) to the current span.
:param key: The key of the key value pair
:type key: str
:param value: The value of the key value pair
:type value: str
"""
self.attributes[key] = value
def get_trace_parent(self):
"""Return traceparent string as defined in W3C trace context specification.
Example:
Value = 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
base16(version) = 00
base16(trace-id) = 4bf92f3577b34da6a3ce929d0e0e4736
base16(parent-id) = 00f067aa0ba902b7
base16(trace-flags) = 01 // sampled
:return: a traceparent string
:rtype: str
"""
return self.to_header()["traceparent"]
@classmethod
def link(cls, traceparent, attributes=None):
# type: (str, Attributes) -> None
"""
Links the context to the current tracer.
:param traceparent: A complete traceparent
:type traceparent: str
"""
cls.link_from_headers({"traceparent": traceparent})
@classmethod
def link_from_headers(cls, headers, attributes=None):
# type: (Dict[str, str], Attributes) -> None
"""
Given a dictionary, extracts the context and links the context to the current tracer.
:param headers: A key value pair dictionary
:type headers: dict
"""
raise NotImplementedError("This method needs to be implemented")
@classmethod
def get_current_span(cls):
# type: () -> Span
"""
Get the current span from the execution context. Return None otherwise.
"""
return cls.CONTEXT[-1]
@classmethod
def get_current_tracer(cls):
# type: () -> Tracer
"""
Get the current tracer from the execution context. Return None otherwise.
"""
raise NotImplementedError()
@classmethod
@contextmanager
def change_context(cls, span):
# type: (Span) -> ContextManager
"""Change the context for the life of this context manager."""
try:
cls.CONTEXT.append(span)
yield
finally:
cls.CONTEXT.pop()
@classmethod
def set_current_span(cls, span):
# type: (Span) -> None
"""Not supported by OpenTelemetry."""
raise NotImplementedError()
@classmethod
def set_current_tracer(cls, tracer):
# type: (Tracer) -> None
"""
Set the given tracer as the current tracer in the execution context.
:param tracer: The tracer to set the current tracer as
:type tracer: :class: OpenTelemetry.trace.Tracer
"""
raise NotImplementedError()
@classmethod
def with_current_context(cls, func):
# type: (Callable) -> Callable
"""Passes the current spans to the new context the function will be run in.
:param func: The function that will be run in the new context
:return: The target the pass in instead of the function
"""
return func
|