def test_requests_exception_with_response(self, *_, **__):
        with self.assertRaises(requests.RequestException):
            self.perform_request(self.URL)

        span = self.assert_span()
        self.assertEqual(
            span.attributes,
            {
                "component": "http",
                "http.method": "GET",
                "http.url": self.URL,
                "http.status_code": 500,
                "http.status_text": "Internal Server Error",
            },
        )
        self.assertEqual(span.status.canonical_code,
                         StatusCanonicalCode.INTERNAL)
        self.assertIsNotNone(RequestsInstrumentor().meter)
        self.assertEqual(len(RequestsInstrumentor().meter.metrics), 1)
        recorder = RequestsInstrumentor().meter.metrics.pop()
        match_key = get_dict_as_key({
            "http.method":
            "GET",
            "http.status_code":
            "500",
            "http.url":
            "http://httpbin.org/status/200",
        })
        for key in recorder.bound_instruments.keys():
            self.assertEqual(key, match_key)
            # pylint: disable=protected-access
            bound = recorder.bound_instruments.get(key)
            for view_data in bound.view_datas:
                self.assertEqual(view_data.labels, key)
                self.assertEqual(view_data.aggregator.current.count, 1)
    def test_requests_exception_without_proper_response_type(self, *_, **__):
        with self.assertRaises(InvalidResponseObjectException):
            self.perform_request(self.URL)

        span = self.assert_span()
        self.assertEqual(
            span.attributes,
            {"component": "http", "http.method": "GET", "http.url": self.URL},
        )
        self.assertEqual(span.status.status_code, StatusCode.ERROR)

        self.assertIsNotNone(RequestsInstrumentor().meter)
        self.assertEqual(len(RequestsInstrumentor().meter.instruments), 1)
        recorder = list(RequestsInstrumentor().meter.instruments.values())[0]
        match_key = get_dict_as_key(
            {
                "http.method": "GET",
                "http.url": "http://httpbin.org/status/200",
            }
        )
        for key in recorder.bound_instruments.keys():
            self.assertEqual(key, match_key)
            # pylint: disable=protected-access
            bound = recorder.bound_instruments.get(key)
            for view_data in bound.view_datas:
                self.assertEqual(view_data.labels, key)
                self.assertEqual(view_data.aggregator.current.count, 1)
Пример #3
0
    def test_create_timeseries(self):
        def create_label(name, value):
            label = Label()
            label.name = name
            label.value = value
            return label

        sum_aggregator = SumAggregator()
        sum_aggregator.update(5)
        sum_aggregator.take_checkpoint()
        export_record = ExportRecord(
            Counter("testname", "testdesc", "testunit", int, None),
            get_dict_as_key({"record_name": "record_value"}),
            sum_aggregator,
            Resource({"resource_name": "resource_value"}),
        )

        expected_timeseries = TimeSeries()
        expected_timeseries.labels.append(create_label("__name__", "testname"))
        expected_timeseries.labels.append(
            create_label("resource_name", "resource_value"))
        expected_timeseries.labels.append(
            create_label("record_name", "record_value"))

        sample = expected_timeseries.samples.add()
        sample.timestamp = int(sum_aggregator.last_update_timestamp / 1000000)
        sample.value = 5.0

        timeseries = self.exporter._create_timeseries(export_record,
                                                      "testname", 5.0)
        self.assertEqual(timeseries, expected_timeseries)
Пример #4
0
    def test_requests_exception_with_response(self, *_, **__):

        with self.assertRaises(HTTPError):
            self.perform_request("http://httpbin.org/status/500")

        span = self.assert_span()
        self.assertEqual(
            dict(span.attributes),
            {
                "http.method": "GET",
                "http.url": "http://httpbin.org/status/500",
                "http.status_code": 500,
                "http.status_text": "Internal Server Error",
            },
        )
        self.assertEqual(span.status.status_code, StatusCode.ERROR)
        self.assertIsNotNone(URLLibInstrumentor().meter)
        self.assertEqual(len(URLLibInstrumentor().meter.instruments), 1)
        recorder = list(URLLibInstrumentor().meter.instruments.values())[0]
        match_key = get_dict_as_key({
            "http.method": "GET",
            "http.status_code": "500",
            "http.url": "http://httpbin.org/status/500",
            "http.flavor": "1.1",
        })
        for key in recorder.bound_instruments.keys():
            self.assertEqual(key, match_key)
            # pylint: disable=protected-access
            bound = recorder.bound_instruments.get(key)
            for view_data in bound.view_datas:
                self.assertEqual(view_data.labels, key)
                self.assertEqual(view_data.aggregator.current.count, 1)
