Change metrics test to work with base_test.py (#1688)

This commit is contained in:
Shalev Roda
2023-02-25 00:05:45 +02:00
committed by GitHub
parent a50caf26bc
commit a7bd56354b
5 changed files with 358 additions and 393 deletions

View File

@ -6,7 +6,7 @@ on:
- 'release/*'
pull_request:
env:
CORE_REPO_SHA: d0bb12b34b0c487198c935001636b6163485a50f
CORE_REPO_SHA: 2d1f0b9f5fce62549d1338882f37b91b95881c75
jobs:
build:

View File

@ -15,97 +15,23 @@
from timeit import default_timer
from tornado.testing import AsyncHTTPTestCase
from opentelemetry import trace
from opentelemetry.instrumentation.tornado import TornadoInstrumentor
from opentelemetry.sdk.metrics.export import (
HistogramDataPoint,
NumberDataPoint,
from opentelemetry.sdk.metrics.export import HistogramDataPoint
from .test_instrumentation import ( # pylint: disable=no-name-in-module,import-error
TornadoTest,
)
from opentelemetry.test.test_base import TestBase
from .tornado_test_app import make_app
class TornadoTest(AsyncHTTPTestCase, TestBase):
# pylint:disable=no-self-use
def get_app(self):
tracer = trace.get_tracer(__name__)
app = make_app(tracer)
return app
def get_sorted_metrics(self):
resource_metrics = (
self.memory_metrics_reader.get_metrics_data().resource_metrics
)
for metrics in resource_metrics:
for scope_metrics in metrics.scope_metrics:
all_metrics = list(scope_metrics.metrics)
return self.sorted_metrics(all_metrics)
@staticmethod
def sorted_metrics(metrics):
"""
Sorts metrics by metric name.
"""
return sorted(
metrics,
key=lambda m: m.name,
)
def assert_metric_expected(
self, metric, expected_value, expected_attributes
):
data_point = next(iter(metric.data.data_points))
if isinstance(data_point, HistogramDataPoint):
self.assertEqual(
data_point.sum,
expected_value,
)
elif isinstance(data_point, NumberDataPoint):
self.assertEqual(
data_point.value,
expected_value,
class TestTornadoMetricsInstrumentation(TornadoTest):
# Return Sequence with one histogram
def create_histogram_data_points(self, sum_data_point, attributes):
return [
self.create_histogram_data_point(
sum_data_point, 1, sum_data_point, sum_data_point, attributes
)
]
self.assertDictEqual(
expected_attributes,
dict(data_point.attributes),
)
def assert_duration_metric_expected(
self, metric, duration_estimated, expected_attributes
):
data_point = next(iter(metric.data.data_points))
self.assertAlmostEqual(
data_point.sum,
duration_estimated,
delta=200,
)
self.assertDictEqual(
expected_attributes,
dict(data_point.attributes),
)
def setUp(self):
super().setUp()
TornadoInstrumentor().instrument(
server_request_hook=getattr(self, "server_request_hook", None),
client_request_hook=getattr(self, "client_request_hook", None),
client_response_hook=getattr(self, "client_response_hook", None),
meter_provider=self.meter_provider,
)
def tearDown(self):
TornadoInstrumentor().uninstrument()
super().tearDown()
class TestTornadoInstrumentor(TornadoTest):
def test_basic_metrics(self):
start_time = default_timer()
response = self.fetch("/")
@ -132,42 +58,51 @@ class TestTornadoInstrumentor(TornadoTest):
)
self.assert_metric_expected(
server_active_request,
0,
{
"http.method": "GET",
"http.flavor": "HTTP/1.1",
"http.scheme": "http",
"http.target": "/",
"http.host": response.request.headers["host"],
},
[
self.create_number_data_point(
0,
attributes={
"http.method": "GET",
"http.flavor": "HTTP/1.1",
"http.scheme": "http",
"http.target": "/",
"http.host": response.request.headers["host"],
},
),
],
)
self.assertEqual(server_duration.name, "http.server.duration")
self.assert_duration_metric_expected(
self.assert_metric_expected(
server_duration,
client_duration_estimated,
{
"http.status_code": response.code,
"http.method": "GET",
"http.flavor": "HTTP/1.1",
"http.scheme": "http",
"http.target": "/",
"http.host": response.request.headers["host"],
},
self.create_histogram_data_points(
client_duration_estimated,
attributes={
"http.method": "GET",
"http.flavor": "HTTP/1.1",
"http.scheme": "http",
"http.target": "/",
"http.host": response.request.headers["host"],
"http.status_code": response.code,
},
),
est_value_delta=200,
)
self.assertEqual(server_request_size.name, "http.server.request.size")
self.assert_metric_expected(
server_request_size,
0,
{
"http.status_code": 200,
"http.method": "GET",
"http.flavor": "HTTP/1.1",
"http.scheme": "http",
"http.target": "/",
"http.host": response.request.headers["host"],
},
self.create_histogram_data_points(
0,
attributes={
"http.status_code": 200,
"http.method": "GET",
"http.flavor": "HTTP/1.1",
"http.scheme": "http",
"http.target": "/",
"http.host": response.request.headers["host"],
},
),
)
self.assertEqual(
@ -175,37 +110,44 @@ class TestTornadoInstrumentor(TornadoTest):
)
self.assert_metric_expected(
server_response_size,
len(response.body),
{
"http.status_code": response.code,
"http.method": "GET",
"http.flavor": "HTTP/1.1",
"http.scheme": "http",
"http.target": "/",
"http.host": response.request.headers["host"],
},
self.create_histogram_data_points(
len(response.body),
attributes={
"http.status_code": response.code,
"http.method": "GET",
"http.flavor": "HTTP/1.1",
"http.scheme": "http",
"http.target": "/",
"http.host": response.request.headers["host"],
},
),
)
self.assertEqual(client_duration.name, "http.client.duration")
self.assert_duration_metric_expected(
self.assert_metric_expected(
client_duration,
client_duration_estimated,
{
"http.status_code": response.code,
"http.method": "GET",
"http.url": response.effective_url,
},
self.create_histogram_data_points(
client_duration_estimated,
attributes={
"http.status_code": response.code,
"http.method": "GET",
"http.url": response.effective_url,
},
),
est_value_delta=200,
)
self.assertEqual(client_request_size.name, "http.client.request.size")
self.assert_metric_expected(
client_request_size,
0,
{
"http.status_code": response.code,
"http.method": "GET",
"http.url": response.effective_url,
},
self.create_histogram_data_points(
0,
attributes={
"http.status_code": response.code,
"http.method": "GET",
"http.url": response.effective_url,
},
),
)
self.assertEqual(
@ -213,12 +155,14 @@ class TestTornadoInstrumentor(TornadoTest):
)
self.assert_metric_expected(
client_response_size,
len(response.body),
{
"http.status_code": response.code,
"http.method": "GET",
"http.url": response.effective_url,
},
self.create_histogram_data_points(
len(response.body),
attributes={
"http.status_code": response.code,
"http.method": "GET",
"http.url": response.effective_url,
},
),
)
def test_metric_uninstrument(self):
@ -226,10 +170,10 @@ class TestTornadoInstrumentor(TornadoTest):
TornadoInstrumentor().uninstrument()
self.fetch("/")
metrics_list = self.memory_metrics_reader.get_metrics_data()
for resource_metric in metrics_list.resource_metrics:
for scope_metric in resource_metric.scope_metrics:
for metric in scope_metric.metrics:
for point in list(metric.data.data_points):
if isinstance(point, HistogramDataPoint):
self.assertEqual(point.count, 1)
metrics = self.get_sorted_metrics()
self.assertEqual(len(metrics), 7)
for metric in metrics:
for point in list(metric.data.data_points):
if isinstance(point, HistogramDataPoint):
self.assertEqual(point.count, 1)

View File

@ -14,7 +14,6 @@
from timeit import default_timer
from typing import Optional, Union
from urllib import request
from urllib.parse import urlencode
@ -23,16 +22,11 @@ import httpretty
from opentelemetry.instrumentation.urllib import ( # pylint: disable=no-name-in-module,import-error
URLLibInstrumentor,
)
from opentelemetry.sdk.metrics._internal.point import Metric
from opentelemetry.sdk.metrics.export import (
HistogramDataPoint,
NumberDataPoint,
)
from opentelemetry.semconv.metrics import MetricInstruments
from opentelemetry.test.test_base import TestBase
class TestRequestsIntegration(TestBase):
class TestUrllibMetricsInstrumentation(TestBase):
URL = "http://httpbin.org/status/200"
URL_POST = "http://httpbin.org/post"
@ -50,63 +44,13 @@ class TestRequestsIntegration(TestBase):
URLLibInstrumentor().uninstrument()
httpretty.disable()
def get_sorted_metrics(self):
resource_metrics = (
self.memory_metrics_reader.get_metrics_data().resource_metrics
)
all_metrics = []
for metrics in resource_metrics:
for scope_metrics in metrics.scope_metrics:
all_metrics.extend(scope_metrics.metrics)
return self.sorted_metrics(all_metrics)
@staticmethod
def sorted_metrics(metrics):
"""
Sorts metrics by metric name.
"""
return sorted(
metrics,
key=lambda m: m.name,
)
def assert_metric_expected(
self,
metric: Metric,
expected_value: Union[int, float],
expected_attributes: dict,
est_delta: Optional[float] = None,
):
data_point = next(iter(metric.data.data_points))
if isinstance(data_point, HistogramDataPoint):
self.assertEqual(
data_point.count,
1,
# Return Sequence with one histogram
def create_histogram_data_points(self, sum_data_point, attributes):
return [
self.create_histogram_data_point(
sum_data_point, 1, sum_data_point, sum_data_point, attributes
)
if est_delta is None:
self.assertEqual(
data_point.sum,
expected_value,
)
else:
self.assertAlmostEqual(
data_point.sum,
expected_value,
delta=est_delta,
)
elif isinstance(data_point, NumberDataPoint):
self.assertEqual(
data_point.value,
expected_value,
)
self.assertDictEqual(
expected_attributes,
dict(data_point.attributes),
)
]
def test_basic_metric(self):
start_time = default_timer()
@ -127,31 +71,33 @@ class TestRequestsIntegration(TestBase):
)
self.assert_metric_expected(
client_duration,
client_duration_estimated,
{
"http.status_code": str(result.code),
"http.method": "GET",
"http.url": str(result.url),
"http.flavor": "1.1",
},
est_delta=200,
self.create_histogram_data_points(
client_duration_estimated,
attributes={
"http.status_code": str(result.code),
"http.method": "GET",
"http.url": str(result.url),
"http.flavor": "1.1",
},
),
est_value_delta=200,
)
# net.peer.name
self.assertEqual(
client_request_size.name,
MetricInstruments.HTTP_CLIENT_REQUEST_SIZE,
)
self.assert_metric_expected(
client_request_size,
0,
{
"http.status_code": str(result.code),
"http.method": "GET",
"http.url": str(result.url),
"http.flavor": "1.1",
},
self.create_histogram_data_points(
0,
attributes={
"http.status_code": str(result.code),
"http.method": "GET",
"http.url": str(result.url),
"http.flavor": "1.1",
},
),
)
self.assertEqual(
@ -160,13 +106,15 @@ class TestRequestsIntegration(TestBase):
)
self.assert_metric_expected(
client_response_size,
result.length,
{
"http.status_code": str(result.code),
"http.method": "GET",
"http.url": str(result.url),
"http.flavor": "1.1",
},
self.create_histogram_data_points(
result.length,
attributes={
"http.status_code": str(result.code),
"http.method": "GET",
"http.url": str(result.url),
"http.flavor": "1.1",
},
),
)
def test_basic_metric_request_not_empty(self):
@ -191,14 +139,16 @@ class TestRequestsIntegration(TestBase):
)
self.assert_metric_expected(
client_duration,
client_duration_estimated,
{
"http.status_code": str(result.code),
"http.method": "POST",
"http.url": str(result.url),
"http.flavor": "1.1",
},
est_delta=200,
self.create_histogram_data_points(
client_duration_estimated,
attributes={
"http.status_code": str(result.code),
"http.method": "POST",
"http.url": str(result.url),
"http.flavor": "1.1",
},
),
est_value_delta=200,
)
self.assertEqual(
@ -207,13 +157,15 @@ class TestRequestsIntegration(TestBase):
)
self.assert_metric_expected(
client_request_size,
len(data_encoded),
{
"http.status_code": str(result.code),
"http.method": "POST",
"http.url": str(result.url),
"http.flavor": "1.1",
},
self.create_histogram_data_points(
len(data_encoded),
attributes={
"http.status_code": str(result.code),
"http.method": "POST",
"http.url": str(result.url),
"http.flavor": "1.1",
},
),
)
self.assertEqual(
@ -222,13 +174,15 @@ class TestRequestsIntegration(TestBase):
)
self.assert_metric_expected(
client_response_size,
result.length,
{
"http.status_code": str(result.code),
"http.method": "POST",
"http.url": str(result.url),
"http.flavor": "1.1",
},
self.create_histogram_data_points(
result.length,
attributes={
"http.status_code": str(result.code),
"http.method": "POST",
"http.url": str(result.url),
"http.flavor": "1.1",
},
),
)
def test_metric_uninstrument(self):

View File

@ -12,11 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from timeit import default_timer
import urllib3
import urllib3.exceptions
from urllib3.request import encode_multipart_formdata
from opentelemetry import trace
from opentelemetry.instrumentation.urllib3 import URLLib3Instrumentor
@ -87,136 +84,3 @@ class TestURLLib3InstrumentorWithRealSocket(HttpTestBase, TestBase):
"net.peer.ip": self.assert_ip,
}
self.assertGreaterEqual(span.attributes.items(), attributes.items())
class TestURLLib3InstrumentorMetric(HttpTestBase, TestBase):
def setUp(self):
super().setUp()
self.assert_ip = self.server.server_address[0]
self.assert_port = self.server.server_address[1]
self.http_host = ":".join(map(str, self.server.server_address[:2]))
self.http_url_base = "http://" + self.http_host
self.http_url = self.http_url_base + "/status/200"
URLLib3Instrumentor().instrument(meter_provider=self.meter_provider)
def tearDown(self):
super().tearDown()
URLLib3Instrumentor().uninstrument()
def test_metric_uninstrument(self):
with urllib3.PoolManager() as pool:
pool.request("GET", self.http_url)
URLLib3Instrumentor().uninstrument()
pool.request("GET", self.http_url)
metrics_list = self.memory_metrics_reader.get_metrics_data()
for resource_metric in metrics_list.resource_metrics:
for scope_metric in resource_metric.scope_metrics:
for metric in scope_metric.metrics:
for point in list(metric.data.data_points):
self.assertEqual(point.count, 1)
def test_basic_metric_check_client_size_get(self):
with urllib3.PoolManager() as pool:
start_time = default_timer()
response = pool.request("GET", self.http_url)
client_duration_estimated = (default_timer() - start_time) * 1000
expected_attributes = {
"http.status_code": 200,
"http.host": self.assert_ip,
"http.method": "GET",
"http.flavor": "1.1",
"http.scheme": "http",
"net.peer.name": self.assert_ip,
"net.peer.port": self.assert_port,
}
expected_data = {
"http.client.request.size": 0,
"http.client.response.size": len(response.data),
}
expected_metrics = [
"http.client.duration",
"http.client.request.size",
"http.client.response.size",
]
resource_metrics = (
self.memory_metrics_reader.get_metrics_data().resource_metrics
)
for metrics in resource_metrics:
for scope_metrics in metrics.scope_metrics:
self.assertEqual(len(scope_metrics.metrics), 3)
for metric in scope_metrics.metrics:
for data_point in metric.data.data_points:
if metric.name in expected_data:
self.assertEqual(
data_point.sum, expected_data[metric.name]
)
if metric.name == "http.client.duration":
self.assertAlmostEqual(
data_point.sum,
client_duration_estimated,
delta=1000,
)
self.assertIn(metric.name, expected_metrics)
self.assertDictEqual(
expected_attributes,
dict(data_point.attributes),
)
self.assertEqual(data_point.count, 1)
def test_basic_metric_check_client_size_post(self):
with urllib3.PoolManager() as pool:
start_time = default_timer()
data_fields = {"data": "test"}
response = pool.request("POST", self.http_url, fields=data_fields)
client_duration_estimated = (default_timer() - start_time) * 1000
expected_attributes = {
"http.status_code": 501,
"http.host": self.assert_ip,
"http.method": "POST",
"http.flavor": "1.1",
"http.scheme": "http",
"net.peer.name": self.assert_ip,
"net.peer.port": self.assert_port,
}
body = encode_multipart_formdata(data_fields)[0]
expected_data = {
"http.client.request.size": len(body),
"http.client.response.size": len(response.data),
}
expected_metrics = [
"http.client.duration",
"http.client.request.size",
"http.client.response.size",
]
resource_metrics = (
self.memory_metrics_reader.get_metrics_data().resource_metrics
)
for metrics in resource_metrics:
for scope_metrics in metrics.scope_metrics:
self.assertEqual(len(scope_metrics.metrics), 3)
for metric in scope_metrics.metrics:
for data_point in metric.data.data_points:
if metric.name in expected_data:
self.assertEqual(
data_point.sum, expected_data[metric.name]
)
if metric.name == "http.client.duration":
self.assertAlmostEqual(
data_point.sum,
client_duration_estimated,
delta=1000,
)
self.assertIn(metric.name, expected_metrics)
self.assertDictEqual(
expected_attributes,
dict(data_point.attributes),
)
self.assertEqual(data_point.count, 1)

View File

@ -0,0 +1,203 @@
# Copyright The OpenTelemetry Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from timeit import default_timer
import urllib3
import urllib3.exceptions
from urllib3.request import encode_multipart_formdata
from opentelemetry.instrumentation.urllib3 import URLLib3Instrumentor
from opentelemetry.test.httptest import HttpTestBase
from opentelemetry.test.test_base import TestBase
class TestUrllib3MetricsInstrumentation(HttpTestBase, TestBase):
def setUp(self):
super().setUp()
self.assert_ip = self.server.server_address[0]
self.assert_port = self.server.server_address[1]
self.http_host = ":".join(map(str, self.server.server_address[:2]))
self.http_url_base = "http://" + self.http_host
self.http_url = self.http_url_base + "/status/200"
URLLib3Instrumentor().instrument(meter_provider=self.meter_provider)
def tearDown(self):
super().tearDown()
URLLib3Instrumentor().uninstrument()
# Return Sequence with one histogram
def create_histogram_data_points(self, sum_data_point, attributes):
return [
self.create_histogram_data_point(
sum_data_point, 1, sum_data_point, sum_data_point, attributes
)
]
def test_basic_metric_check_client_size_get(self):
with urllib3.PoolManager() as pool:
start_time = default_timer()
response = pool.request("GET", self.http_url)
client_duration_estimated = (default_timer() - start_time) * 1000
metrics = self.get_sorted_metrics()
(
client_duration,
client_request_size,
client_response_size,
) = metrics
self.assertEqual(client_duration.name, "http.client.duration")
self.assert_metric_expected(
client_duration,
self.create_histogram_data_points(
client_duration_estimated,
attributes={
"http.status_code": 200,
"http.host": self.assert_ip,
"http.method": "GET",
"http.flavor": "1.1",
"http.scheme": "http",
"net.peer.name": self.assert_ip,
"net.peer.port": self.assert_port,
},
),
est_value_delta=200,
)
self.assertEqual(
client_request_size.name, "http.client.request.size"
)
self.assert_metric_expected(
client_request_size,
self.create_histogram_data_points(
0,
attributes={
"http.status_code": 200,
"http.host": self.assert_ip,
"http.method": "GET",
"http.flavor": "1.1",
"http.scheme": "http",
"net.peer.name": self.assert_ip,
"net.peer.port": self.assert_port,
},
),
)
self.assertEqual(
client_response_size.name, "http.client.response.size"
)
self.assert_metric_expected(
client_response_size,
self.create_histogram_data_points(
len(response.data),
attributes={
"http.status_code": 200,
"http.host": self.assert_ip,
"http.method": "GET",
"http.flavor": "1.1",
"http.scheme": "http",
"net.peer.name": self.assert_ip,
"net.peer.port": self.assert_port,
},
),
)
def test_basic_metric_check_client_size_post(self):
with urllib3.PoolManager() as pool:
start_time = default_timer()
data_fields = {"data": "test"}
response = pool.request("POST", self.http_url, fields=data_fields)
client_duration_estimated = (default_timer() - start_time) * 1000
body = encode_multipart_formdata(data_fields)[0]
metrics = self.get_sorted_metrics()
(
client_duration,
client_request_size,
client_response_size,
) = metrics
self.assertEqual(client_duration.name, "http.client.duration")
self.assert_metric_expected(
client_duration,
self.create_histogram_data_points(
client_duration_estimated,
attributes={
"http.status_code": 501,
"http.host": self.assert_ip,
"http.method": "POST",
"http.flavor": "1.1",
"http.scheme": "http",
"net.peer.name": self.assert_ip,
"net.peer.port": self.assert_port,
},
),
est_value_delta=200,
)
self.assertEqual(
client_request_size.name, "http.client.request.size"
)
client_request_size_expected = len(body)
self.assert_metric_expected(
client_request_size,
self.create_histogram_data_points(
client_request_size_expected,
attributes={
"http.status_code": 501,
"http.host": self.assert_ip,
"http.method": "POST",
"http.flavor": "1.1",
"http.scheme": "http",
"net.peer.name": self.assert_ip,
"net.peer.port": self.assert_port,
},
),
)
self.assertEqual(
client_response_size.name, "http.client.response.size"
)
client_response_size_expected = len(response.data)
self.assert_metric_expected(
client_response_size,
self.create_histogram_data_points(
client_response_size_expected,
attributes={
"http.status_code": 501,
"http.host": self.assert_ip,
"http.method": "POST",
"http.flavor": "1.1",
"http.scheme": "http",
"net.peer.name": self.assert_ip,
"net.peer.port": self.assert_port,
},
),
)
def test_metric_uninstrument(self):
with urllib3.PoolManager() as pool:
pool.request("GET", self.http_url)
URLLib3Instrumentor().uninstrument()
pool.request("GET", self.http_url)
metrics = self.get_sorted_metrics()
self.assertEqual(len(metrics), 3)
for metric in metrics:
for point in list(metric.data.data_points):
self.assertEqual(point.count, 1)