Exemplo n.º 1
0
    def __call__(self, *args, **kwargs):
        data = to_json(request.json)
        result = self.action(data)

        if isinstance(result, requests.models.Response):
            self.response.status_code = result.status_code
            self.response.set_data(result.content)
            try:
                res_json = json.loads(result.content)
                if result.status_code == 402:
                    trace.get_current_span().add_event(
                        "exception", {
                            "exception.code": int(result.status_code),
                            "exception.message": res_json['error']
                        }, time_ns())
            except:
                pass
        else:
            self.response.status_code = result.code
            self.response.set_data(
                str({
                    'msg': result.msg,
                    'error': result.error
                }))

            if result.code == 402:
                trace.get_current_span().add_event(
                    "exception", {
                        "exception.code": int(result.code),
                        "exception.message": str(result.error)
                    }, time_ns())

        return self.response
Exemplo n.º 2
0
    def worker(self):
        timeout = self.schedule_delay_millis / 1e3
        while not self.done:
            if (
                len(self.queue) < self.max_export_batch_size
                and not self._flushing
            ):
                with self.condition:
                    self.condition.wait(timeout)
                    if not self.queue:
                        # spurious notification, let's wait again
                        continue
                    if self.done:
                        # missing spans will be sent when calling flush
                        break

            # substract the duration of this export call to the next timeout
            start = time_ns()
            self.export()
            end = time_ns()
            duration = (end - start) / 1e9
            timeout = self.schedule_delay_millis / 1e3 - duration

        # be sure that all spans are sent
        self._drain_queue()
Exemplo n.º 3
0
    def test_events(self):
        self.assertIsNone(self.tracer.get_current_span())

        with self.tracer.start_as_current_span("root") as root:
            # only event name
            root.add_event("event0")

            # event name and attributes
            now = time_ns()
            root.add_event("event1", {"name": "pluto"})

            # event name, attributes and timestamp
            now = time_ns()
            root.add_event("event2", {"name": "birthday"}, now)

            # lazy event
            root.add_lazy_event(
                trace_api.Event("event3", {"name": "hello"}, now))

            self.assertEqual(len(root.events), 4)

            self.assertEqual(root.events[0].name, "event0")
            self.assertEqual(root.events[0].attributes, {})

            self.assertEqual(root.events[1].name, "event1")
            self.assertEqual(root.events[1].attributes, {"name": "pluto"})

            self.assertEqual(root.events[2].name, "event2")
            self.assertEqual(root.events[2].attributes, {"name": "birthday"})
            self.assertEqual(root.events[2].timestamp, now)

            self.assertEqual(root.events[3].name, "event3")
            self.assertEqual(root.events[3].attributes, {"name": "hello"})
            self.assertEqual(root.events[3].timestamp, now)
Exemplo n.º 4
0
    def test_events(self):
        self.assertEqual(trace_api.get_current_span(), trace_api.INVALID_SPAN)

        with self.tracer.start_as_current_span("root") as root:
            # only event name
            root.add_event("event0")

            # event name and attributes
            now = time_ns()
            root.add_event("event1", {
                "name": "pluto",
                "some_bools": [True, False]
            })

            # event name, attributes and timestamp
            now = time_ns()
            root.add_event("event2", {"name": ["birthday"]}, now)

            mutable_list = ["original_contents"]
            root.add_event("event3", {"name": mutable_list})

            def event_formatter():
                return {"name": "hello"}

            # lazy event
            root.add_lazy_event("event4", event_formatter, now)

            self.assertEqual(len(root.events), 5)

            self.assertEqual(root.events[0].name, "event0")
            self.assertEqual(root.events[0].attributes, {})

            self.assertEqual(root.events[1].name, "event1")
            self.assertEqual(
                root.events[1].attributes,
                {
                    "name": "pluto",
                    "some_bools": (True, False)
                },
            )

            self.assertEqual(root.events[2].name, "event2")
            self.assertEqual(root.events[2].attributes,
                             {"name": ("birthday", )})
            self.assertEqual(root.events[2].timestamp, now)

            self.assertEqual(root.events[3].name, "event3")
            self.assertEqual(root.events[3].attributes,
                             {"name": ("original_contents", )})
            mutable_list = ["new_contents"]
            self.assertEqual(root.events[3].attributes,
                             {"name": ("original_contents", )})

            self.assertEqual(root.events[4].name, "event4")
            self.assertEqual(root.events[4].attributes, {"name": "hello"})
            self.assertEqual(root.events[4].timestamp, now)
