From 61447ee768e21719a4d722eeee29b8293eba23fc Mon Sep 17 00:00:00 2001 From: "Luca Sorace \"Stranck" Date: Wed, 14 Feb 2024 20:22:56 +0100 Subject: [PATCH] Added custom metrics And removed old library --- app.py | 32 ++++++++++++++------------ checkin.py | 2 ++ config.example.py | 8 ++----- ext.py | 7 ++++++ metrics.py | 58 +++++++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 3 +-- room.py | 1 + utils.py | 6 ++++- 8 files changed, 94 insertions(+), 23 deletions(-) create mode 100644 metrics.py diff --git a/app.py b/app.py index 1d66249..6bbdd11 100644 --- a/app.py +++ b/app.py @@ -14,10 +14,8 @@ from messages import LOCALES import sqlite3 import requests import sys -from sanic.log import logger, logging - -if METRICS: - from sanic_prometheus import monitor +from sanic.log import logger, logging, access_logger +from metrics import * app = Sanic(__name__) app.static("/res", "res/") @@ -39,8 +37,7 @@ app.blueprint([room_bp, karaoke_bp, propic_bp, export_bp, stats_bp, api_bp, carp @app.exception(exceptions.SanicException) async def clear_session(request, exception): - print(exception) - print(request) + logger.warning(f"{request} -> {exception}") tpl = app.ctx.tpl.get_template('error.html') r = html(tpl.render(exception=exception)) @@ -53,6 +50,7 @@ async def clear_session(request, exception): async def main_start(*_): logger.info(f"[{app.name}] >>>>>> main_start <<<<<<") logger.setLevel(LOG_LEVEL) + access_logger.addFilter(MetricsFilter()) app.config.REQUEST_MAX_SIZE = PROPIC_MAX_FILE_SIZE * 3 @@ -93,6 +91,7 @@ async def redirect_explore(request, code, secret, order: Order, secret2=None): if not order: async with httpx.AsyncClient() as client: + incPretixRead() res = await client.get(join(base_url_event, f"orders/{code}/"), headers=headers) if res.status_code != 200: @@ -157,6 +156,7 @@ async def download_ticket(request, order: Order): raise exceptions.Forbidden("You are not allowed to download this ticket.") async with httpx.AsyncClient() as client: + incPretixRead() res = await client.get(join(base_url_event, f"orders/{order.code}/download/pdf/"), headers=headers) if res.status_code == 409: @@ -191,6 +191,16 @@ async def logout(request): raise exceptions.Forbidden("You have been logged out.") +@app.get(METRICS_PATH) +async def metrics(request): + return text(getMetricsText() + "\n" + getRoomCountersText(request)) + +@app.on_request +async def countReqs(request : Request): + global METRICS_REQ_NO + if(request.path != METRICS_PATH): + incReqNo() + if __name__ == "__main__": # Wait for pretix in server reboot # Using a docker configuration, pretix may be unable to talk with postgres if postgres' service started before it. @@ -201,10 +211,12 @@ if __name__ == "__main__": while True: print("Trying connecting to pretix...", file=sys.stderr) try: + incPretixRead() res = requests.get(base_url_event, headers=headers) res = res.json() if(res['slug'] == EVENT_NAME): print("Healtchecking...", file=sys.stderr) + incPretixRead() res = requests.get(join(domain, "healthcheck"), headers=headers) if(res.status_code == 200): break @@ -213,12 +225,4 @@ if __name__ == "__main__": sleep(5) print("Connected to pretix!", file=sys.stderr) - if(METRICS): - if(METRICS_USE_ANOTHER_SOCKET): - print(f"Startin metrics server on {METRICS_IP}:{METRICS_PORT} on path '{METRICS_PATH}'") - monitor(app, metrics_path=METRICS_PATH).start_server(addr=METRICS_IP, port=METRICS_PORT) - else: - print(f"Startin metrics server on path '{METRICS_PATH}'") - monitor(app, metrics_path=METRICS_PATH).expose_endpoint() - app.run(host="127.0.0.1", port=8188, dev=DEV_MODE, access_log=ACCESS_LOG) diff --git a/checkin.py b/checkin.py index a51e14f..f61f590 100644 --- a/checkin.py +++ b/checkin.py @@ -11,6 +11,7 @@ from hashlib import sha224 from time import time from urllib.parse import unquote import json +from metrics import * bp = Blueprint("checkin", url_prefix="/checkin") @@ -64,6 +65,7 @@ async def do_checkin(request): if not order.checked_in: async with httpx.AsyncClient() as client: + incPretixWrite() res = await client.post(base_url_event.replace(f'events/{EVENT_NAME}/', 'checkinrpc/redeem/'), json={'secret': order.barcode, 'source_type': 'barcode', 'type': 'entry', 'lists': [3,]}, headers=headers) tpl = request.app.ctx.tpl.get_template('checkin_3.html') diff --git a/config.example.py b/config.example.py index 5fa52f9..f72d50a 100644 --- a/config.example.py +++ b/config.example.py @@ -40,11 +40,7 @@ DEV_MODE = True ACCESS_LOG = True EXTRA_PRINTS = True -METRICS = True -METRICS_USE_ANOTHER_SOCKET = True -METRICS_IP = "172.17.0.1" -METRICS_PORT = "1211" -METRICS_PATH = "/metrics" +METRICS_PATH = "/welcome/metrics" # Additional configured locales. # If an order has a country that's not listed here, @@ -138,5 +134,5 @@ ROOM_CAPACITY_MAP = { 'bed_in_room_overflow1_2': 2, } -# Autofilled +# Autofilled. Maps roomTypeId -> roomName ROOM_TYPE_NAMES = { } \ No newline at end of file diff --git a/ext.py b/ext.py index 5ececfc..4360783 100644 --- a/ext.py +++ b/ext.py @@ -8,6 +8,7 @@ from os.path import join import json from sanic.log import logger from time import time +from metrics import * import asyncio @dataclass @@ -159,6 +160,7 @@ class Order: localHeaders = dict(headers) localHeaders['Content-Type'] = mimeType localHeaders['Content-Disposition'] = f'attachment; filename="{fileName}"' + incPretixWrite() res = await client.post(join(base_url, 'upload'), headers=localHeaders, content=data) res = res.json() await self.edit_answer(name, res['id']) @@ -184,6 +186,7 @@ class Order: if (not found) and (new_answer is not None): async with httpx.AsyncClient() as client: + incPretixRead() res = await client.get(join(base_url_event, 'questions/'), headers=headers) res = res.json() for r in res['results']: @@ -211,6 +214,7 @@ class Order: # del self.answers[i]['options'] # del self.answers[i]['option_identifiers'] + incPretixWrite() res = await client.patch(join(base_url_event, f'orderpositions/{self.position_id}/'), headers=headers, json={'answers': self.answers}) if res.status_code != 200: @@ -244,6 +248,7 @@ class Quotas: async def get_quotas(request: Request=None): async with httpx.AsyncClient() as client: + incPretixRead() res = await client.get(join(base_url_event, 'quotas/?order=id&with_availability=true'), headers=headers) res = res.json() @@ -302,6 +307,7 @@ class OrderManager: async with httpx.AsyncClient() as client: while 1: p += 1 + incPretixRead() res = await client.get(join(base_url_event, f"orders/?page={p}"), headers=headers) if res.status_code == 404: break # Parse order data @@ -344,6 +350,7 @@ class OrderManager: if DEV_MODE and EXTRA_PRINTS: logger.debug(f'Fetching {code} with secret {secret}') async with httpx.AsyncClient() as client: + incPretixRead() res = await client.get(join(base_url_event, f"orders/{code}/"), headers=headers) if res.status_code != 200: if request: diff --git a/metrics.py b/metrics.py new file mode 100644 index 0000000..805f45c --- /dev/null +++ b/metrics.py @@ -0,0 +1,58 @@ +from sanic.log import logger, logging +from logging import LogRecord +from config import * + +METRICS_REQ_NO = 0 +METRICS_PRETIX_READ = 0 +METRICS_PRETIX_WRITE = 0 + +def incPretixRead(): + global METRICS_PRETIX_READ + METRICS_PRETIX_READ += 1 + +def incPretixWrite(): + global METRICS_PRETIX_WRITE + METRICS_PRETIX_WRITE += 1 + +def incReqNo(): + global METRICS_REQ_NO + METRICS_REQ_NO += 1 + +def getMetricsText(): + global METRICS_REQ_NO + global METRICS_PRETIX_READ + global METRICS_PRETIX_WRITE + out = [] + + out.append(f'sanic_request_count{{}} {METRICS_REQ_NO}') + out.append(f'webint_pretix_read_count{{}} {METRICS_PRETIX_READ}') + out.append(f'webint_pretix_write_count{{}} {METRICS_PRETIX_WRITE}') + + return "\n".join(out) + +def getRoomCountersText(request): + out = [] + try : + daily = 0 + counters = {} + for id in ROOM_TYPE_NAMES.keys(): + counters[id] = 0 + + for order in request.app.ctx.om.cache.values(): + if(order.daily): + daily += 1 + else: + counters[order.bed_in_room] += 1 + + for id, count in counters.items(): + out.append(f'webint_order_room_counter{{label="{ROOM_TYPE_NAMES[id]}"}} {count}') + out.append(f'webint_order_room_counter{{label="Daily"}} {daily}') + + except Exception as e: + print(e) + logger.warning("Error in loading metrics rooms") + return "\n".join(out) + +class MetricsFilter(logging.Filter): + def filter(self, record : LogRecord): + return not (record.request.endswith("/manage/metrics") and record.status == 200) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 1914903..c2ae761 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,5 +4,4 @@ httpx Pillow aztec_code_generator Jinja2 -Requests -sanic_prometheus \ No newline at end of file +Requests \ No newline at end of file diff --git a/room.py b/room.py index 4474c24..e521e82 100644 --- a/room.py +++ b/room.py @@ -344,6 +344,7 @@ async def confirm_room(request, order: Order, quotas: Quotas): # } # # async with httpx.AsyncClient() as client: + # incPretixRead() # res = await client.post(join(base_url_event, "orderpositions/"), headers=headers, json=thing) # # if res.status_code != 201: diff --git a/utils.py b/utils.py index 86f5b2f..a582ff1 100644 --- a/utils.py +++ b/utils.py @@ -4,7 +4,9 @@ from config import * import httpx from messages import ROOM_ERROR_TYPES from email_util import send_unconfirm_message +from sanic.response import text, html, redirect, raw from sanic.log import logger +from metrics import * METADATA_TAG = "meta_data" VARIATIONS_TAG = "variations" @@ -33,6 +35,7 @@ async def load_questions(): p = 0 while 1: p += 1 + incPretixRead() res = await client.get(join(base_url_event, f"questions/?page={p}"), headers=headers) if res.status_code == 404: break @@ -50,6 +53,7 @@ async def load_items(): p = 0 while 1: p += 1 + incPretixRead() res = await client.get(join(base_url_event, f"items/?page={p}"), headers=headers) if res.status_code == 404: break @@ -253,4 +257,4 @@ async def check_room(request, order, om=None): if order.room_confirmed: allOk = False order.set_room_errors(room_errors) - return (order, allOk, room_members) + return (order, allOk, room_members) \ No newline at end of file