async def test_render_in_quart_app(self): """ check render usage in Quart app """ app = Quart(__name__) app.registry = aioprometheus.Registry() app.events_counter = aioprometheus.Counter("events", "Number of events.") app.registry.register(app.events_counter) @app.route("/") async def index(): app.events_counter.inc({"path": "/"}) return "hello" @app.route("/metrics") async def handle_metrics(): content, http_headers = aioprometheus.render( app.registry, request.headers.getlist("accept")) return content, http_headers # The test client also starts the web service test_client = app.test_client() # Access root to increment metric counter response = await test_client.get("/") self.assertEqual(response.status_code, 200) # Get default format response = await test_client.get("/metrics", headers={"accept": "*/*"}) self.assertEqual(response.status_code, 200) self.assertIn( aioprometheus.formats.text.TEXT_CONTENT_TYPE, response.headers.get("content-type"), ) # payload = await response.get_data() # Get text format response = await test_client.get("/metrics", headers={"accept": "text/plain;"}) self.assertEqual(response.status_code, 200) self.assertIn( aioprometheus.formats.text.TEXT_CONTENT_TYPE, response.headers.get("content-type"), ) # Get binary format response = await test_client.get( "/metrics", headers={ "accept": aioprometheus.formats.binary.BINARY_CONTENT_TYPE }, ) self.assertEqual(response.status_code, 200) self.assertIn( aioprometheus.formats.binary.BINARY_CONTENT_TYPE, response.headers.get("content-type"), )
def test_render_in_fastapi_app(self): """ check render usage in FastAPI app """ app = FastAPI() app.registry = aioprometheus.Registry() app.events_counter = aioprometheus.Counter("events", "Number of events.") app.registry.register(app.events_counter) @app.get("/") async def hello(): app.events_counter.inc({"path": "/"}) return "hello" @app.get("/metrics") async def handle_metrics(response: Response, accept: List[str] = Header(None)): content, http_headers = aioprometheus.render(app.registry, accept) return Response(content=content, media_type=http_headers["Content-Type"]) # The test client also starts the web service test_client = TestClient(app) # Access root to increment metric counter response = test_client.get("/") self.assertEqual(response.status_code, 200) # Get default format response = test_client.get("/metrics", headers={"accept": "*/*"}) self.assertEqual(response.status_code, 200) self.assertIn( aioprometheus.formats.text.TEXT_CONTENT_TYPE, response.headers.get("content-type"), ) # Get text format response = test_client.get("/metrics", headers={"accept": "text/plain;"}) self.assertEqual(response.status_code, 200) self.assertIn( aioprometheus.formats.text.TEXT_CONTENT_TYPE, response.headers.get("content-type"), ) # Get binary format response = test_client.get( "/metrics", headers={"accept": aioprometheus.formats.binary.BINARY_CONTENT_TYPE}, ) self.assertEqual(response.status_code, 200) self.assertIn( aioprometheus.formats.binary.BINARY_CONTENT_TYPE, response.headers.get("content-type"), )
import socket import aioprometheus import servo from typing import List # TODO: These are modeled as globals rather than instance attributes # to deliver poor man's multiservo support. Needs a new design service: aioprometheus.Service = aioprometheus.Service() measure_counter: aioprometheus.Counter = aioprometheus.Counter( "measurements", "Number of events.", const_labels={"host": socket.gethostname()}) adjust_counter: aioprometheus.Counter = aioprometheus.Counter( "adjusts", "Number of events.", const_labels={"host": socket.gethostname()}) service.register(measure_counter) service.register(adjust_counter) @servo.metadata( description="Tracks metrics for servo events.", version="0.5.0", homepage="https://github.com/opsani/servox", license=servo.License.apache2, maturity=servo.Maturity.experimental, ) class MetricsConnector(servo.BaseConnector): @servo.on_event() async def startup(self) -> None: await service.start(addr="127.0.0.1")
async def test_render_in_aiohttp_app(self): """ check render usage in aiohttp app """ app = aiohttp.web.Application() app.registry = aioprometheus.Registry() app.events_counter = aioprometheus.Counter("events", "Number of events.") app.registry.register(app.events_counter) async def index(request): app.events_counter.inc({"path": "/"}) return aiohttp.web.Response(text="hello") async def handle_metrics(request): content, http_headers = aioprometheus.render( app.registry, request.headers.getall(aiohttp.hdrs.ACCEPT, []) ) return aiohttp.web.Response(body=content, headers=http_headers) app.add_routes( [aiohttp.web.get("/", index), aiohttp.web.get("/metrics", handle_metrics)] ) runner = aiohttp.web.AppRunner(app) await runner.setup() site = aiohttp.web.TCPSite(runner, "127.0.0.1", 0, shutdown_timeout=1.0) await site.start() # Fetch ephemeral port that was bound. # IPv4 address returns a 2-tuple, IPv6 returns a 4-tuple host, port, *_ = runner.addresses[0] host = host if ":" not in host else f"[{host}]" url = f"http://{host}:{port}" root_url = f"{url}/" metrics_url = f"{url}/metrics" async with aiohttp.ClientSession() as session: # Access root to increment metric counter async with session.get(root_url) as response: self.assertEqual(response.status, 200) # Get default format async with session.get( metrics_url, headers={aiohttp.hdrs.ACCEPT: "*/*"} ) as response: self.assertEqual(response.status, 200) self.assertIn( aioprometheus.formats.text.TEXT_CONTENT_TYPE, response.headers.get("content-type"), ) # content = await response.read() # Get text format async with session.get( metrics_url, headers={aiohttp.hdrs.ACCEPT: "text/plain;"} ) as response: self.assertEqual(response.status, 200) self.assertIn( aioprometheus.formats.text.TEXT_CONTENT_TYPE, response.headers.get("content-type"), ) # Get binary format async with session.get( metrics_url, headers={ aiohttp.hdrs.ACCEPT: aioprometheus.formats.binary.BINARY_CONTENT_TYPE }, ) as response: self.assertEqual(response.status, 200) self.assertIn( aioprometheus.formats.binary.BINARY_CONTENT_TYPE, response.headers.get("content-type"), ) await runner.cleanup()
async def test_render_in_vibora_app(self): """ check render usage in Vibora app """ app = Vibora(__name__) app.registry = aioprometheus.Registry() app.events_counter = aioprometheus.Counter("events", "Number of events.") app.registry.register(app.events_counter) @app.route("/") async def index(request: Request): app.events_counter.inc({"path": "/"}) return Response(b"hello") @app.route("/metrics") async def handle_metrics(request: Request): """ Negotiate a response format by inspecting the ACCEPTS headers and selecting the most efficient format. Render metrics in the registry into the chosen format and return a response. """ content, http_headers = aioprometheus.render( app.registry, [request.headers.get("accept")]) return Response(content, headers=http_headers) # NOTE: Vibora client.get HTTP headers handling seem to expect case-sensitive. # Must use Accept and not accept or ACCEPT! Where as response handling of # requests doesn't seem to care. # Until Vibora #139 is resolved we must use "Accept". # The test client also starts the web service client = app.test_client() # Access root to increment metric counter response = await client.get("/") self.assertEqual(response.status_code, 200) # Get default format response = await client.get("/metrics", headers={"Accept": "*/*"}) self.assertEqual(response.status_code, 200) self.assertIn( aioprometheus.formats.TEXT_CONTENT_TYPE, [response.headers.get("Content-Type")], ) # Get text format response = await client.get("/metrics", headers={"Accept": "text/plain;"}) self.assertEqual(response.status_code, 200) self.assertIn( aioprometheus.formats.TEXT_CONTENT_TYPE, [response.headers.get("content-type")], ) # # Get binary format response = await client.get( "/metrics", headers={"Accept": aioprometheus.formats.BINARY_CONTENT_TYPE}) self.assertEqual(response.status_code, 200) self.assertIn( aioprometheus.formats.BINARY_CONTENT_TYPE, [response.headers.get("content-type")], )
BIND_ADDRESS = os.getenv('BIND_ADDRESS', '0.0.0.0') BIND_PORT = os.getenv('BIND_PORT', '53') METRICS_PORT = os.getenv('METRICS_PORT', '5000') UPSTREAM_ADDRESS = os.getenv('UPSTREAM_ADDRESS', '1.1.1.1') UPSTREAM_PORT = 853 DEBUG = os.getenv('DEBUG', 0) FORMAT = "%(asctime)s %(name)-4s %(process)d %(levelname)-6s %(funcName)-8s %(message)s" logger = logging.getLogger(__name__) const_labels = { "host": socket.gethostname(), } REQUESTS = aioprometheus.Counter("requests", "Number of requests.", const_labels=const_labels) REQUEST_TIME = aioprometheus.Summary("request_processing_seconds", "Time spent processing request", const_labels=const_labels) metric_svc = aioprometheus.Service() metric_svc.register(REQUESTS) metric_svc.register(REQUEST_TIME) async def query_upstream_server(raw_data): """Query a DNS-over-TLS backend server with the given data.""" # To establish a SSL/TLS connection not vulnerable to man-in-the-middle attacks, # it's essential to make sure the server presents the right certificate. # The certificate's hostname-specific data should match the server hostname.