Exemplo n.º 5
0
 def record(self, value: metrics_api.ValueT) -> None:
     """See `opentelemetry.metrics.MeasureHandle.record`."""
     if self._validate_update(value):
         if self.monotonic and value < 0:
             logger.warning("Monotonic measure cannot accept negatives.")
             return
         self.last_update_timestamp = time_ns()
def _prepare(tracer, func, handler, args, kwargs):
    start_time = time_ns()
    request = handler.request
    if _excluded_urls.url_disabled(request.uri):
        return func(*args, **kwargs)
    _start_span(tracer, handler, start_time)
    return func(*args, **kwargs)
    def _wrapped_app(wrapped_app_environ, start_response):
        # We want to measure the time for route matching, etc.
        # In theory, we could start the span here and use
        # update_name later but that API is "highly discouraged" so
        # we better avoid it.
        wrapped_app_environ[_ENVIRON_STARTTIME_KEY] = time_ns()

        def _start_response(status, response_headers, *args, **kwargs):
            if not _excluded_urls.url_disabled(flask.request.url):
                span = flask.request.environ.get(_ENVIRON_SPAN_KEY)

                if span:
                    otel_wsgi.add_response_attributes(
                        span, status, response_headers
                    )
                else:
                    _logger.warning(
                        "Flask environ's OpenTelemetry span "
                        "missing at _start_response(%s)",
                        status,
                    )

            return start_response(status, response_headers, *args, **kwargs)

        return wsgi_app(wrapped_app_environ, _start_response)
def fetch_async(tracer, func, _, args, kwargs):
    start_time = time_ns()

    # Return immediately if no args were provided (error)
    # or original_request is set (meaning we are in a redirect step).
    if len(args) == 0 or hasattr(args[0], "original_request"):
        return func(*args, **kwargs)

    # Force the creation of a HTTPRequest object if needed,
    # so we can inject the context into the headers.
    args, kwargs = _normalize_request(args, kwargs)
    request = args[0]

    span = tracer.start_span(
        request.method, kind=trace.SpanKind.CLIENT, start_time=start_time,
    )

    if span.is_recording():
        attributes = {
            "component": "tornado",
            "http.url": request.url,
            "http.method": request.method,
        }
        for key, value in attributes.items():
            span.set_attribute(key, value)

    with tracer.use_span(span):
        propagators.inject(type(request.headers).__setitem__, request.headers)
        future = func(*args, **kwargs)
        future.add_done_callback(
            functools.partial(_finish_tracing_callback, span=span)
        )
        return future
Exemplo n.º 9
0
    def test_invalid_event_attributes(self):
        self.assertEqual(trace_api.get_current_span(), trace_api.INVALID_SPAN)
        now = time_ns()

        with self.tracer.start_as_current_span("root") as root:
            root.add_event("event0", {"attr1": True, "attr2": ["hi", False]})
            root.add_event("event0", {"attr1": dict()})
            root.add_event("event0", {"attr1": [[True]]})
            root.add_event("event0", {"attr1": [dict()], "attr2": [1, 2]})

            self.assertEqual(len(root.events), 4)
            self.assertEqual(root.events[0].attributes, {"attr1": True})
            self.assertEqual(root.events[1].attributes, {})
            self.assertEqual(root.events[2].attributes, {})
            self.assertEqual(root.events[3].attributes, {"attr2": (1, 2)})

            def event_formatter():
                properties = {}
                properties["attr1"] = dict()
                properties["attr2"] = "hello"
                return properties

            root.add_lazy_event("event4", event_formatter, now)

            self.assertEqual(len(root.events), 5)
            self.assertEqual(root.events[4].name, "event4")
            self.assertEqual(root.events[4].attributes, {"attr2": "hello"})
            self.assertEqual(root.events[4].timestamp, now)
