Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Prometheus Remote Write Exporter (2/6) #206

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Changelog

## Unreleased
- Setup for Prometheus Remote Write Exporter
((#180)[https://github.com/open-telemetry/opentelemetry-python-contrib/pull/180])
- Prometheus Remote Write Exporter Setup
((#180)[https://github.com/open-telemetry/opentelemetry-python-contrib/pull/180])
- Add Exporter constructor validation methods
((#206)[https://github.com/open-telemetry/opentelemetry-python-contrib/pull/206])
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,106 @@ class PrometheusRemoteWriteMetricsExporter(MetricsExporter):
Args:
endpoint: url where data will be sent (Required)
basic_auth: username and password for authentication (Optional)
bearer_token: token used for authentication (Optional)
bearer_token_file: filepath to file containing authentication token (Optional)
headers: additional headers for remote write request (Optional
headers: additional headers for remote write request (Optional)
timeout: timeout for requests to the remote write endpoint in seconds (Optional)
proxies: dict mapping request proxy protocols to proxy urls (Optional)
tls_config: configuration for remote write TLS settings (Optional)
"""

def __init__(
self,
endpoint: str,
basic_auth: Dict = None,
bearer_token: str = None,
bearer_token_file: str = None,
headers: Dict = None,
timeout: int = 30,
tls_config: Dict = None,
proxies: Dict = None,
):
raise NotImplementedError()
self.endpoint = endpoint
self.basic_auth = basic_auth
self.headers = headers
self.timeout = timeout
self.tls_config = tls_config
self.proxies = proxies

@property
def endpoint(self):
return self._endpoint

@endpoint.setter
def endpoint(self, endpoint: str):
if endpoint == "":
raise ValueError("endpoint required")
self._endpoint = endpoint

@property
def basic_auth(self):
return self._basic_auth

@basic_auth.setter
def basic_auth(self, basic_auth: Dict):
if basic_auth:
if "username" not in basic_auth:
raise ValueError("username required in basic_auth")
if (
"password" not in basic_auth
and "password_file" not in basic_auth
):
raise ValueError("password required in basic_auth")
if "password" in basic_auth and "password_file" in basic_auth:
raise ValueError(
"basic_auth cannot contain password and password_file"
)
self._basic_auth = basic_auth

@property
def timeout(self):
return self._timeout

@timeout.setter
def timeout(self, timeout: int):
if timeout <= 0:
raise ValueError("timeout must be greater than 0")
self._timeout = timeout

@property
def tls_config(self):
return self._tls_config

@tls_config.setter
def tls_config(self, tls_config: Dict):
if tls_config:
new_config = {}
ocelotl marked this conversation as resolved.
Show resolved Hide resolved
if "ca_file" in tls_config:
new_config["ca_file"] = tls_config["ca_file"]
if "cert_file" in tls_config and "key_file" in tls_config:
new_config["cert_file"] = tls_config["cert_file"]
new_config["key_file"] = tls_config["key_file"]
elif "cert_file" in tls_config or "key_file" in tls_config:
raise ValueError(
"tls_config requires both cert_file and key_file"
)
if "insecure_skip_verify" in tls_config:
new_config["insecure_skip_verify"] = tls_config[
"insecure_skip_verify"
]
self._tls_config = tls_config

@property
def proxies(self):
return self._proxies

@proxies.setter
def proxies(self, proxies: Dict):
self._proxies = proxies

@property
def headers(self):
return self._headers

@headers.setter
def headers(self, headers: Dict):
self._headers = headers

def export(
self, export_records: Sequence[ExportRecord]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,102 @@

import unittest

from opentelemetry.exporter.prometheus_remote_write import (
PrometheusRemoteWriteMetricsExporter,
)


class TestValidation(unittest.TestCase):
# Test cases to ensure exporter parameter validation works as intended
def test_valid_standard_param(self):
pass
exporter = PrometheusRemoteWriteMetricsExporter(
endpoint="/prom/test_endpoint",
)
self.assertEqual(exporter.endpoint, "/prom/test_endpoint")

def test_valid_basic_auth_param(self):
pass

def test_valid_bearer_token_param(self):
pass
exporter = PrometheusRemoteWriteMetricsExporter(
endpoint="/prom/test_endpoint",
basic_auth={
"username": "test_username",
"password": "test_password",
},
)
self.assertEqual(exporter.basic_auth["username"], "test_username")
self.assertEqual(exporter.basic_auth["password"], "test_password")

def test_invalid_no_endpoint_param(self):
pass
with self.assertRaises(ValueError):
PrometheusRemoteWriteMetricsExporter("")

def test_invalid_no_username_param(self):
pass
with self.assertRaises(ValueError):
PrometheusRemoteWriteMetricsExporter(
endpoint="/prom/test_endpoint",
basic_auth={"password": "test_password"},
)

def test_invalid_no_password_param(self):
pass
with self.assertRaises(ValueError):
PrometheusRemoteWriteMetricsExporter(
endpoint="/prom/test_endpoint",
basic_auth={"username": "test_username"},
)

def test_invalid_conflicting_passwords_param(self):
pass

def test_invalid_conflicting_bearer_tokens_param(self):
pass

def test_invalid_conflicting_auth_param(self):
pass
with self.assertRaises(ValueError):
PrometheusRemoteWriteMetricsExporter(
endpoint="/prom/test_endpoint",
basic_auth={
"username": "test_username",
"password": "test_password",
"password_file": "test_file",
},
)

def test_invalid_timeout_param(self):
with self.assertRaises(ValueError):
PrometheusRemoteWriteMetricsExporter(
endpoint="/prom/test_endpoint", timeout=0
)

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"],
)

# if cert_file is provided, then key_file must also be provided
def test_invalid_tls_config_cert_only_param(self):
tls_config = {"cert_file": "value"}
with self.assertRaises(ValueError):
PrometheusRemoteWriteMetricsExporter(
endpoint="/prom/test_endpoint", tls_config=tls_config
)

# if cert_file is provided, then key_file must also be provided
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
)


class TestConversion(unittest.TestCase):
Expand Down