Пример #5
0
    def process(self, record) -> None:
        """Stores record information to be ready for exporting."""
        # Checkpoints the current aggregator value to be collected for export
        aggregator = record.aggregator

        # The uniqueness of a batch record is defined by a specific metric
        # using an aggregator type with a specific set of labels.
        # If two aggregators are the same but with different configs, they are still two valid unique records
        # (for example, two histogram views with different buckets)
        key = (
            record.instrument,
            aggregator.__class__,
            get_dict_as_key(aggregator.config),
            record.labels,
        )
        batch_value = self._batch_map.get(key)
        if batch_value:
            if batch_value != aggregator:
                aggregator.take_checkpoint()
                batch_value.merge(aggregator)
        else:
            aggregator.take_checkpoint()

        if self.stateful:
            # if stateful batcher, create a copy of the aggregator and update
            # it with the current checkpointed value for long-term storage
            aggregator = record.aggregator.__class__(
                config=record.aggregator.config)
            aggregator.merge(record.aggregator)
        self._batch_map[key] = aggregator
Пример #6
0
    def test_counter_to_prometheus(self):
        meter = get_meter_provider().get_meter(__name__)
        metric = meter.create_counter(
            "test@name",
            "testdesc",
            "unit",
            int,
        )
        labels = {"environment@": "staging", "os": "Windows"}
        key_labels = get_dict_as_key(labels)
        aggregator = SumAggregator()
        aggregator.update(123)
        aggregator.take_checkpoint()
        record = ExportRecord(metric, key_labels, aggregator,
                              get_meter_provider().resource)
        collector = CustomCollector("testprefix")
        collector.add_metrics_data([record])

        for prometheus_metric in collector.collect():
            self.assertEqual(type(prometheus_metric), CounterMetricFamily)
            self.assertEqual(prometheus_metric.name, "testprefix_test_name")
            self.assertEqual(prometheus_metric.documentation, "testdesc")
            self.assertTrue(len(prometheus_metric.samples) == 1)
            self.assertEqual(prometheus_metric.samples[0].value, 123)
            self.assertTrue(len(prometheus_metric.samples[0].labels) == 2)
            self.assertEqual(
                prometheus_metric.samples[0].labels["environment_"], "staging")
            self.assertEqual(prometheus_metric.samples[0].labels["os"],
                             "Windows")
Пример #7
0
 def bind(self, labels: Dict[str, str]) -> BaseBoundInstrument:
     """See `opentelemetry.metrics.Metric.bind`."""
     key = get_dict_as_key(labels)
     with self.bound_instruments_lock:
         bound_instrument = self.bound_instruments.get(key)
         if bound_instrument is None:
             bound_instrument = self.BOUND_INSTR_TYPE(key, self)
             self.bound_instruments[key] = bound_instrument
     bound_instrument.increase_ref_count()
     return bound_instrument
Пример #8
0
 def test_invalid_metric(self):
     meter = get_meter_provider().get_meter(__name__)
     metric = StubMetric("tesname", "testdesc", "unit", int, meter)
     labels = {"environment": "staging"}
     key_labels = get_dict_as_key(labels)
     record = ExportRecord(metric, key_labels, None,
                           get_meter_provider().resource)
     collector = CustomCollector("testprefix")
     collector.add_metrics_data([record])
     collector.collect()
     self.assertLogs("opentelemetry.exporter.prometheus", level="WARNING")
Пример #9
0
    def observe(self, value: metrics_api.ValueT, labels: Dict[str,
                                                              str]) -> None:
        key = get_dict_as_key(labels)
        if not self._validate_observe(value, key):
            return

        if key not in self.aggregators:
            # TODO: how to cleanup aggregators?
            self.aggregators[key] = get_default_aggregator(self)()
        aggregator = self.aggregators[key]
        aggregator.update(value)
    def test_valid_export(self, mock_post):
        mock_post.return_value.configure_mock(**{"status_code": 200})
        test_metric = Counter("testname", "testdesc", "testunit", int, None)
        labels = get_dict_as_key({"environment": "testing"})
        record = ExportRecord(test_metric, labels, SumAggregator(),
                              Resource({}))
        result = self.exporter.export([record])
        self.assertIs(result, MetricsExportResult.SUCCESS)
        self.assertEqual(mock_post.call_count, 1)

        result = self.exporter.export([])
        self.assertIs(result, MetricsExportResult.SUCCESS)
    def setUp(self):
        set_meter_provider(metrics.MeterProvider())
        self._meter = get_meter_provider().get_meter(__name__)
        self._test_metric = self._meter.create_counter(
            "testname", "testdesc", "unit", int,
        )
        labels = {"environment": "staging"}
        self._labels_key = get_dict_as_key(labels)

        self._mock_registry_register = mock.Mock()
        self._registry_register_patch = mock.patch(
            "prometheus_client.core.REGISTRY.register",
            side_effect=self._mock_registry_register,
        )