Exemplo n.º 10
0
 def set(self, value: metrics_api.ValueT) -> None:
     """See `opentelemetry.metrics.GaugeHandle.set`."""
     if self._validate_update(value):
         if self.monotonic and value < self.data:
             logger.warning("Monotonic gauge cannot descend.")
             return
         self.last_update_timestamp = time_ns()
         self.data = value
Exemplo n.º 11
0
 def add(self, value: metrics_api.ValueT) -> None:
     """See `opentelemetry.metrics.CounterHandle.add`."""
     if self._validate_update(value):
         if self.monotonic and value < 0:
             logger.warning("Monotonic counter cannot descend.")
             return
         self.last_update_timestamp = time_ns()
         self.data += value
Exemplo n.º 12
0
    def worker(self):
        timeout = self.schedule_delay_millis / 1e3
        flush_request = None  # type: typing.Optional[_FlushRequest]
        while not self.done:
            with self.condition:
                if self.done:
                    # done flag may have changed, avoid waiting
                    break
                flush_request = self._get_and_unset_flush_request()
                if (
                    len(self.queue) < self.max_export_batch_size
                    and flush_request is None
                ):

                    self.condition.wait(timeout)
                    flush_request = self._get_and_unset_flush_request()
                    if not self.queue:
                        # spurious notification, let's wait again, reset timeout
                        timeout = self.schedule_delay_millis / 1e3
                        self._notify_flush_request_finished(flush_request)
                        flush_request = None
                        continue
                    if self.done:
                        # missing spans will be sent when calling flush
                        break

            # subtract the duration of this export call to the next timeout
            start = time_ns()
            self._export(flush_request)
            end = time_ns()
            duration = (end - start) / 1e9
            timeout = self.schedule_delay_millis / 1e3 - duration

            self._notify_flush_request_finished(flush_request)
            flush_request = None

        # there might have been a new flush request while export was running
        # and before the done flag switched to true
        with self.condition:
            shutdown_flush_request = self._get_and_unset_flush_request()

        # be sure that all spans are sent
        self._drain_queue()
        self._notify_flush_request_finished(flush_request)
        self._notify_flush_request_finished(shutdown_flush_request)
Exemplo n.º 13
0
    def test_export(self):
        trace_id = "6e0c63257de34c92bf9efcd03927272e"
        span_id = "95bb5edabd45950f"

        # Create span and associated data.
        resource_info = Resource(
            {
                "cloud.account.id": 123,
                "host.id": "host",
                "cloud.zone": "US",
                "cloud.provider": "gcp",
                "gcp.resource_type": "gce_instance",
            }
        )
        span = Span(
            name="span_name",
            context=SpanContext(
                trace_id=int(trace_id, 16),
                span_id=int(span_id, 16),
                is_remote=False,
            ),
            parent=None,
            kind=SpanKind.INTERNAL,
            resource=resource_info,
            attributes={"attr_key": "attr_value"},
        )

        # pylint: disable=protected-access
        span._start_time = int(time_ns() - (60 * 1e9))
        span._end_time = time_ns()
        span_data = [span]

        # Setup the trace exporter.
        channel = grpc.insecure_channel(self.address)
        transport = trace_service_grpc_transport.TraceServiceGrpcTransport(
            channel=channel
        )
        client = TraceServiceClient(transport=transport)
        trace_exporter = CloudTraceSpanExporter(self.project_id, client=client)

        # Export the spans and verify the results.
        result = trace_exporter.export(span_data)
        self.assertEqual(result, SpanExportResult.SUCCESS)
Exemplo n.º 14
0
 def __init__(
     self,
     value_type: Type[metrics_api.ValueT],
     enabled: bool,
     aggregator: Aggregator,
 ):
     self.value_type = value_type
     self.enabled = enabled
     self.aggregator = aggregator
     self.last_update_timestamp = time_ns()
