示例#1
0
    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"),
        )
示例#2
0
    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"),
        )
示例#3
0
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")
示例#4
0
    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()
示例#5
0
    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")],
        )
示例#6
0
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.