Пример #12
0
    def test_error(self):
        with self.assertRaises(ValueError):
            Client().get("/error/")

        spans = self.memory_exporter.get_finished_spans()
        self.assertEqual(len(spans), 1)

        span = spans[0]

        self.assertEqual(
            span.name, "^error/" if DJANGO_2_2 else "tests.views.error"
        )
        self.assertEqual(span.kind, SpanKind.SERVER)
        self.assertEqual(
            span.status.canonical_code, StatusCanonicalCode.INTERNAL
        )
        self.assertEqual(span.attributes["http.method"], "GET")
        self.assertEqual(
            span.attributes["http.url"], "http://testserver/error/"
        )
        self.assertEqual(span.attributes["http.route"], "^error/")
        self.assertEqual(span.attributes["http.scheme"], "http")
        self.assertEqual(span.attributes["http.status_code"], 500)
        self.assertIsNotNone(_django_instrumentor.meter)
        self.assertEqual(len(_django_instrumentor.meter.metrics), 1)

        self.assertEqual(len(span.events), 1)
        event = span.events[0]
        self.assertEqual(event.name, "exception")
        self.assertEqual(event.attributes["exception.type"], "ValueError")
        self.assertEqual(event.attributes["exception.message"], "error")

        recorder = _django_instrumentor.meter.metrics.pop()
        match_key = get_dict_as_key(
            {
                "http.flavor": "1.1",
                "http.method": "GET",
                "http.status_code": "500",
                "http.url": "http://testserver/error/",
            }
        )
        for key in recorder.bound_instruments.keys():
            self.assertEqual(key, match_key)
            # pylint: disable=protected-access
            bound = recorder.bound_instruments.get(key)
            for view_data in bound.view_datas:
                self.assertEqual(view_data.labels, key)
                self.assertEqual(view_data.aggregator.current.count, 1)
    def test_basic(self):
        result = self.perform_request(self.URL)
        self.assertEqual(result.text, "Hello!")
        span = self.assert_span()

        self.assertIs(span.kind, trace.SpanKind.CLIENT)
        self.assertEqual(span.name, "HTTP GET")

        self.assertEqual(
            span.attributes,
            {
                "component": "http",
                "http.method": "GET",
                "http.url": self.URL,
                "http.status_code": 200,
                "http.status_text": "OK",
            },
        )

        self.assertIs(span.status.canonical_code,
                      trace.status.StatusCanonicalCode.OK)

        self.check_span_instrumentation_info(
            span, opentelemetry.instrumentation.requests)

        self.assertIsNotNone(RequestsInstrumentor().meter)
        self.assertEqual(len(RequestsInstrumentor().meter.metrics), 1)
        recorder = RequestsInstrumentor().meter.metrics.pop()
        match_key = get_dict_as_key({
            "http.flavor":
            "1.1",
            "http.method":
            "GET",
            "http.status_code":
            "200",
            "http.status_text":
            "OK",
            "http.url":
            "http://httpbin.org/status/200",
        })
        for key in recorder.bound_instruments.keys():
            self.assertEqual(key, match_key)
            # pylint: disable=protected-access
            bound = recorder.bound_instruments.get(key)
            for view_data in bound.view_datas:
                self.assertEqual(view_data.labels, key)
                self.assertEqual(view_data.aggregator.current.count, 1)
                self.assertGreater(view_data.aggregator.current.sum, 0)
 def test_record_server_duration(self):
     meter = metrics_api.get_meter(__name__)
     recorder = HTTPMetricRecorder(meter, HTTPMetricType.SERVER)
     labels = {"test": "asd"}
     with mock.patch("time.time") as time_patch:
         time_patch.return_value = 5.0
         with recorder.record_server_duration(labels):
             labels["test2"] = "asd2"
     match_key = get_dict_as_key({"test": "asd", "test2": "asd2"})
     for key in recorder._server_duration.bound_instruments.keys():
         self.assertEqual(key, match_key)
         # pylint: disable=protected-access
         bound = recorder._server_duration.bound_instruments.get(key)
         for view_data in bound.view_datas:
             self.assertEqual(view_data.labels, key)
             self.assertEqual(view_data.aggregator.current.count, 1)
             self.assertGreaterEqual(view_data.aggregator.current.sum, 0)