Exemplo n.º 15
0
    def end(self, end_time: Optional[int] = None) -> None:
        with self._lock:
            if self.start_time is None:
                raise RuntimeError("Calling end() on a not started span.")
            if self.end_time is not None:
                logger.warning("Calling end() on an ended span.")
                return

            self._end_time = end_time if end_time is not None else time_ns()

        self.span_processor.on_end(self)
Exemplo n.º 16
0
 def __init__(
     self,
     value_type: Type[metrics_api.ValueT],
     enabled: bool,
     monotonic: bool,
 ):
     self.data = value_type()
     self.value_type = value_type
     self.enabled = enabled
     self.monotonic = monotonic
     self.last_update_timestamp = time_ns()
Exemplo n.º 17
0
 def __init__(
     self,
     value_type: Type[metrics_api.ValueT],
     enabled: bool,
     aggregator: Aggregator,
 ):
     self.value_type = value_type
     self.enabled = enabled
     self.aggregator = aggregator
     self.last_update_timestamp = time_ns()
     self._ref_count = 0
     self._ref_count_lock = threading.Lock()
Exemplo n.º 18
0
 def update(self, value):
     with self._lock:
         if self.current is self._EMPTY:
             self.current = self._TYPE(value, value, value, 1)
         else:
             self.current = self._TYPE(
                 min(self.current.min, value),
                 max(self.current.max, value),
                 self.current.sum + value,
                 self.current.count + 1,
             )
         self.last_update_timestamp = time_ns()
Exemplo n.º 19
0
 def add_lazy_event(
     self,
     name: str,
     event_formatter: types.AttributesFormatter,
     timestamp: Optional[int] = None,
 ) -> None:
     self._add_event(
         LazyEvent(
             name=name,
             event_formatter=event_formatter,
             timestamp=time_ns() if timestamp is None else timestamp,
         ))
Exemplo n.º 20
0
 def start(self, start_time: Optional[int] = None) -> None:
     with self._lock:
         if not self.is_recording_events():
             return
         has_started = self.start_time is not None
         if not has_started:
             self._start_time = (start_time
                                 if start_time is not None else time_ns())
     if has_started:
         logger.warning("Calling start() on a started span.")
         return
     self.span_processor.on_start(self)
Exemplo n.º 21
0
 def add_event(
     self,
     name: str,
     timestamp: int = None,
     attributes: types.Attributes = None,
 ) -> None:
     self.add_lazy_event(
         trace_api.Event(
             name,
             time_ns() if timestamp is None else timestamp,
             Span.empty_attributes if attributes is None else attributes,
         ))
Exemplo n.º 22
0
    def start(
        self,
        start_time: Optional[int] = None,
        parent_context: Optional[context_api.Context] = None,
    ) -> None:
        with self._lock:
            if self.start_time is not None:
                logger.warning("Calling start() on a started span.")
                return
            self._start_time = (start_time
                                if start_time is not None else time_ns())

        self.span_processor.on_start(self, parent_context=parent_context)
Exemplo n.º 23
0
 def update(self, value):
     with self._lock:
         if self.current is None:
             self.current = [0 for ii in range(len(self._boundaries) + 1)]
         # greater than max value
         if value >= self._boundaries[len(self._boundaries) - 1]:
             self.current[">"] += 1
         else:
             for bb in self._boundaries:
                 # find first bucket that value is less than
                 if value < bb:
                     self.current[bb] += 1
                     break
         self.last_update_timestamp = time_ns()
    def trace_tween(request):
        if _excluded_urls.url_disabled(request.url):
            request.environ[_ENVIRON_ENABLED_KEY] = False
            # short-circuit when we don't want to trace anything
            return handler(request)

        request.environ[_ENVIRON_ENABLED_KEY] = True
        request.environ[_ENVIRON_STARTTIME_KEY] = time_ns()

        try:
            response = handler(request)
            response_or_exception = response
        except HTTPException as exc:
            # If the exception is a pyramid HTTPException,
            # that's still valuable information that isn't necessarily
            # a 500. For instance, HTTPFound is a 302.
            # As described in docs, Pyramid exceptions are all valid
            # response types
            response_or_exception = exc
            raise
        finally:
            span = request.environ.get(_ENVIRON_SPAN_KEY)
            enabled = request.environ.get(_ENVIRON_ENABLED_KEY)
            if not span and enabled:
                _logger.warning(
                    "Pyramid environ's OpenTelemetry span missing."
                    "If the OpenTelemetry tween was added manually, make sure"
                    "PyramidInstrumentor().instrument_config(config) is called"
                )
            elif enabled:
                otel_wsgi.add_response_attributes(
                    span,
                    response_or_exception.status,
                    response_or_exception.headers,
                )

                activation = request.environ.get(_ENVIRON_ACTIVATION_KEY)

                if isinstance(response_or_exception, HTTPException):
                    activation.__exit__(
                        type(response_or_exception),
                        response_or_exception,
                        getattr(response_or_exception, "__traceback__", None),
                    )
                else:
                    activation.__exit__(None, None, None)

                context.detach(request.environ.get(_ENVIRON_TOKEN))

        return response
