def test_valid_basic_auth_param(self): exporter = PrometheusRemoteWriteMetricsExporter( endpoint="/prom/test_endpoint", basic_auth={ "username": "******", "password": "******", }, ) self.assertEqual(exporter.basic_auth["username"], "test_username") self.assertEqual(exporter.basic_auth["password"], "test_password")
def test_invalid_conflicting_passwords_param(self): with self.assertRaises(ValueError): PrometheusRemoteWriteMetricsExporter( endpoint="/prom/test_endpoint", basic_auth={ "username": "******", "password": "******", "password_file": "test_file", }, )
def setUp(self): super().setUp self.exporter = PrometheusRemoteWriteMetricsExporter( endpoint="http://localhost:9009/api/prom/push", headers={"X-Scope-Org-ID": "5"}, ) self.labels = {"environment": "testing"} self.meter = self.meter_provider.get_meter(__name__) metrics.get_meter_provider().start_pipeline( self.meter, self.exporter, 1, )
class TestExport(unittest.TestCase): # Initializes test data that is reused across tests def setUp(self): self.exporter = PrometheusRemoteWriteMetricsExporter( endpoint="/prom/test_endpoint") # Ensures export is successful with valid export_records and config @patch("requests.post") 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 test_invalid_export(self): record = ExportRecord(None, None, None, None) result = self.exporter.export([record]) self.assertIs(result, MetricsExportResult.FAILURE) @patch("requests.post") def test_valid_send_message(self, mock_post): mock_post.return_value.configure_mock(**{"ok": True}) result = self.exporter._send_message(bytes(), {}) self.assertEqual(mock_post.call_count, 1) self.assertEqual(result, MetricsExportResult.SUCCESS) def test_invalid_send_message(self): result = self.exporter._send_message(bytes(), {}) self.assertEqual(result, MetricsExportResult.FAILURE) # Verifies that build_message calls snappy.compress and returns SerializedString @patch("snappy.compress", return_value=bytes()) def test_build_message(self, mock_compress): message = self.exporter._build_message([TimeSeries()]) self.assertEqual(mock_compress.call_count, 1) self.assertIsInstance(message, bytes) # Ensure correct headers are added when valid config is provided def test_build_headers(self): self.exporter.headers = {"Custom Header": "test_header"} headers = self.exporter._build_headers() self.assertEqual(headers["Content-Encoding"], "snappy") self.assertEqual(headers["Content-Type"], "application/x-protobuf") self.assertEqual(headers["X-Prometheus-Remote-Write-Version"], "0.1.0") self.assertEqual(headers["Custom Header"], "test_header")
def test_valid_tls_config_param(self): tls_config = { "ca_file": "test_ca_file", "cert_file": "test_cert_file", "key_file": "test_key_file", "insecure_skip_verify": True, } exporter = PrometheusRemoteWriteMetricsExporter( endpoint="/prom/test_endpoint", tls_config=tls_config) self.assertEqual(exporter.tls_config["ca_file"], tls_config["ca_file"]) self.assertEqual(exporter.tls_config["cert_file"], tls_config["cert_file"]) self.assertEqual(exporter.tls_config["key_file"], tls_config["key_file"]) self.assertEqual( exporter.tls_config["insecure_skip_verify"], tls_config["insecure_skip_verify"], )
def test_invalid_timeout_param(self): with self.assertRaises(ValueError): PrometheusRemoteWriteMetricsExporter( endpoint="/prom/test_endpoint", timeout=0)
def test_invalid_no_password_param(self): with self.assertRaises(ValueError): PrometheusRemoteWriteMetricsExporter( endpoint="/prom/test_endpoint", basic_auth={"username": "******"}, )
def test_invalid_no_endpoint_param(self): with self.assertRaises(ValueError): PrometheusRemoteWriteMetricsExporter("")
def test_valid_standard_param(self): exporter = PrometheusRemoteWriteMetricsExporter( endpoint="/prom/test_endpoint", ) self.assertEqual(exporter.endpoint, "/prom/test_endpoint")
def setUp(self): self.exporter = PrometheusRemoteWriteMetricsExporter( endpoint="/prom/test_endpoint")
class TestConversion(unittest.TestCase): # Initializes test data that is reused across tests def setUp(self): self.exporter = PrometheusRemoteWriteMetricsExporter( endpoint="/prom/test_endpoint") # Ensures conversion to timeseries function works with valid aggregation types def test_valid_convert_to_timeseries(self): test_records = [ ExportRecord( Counter("testname", "testdesc", "testunit", int, None), None, SumAggregator(), Resource({}), ), ExportRecord( Counter("testname", "testdesc", "testunit", int, None), None, MinMaxSumCountAggregator(), Resource({}), ), ExportRecord( Counter("testname", "testdesc", "testunit", int, None), None, HistogramAggregator(), Resource({}), ), ExportRecord( Counter("testname", "testdesc", "testunit", int, None), None, LastValueAggregator(), Resource({}), ), ExportRecord( Counter("testname", "testdesc", "testunit", int, None), None, ValueObserverAggregator(), Resource({}), ), ] for record in test_records: record.aggregator.update(5) record.aggregator.take_checkpoint() data = self.exporter._convert_to_timeseries(test_records) self.assertIsInstance(data, list) self.assertEqual(len(data), 13) for timeseries in data: self.assertIsInstance(timeseries, TimeSeries) # Ensures conversion to timeseries fails for unsupported aggregation types def test_invalid_convert_to_timeseries(self): data = self.exporter._convert_to_timeseries( [ExportRecord(None, None, None, Resource({}))]) self.assertIsInstance(data, list) self.assertEqual(len(data), 0) # Ensures sum aggregator is correctly converted to timeseries def test_convert_from_sum(self): sum_record = ExportRecord( Counter("testname", "testdesc", "testunit", int, None), None, SumAggregator(), Resource({}), ) sum_record.aggregator.update(3) sum_record.aggregator.update(2) sum_record.aggregator.take_checkpoint() expected_timeseries = self.exporter._create_timeseries( sum_record, "testname_sum", 5.0) timeseries = self.exporter._convert_from_sum(sum_record) self.assertEqual(timeseries[0], expected_timeseries) # Ensures sum min_max_count aggregator is correctly converted to timeseries def test_convert_from_min_max_sum_count(self): min_max_sum_count_record = ExportRecord( Counter("testname", "testdesc", "testunit", int, None), None, MinMaxSumCountAggregator(), Resource({}), ) min_max_sum_count_record.aggregator.update(5) min_max_sum_count_record.aggregator.update(1) min_max_sum_count_record.aggregator.take_checkpoint() expected_min_timeseries = self.exporter._create_timeseries( min_max_sum_count_record, "testname_min", 1.0) expected_max_timeseries = self.exporter._create_timeseries( min_max_sum_count_record, "testname_max", 5.0) expected_sum_timeseries = self.exporter._create_timeseries( min_max_sum_count_record, "testname_sum", 6.0) expected_count_timeseries = self.exporter._create_timeseries( min_max_sum_count_record, "testname_count", 2.0) timeseries = self.exporter._convert_from_min_max_sum_count( min_max_sum_count_record) self.assertEqual(timeseries[0], expected_min_timeseries) self.assertEqual(timeseries[1], expected_max_timeseries) self.assertEqual(timeseries[2], expected_sum_timeseries) self.assertEqual(timeseries[3], expected_count_timeseries) # Ensures histogram aggregator is correctly converted to timeseries def test_convert_from_histogram(self): histogram_record = ExportRecord( Counter("testname", "testdesc", "testunit", int, None), None, HistogramAggregator(), Resource({}), ) histogram_record.aggregator.update(5) histogram_record.aggregator.update(2) histogram_record.aggregator.update(-1) histogram_record.aggregator.take_checkpoint() expected_le_0_timeseries = self.exporter._create_timeseries( histogram_record, "testname_histogram", 1.0, ("le", "0")) expected_le_inf_timeseries = self.exporter._create_timeseries( histogram_record, "testname_histogram", 2.0, ("le", "+Inf")) timeseries = self.exporter._convert_from_histogram(histogram_record) self.assertEqual(timeseries[0], expected_le_0_timeseries) self.assertEqual(timeseries[1], expected_le_inf_timeseries) # Ensures last value aggregator is correctly converted to timeseries def test_convert_from_last_value(self): last_value_record = ExportRecord( Counter("testname", "testdesc", "testunit", int, None), None, LastValueAggregator(), Resource({}), ) last_value_record.aggregator.update(1) last_value_record.aggregator.update(5) last_value_record.aggregator.take_checkpoint() expected_timeseries = self.exporter._create_timeseries( last_value_record, "testname_last", 5.0) timeseries = self.exporter._convert_from_last_value(last_value_record) self.assertEqual(timeseries[0], expected_timeseries) # Ensures value observer aggregator is correctly converted to timeseries def test_convert_from_value_observer(self): value_observer_record = ExportRecord( Counter("testname", "testdesc", "testunit", int, None), None, ValueObserverAggregator(), Resource({}), ) value_observer_record.aggregator.update(5) value_observer_record.aggregator.update(1) value_observer_record.aggregator.update(2) value_observer_record.aggregator.take_checkpoint() expected_min_timeseries = self.exporter._create_timeseries( value_observer_record, "testname_min", 1.0) expected_max_timeseries = self.exporter._create_timeseries( value_observer_record, "testname_max", 5.0) expected_sum_timeseries = self.exporter._create_timeseries( value_observer_record, "testname_sum", 8.0) expected_count_timeseries = self.exporter._create_timeseries( value_observer_record, "testname_count", 3.0) expected_last_timeseries = self.exporter._create_timeseries( value_observer_record, "testname_last", 2.0) timeseries = self.exporter._convert_from_value_observer( value_observer_record) self.assertEqual(timeseries[0], expected_min_timeseries) self.assertEqual(timeseries[1], expected_max_timeseries) self.assertEqual(timeseries[2], expected_sum_timeseries) self.assertEqual(timeseries[3], expected_count_timeseries) self.assertEqual(timeseries[4], expected_last_timeseries) # Ensures quantile aggregator is correctly converted to timeseries # TODO: Add test_convert_from_quantile once method is implemented # Ensures timeseries produced contains appropriate sample and labels 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)
def test_invalid_tls_config_key_only_param(self): tls_config = {"cert_file": "value"} with self.assertRaises(ValueError): PrometheusRemoteWriteMetricsExporter( endpoint="/prom/test_endpoint", tls_config=tls_config)
from opentelemetry.sdk.metrics import MeterProvider from opentelemetry.sdk.metrics.export.aggregate import ( HistogramAggregator, LastValueAggregator, MinMaxSumCountAggregator, SumAggregator, ) from opentelemetry.sdk.metrics.view import View, ViewConfig logging.basicConfig(stream=sys.stdout, level=logging.INFO) logger = logging.getLogger(__name__) metrics.set_meter_provider(MeterProvider()) meter = metrics.get_meter(__name__) exporter = PrometheusRemoteWriteMetricsExporter( endpoint="http://cortex:9009/api/prom/push", headers={"X-Scope-Org-ID": "5"}, ) metrics.get_meter_provider().start_pipeline(meter, exporter, 1) testing_labels = {"environment": "testing"} # Callback to gather cpu usage def get_cpu_usage_callback(observer): for (number, percent) in enumerate(psutil.cpu_percent(percpu=True)): labels = {"cpu_number": str(number)} observer.observe(percent, labels) # Callback to gather RAM usage def get_ram_usage_callback(observer): ram_percent = psutil.virtual_memory().percent