Пример #15
0
 def test_min_max_sum_aggregator_to_prometheus(self):
     meter = get_meter_provider().get_meter(__name__)
     metric = meter.create_metric("test@name", "testdesc", "unit", int,
                                  metrics.ValueRecorder, [])
     labels = {}
     key_labels = get_dict_as_key(labels)
     aggregator = MinMaxSumCountAggregator()
     aggregator.update(123)
     aggregator.update(456)
     aggregator.take_checkpoint()
     record = MetricRecord(metric, key_labels, aggregator)
     collector = CustomCollector("testprefix")
     collector.add_metrics_data([record])
     result_bytes = generate_latest(collector)
     result = result_bytes.decode("utf-8")
     self.assertIn("testprefix_test_name_count 2.0", result)
     self.assertIn("testprefix_test_name_sum 579.0", result)
Пример #16
0
    def _get_system_network_connections(
        self, observer: metrics.UpDownSumObserver
    ) -> None:
        """Observer callback for network connections

        Args:
            observer: the observer to update
        """
        # TODO How to find the device identifier for a particular
        # connection?

        connection_counters = {}

        for net_connection in psutil.net_connections():
            for metric in self._config["system.network.connections"]:
                self._system_network_connections_labels["protocol"] = {
                    1: "tcp",
                    2: "udp",
                }[net_connection.type.value]
                self._system_network_connections_labels[
                    "state"
                ] = net_connection.status
                self._system_network_connections_labels[metric] = getattr(
                    net_connection, metric
                )

            connection_counters_key = get_dict_as_key(
                self._system_network_connections_labels
            )

            if connection_counters_key in connection_counters.keys():
                connection_counters[connection_counters_key]["counter"] += 1
            else:
                connection_counters[connection_counters_key] = {
                    "counter": 1,
                    "labels": self._system_network_connections_labels.copy(),
                }

        for connection_counter in connection_counters.values():
            observer.observe(
                connection_counter["counter"], connection_counter["labels"],
            )
Пример #17
0
    def test_traced_get(self):
        Client().get("/traced/")

        spans = self.memory_exporter.get_finished_spans()
        self.assertEqual(len(spans), 1)

        span = spans[0]

        self.assertEqual(
            span.name, "^traced/" if DJANGO_2_2 else "tests.views.traced"
        )
        self.assertEqual(span.kind, SpanKind.SERVER)
        self.assertEqual(span.status.canonical_code, StatusCanonicalCode.OK)
        self.assertEqual(span.attributes["http.method"], "GET")
        self.assertEqual(
            span.attributes["http.url"], "http://testserver/traced/"
        )
        self.assertEqual(span.attributes["http.route"], "^traced/")
        self.assertEqual(span.attributes["http.scheme"], "http")
        self.assertEqual(span.attributes["http.status_code"], 200)
        self.assertEqual(span.attributes["http.status_text"], "OK")

        self.assertIsNotNone(_django_instrumentor.meter)
        self.assertEqual(len(_django_instrumentor.meter.metrics), 1)
        recorder = _django_instrumentor.meter.metrics.pop()
        match_key = get_dict_as_key(
            {
                "http.flavor": "1.1",
                "http.method": "GET",
                "http.status_code": "200",
                "http.url": "http://testserver/traced/",
            }
        )
        for key in recorder.bound_instruments.keys():
            self.assertEqual(key, match_key)
            # pylint: disable=protected-access
            bound = recorder.bound_instruments.get(key)
            for view_data in bound.view_datas:
                self.assertEqual(view_data.labels, key)
                self.assertEqual(view_data.aggregator.current.count, 1)
                self.assertGreaterEqual(view_data.aggregator.current.sum, 0)
Пример #18
0
    def _get_system_network_connections(
        self, options: CallbackOptions
    ) -> Iterable[Observation]:
        """Observer callback for network connections"""
        # TODO How to find the device identifier for a particular
        # connection?

        connection_counters = {}

        for net_connection in psutil.net_connections():
            for metric in self._config["system.network.connections"]:
                self._system_network_connections_labels["protocol"] = {
                    1: "tcp",
                    2: "udp",
                }[net_connection.type.value]
                self._system_network_connections_labels[
                    "state"
                ] = net_connection.status
                self._system_network_connections_labels[metric] = getattr(
                    net_connection, metric
                )

            connection_counters_key = get_dict_as_key(
                self._system_network_connections_labels
            )

            if connection_counters_key in connection_counters:
                connection_counters[connection_counters_key]["counter"] += 1
            else:
                connection_counters[connection_counters_key] = {
                    "counter": 1,
                    "labels": self._system_network_connections_labels.copy(),
                }

        for connection_counter in connection_counters.values():
            yield Observation(
                connection_counter["counter"],
                connection_counter["labels"],
            )