Exemplo n.º 25
0
    def end(self, end_time: int = None) -> None:
        with self._lock:
            if not self.is_recording_events():
                return
            if self.start_time is None:
                raise RuntimeError("Calling end() on a not started span.")
            has_ended = self.end_time is not None
            if not has_ended:
                self.end_time = end_time if end_time is not None else time_ns()
        if has_ended:
            logger.warning("Calling end() on an ended span.")
            return

        self.span_processor.on_end(self)
Exemplo n.º 26
0
 def add_event(
     self,
     name: str,
     attributes: types.Attributes = None,
     timestamp: Optional[int] = None,
 ) -> None:
     if attributes is None:
         attributes = Span._empty_attributes
     self._add_event(
         Event(
             name=name,
             attributes=attributes,
             timestamp=time_ns() if timestamp is None else timestamp,
         ))
Exemplo n.º 27
0
 def add_event(
     self,
     name: str,
     attributes: types.Attributes = None,
     timestamp: Optional[int] = None,
 ) -> None:
     _filter_attribute_values(attributes)
     attributes = _create_immutable_attributes(attributes)
     self._add_event(
         Event(
             name=name,
             attributes=attributes,
             timestamp=time_ns() if timestamp is None else timestamp,
         ))
Exemplo n.º 28
0
 def add_event(
     self,
     name: str,
     attributes: types.Attributes = None,
     timestamp: Optional[int] = None,
 ) -> None:
     _filter_attribute_values(attributes)
     if not attributes:
         attributes = self._new_attributes()
     self._add_event(
         Event(
             name=name,
             attributes=attributes,
             timestamp=time_ns() if timestamp is None else timestamp,
         ))
Exemplo n.º 29
0
    def force_flush(self, timeout_millis: int = 30000) -> bool:
        """Sequentially calls force_flush on all underlying
        :class:`SpanProcessor`

        Args:
            timeout_millis: The maximum amount of time over all span processors
                to wait for spans to be exported. In case the first n span
                processors exceeded the timeout followup span processors will be
                skipped.

        Returns:
            True if all span processors flushed their spans within the
            given timeout, False otherwise.
        """
        deadline_ns = time_ns() + timeout_millis * 1000000
        for sp in self._span_processors:
            current_time_ns = time_ns()
            if current_time_ns >= deadline_ns:
                return False

            if not sp.force_flush((deadline_ns - current_time_ns) // 1000000):
                return False

        return True
Exemplo n.º 30
0
    def end(self, end_time: Optional[int] = None) -> None:
        with self._lock:
            if not self.is_recording_events():
                return
            if self.start_time is None:
                raise RuntimeError("Calling end() on a not started span.")
            has_ended = self.end_time is not None
            if not has_ended:
                self.end_time = end_time if end_time is not None else time_ns()
        if has_ended:
            logger.warning("Calling end() on an ended span.")
            return

        if self.status is None:
            self.set_status(Status(canonical_code=StatusCanonicalCode.OK))

        self.span_processor.on_end(self)