""" Stats resource for the OpenEventDatabase. """ import subprocess import falcon import psycopg2.extras from oedb.utils.db import db_connect from oedb.utils.serialization import dumps from oedb.utils.logging import logger class StatsResource: """ Resource for retrieving database statistics. Handles the /stats endpoint. """ def on_get(self, req, resp): """ Handle GET requests to the /stats endpoint. Args: req: The request object. resp: The response object. """ logger.info("Processing GET request to /stats") db = db_connect() cur = db.cursor(cursor_factory=psycopg2.extras.DictCursor) try: # Estimated row count, way faster than count(*) cur.execute("SELECT reltuples::bigint FROM pg_class r WHERE relname = 'events';") count = cur.fetchone()[0] logger.debug(f"Estimated event count: {count}") # If the estimated count is negative, fall back to an actual count if count < 0: logger.warning(f"Estimated event count is negative ({count}), falling back to COUNT(*)") cur.execute("SELECT COUNT(*) FROM events;") count = cur.fetchone()[0] logger.debug(f"Actual event count: {count}") # Global info cur.execute("SELECT max(lastupdate) as last_updated, current_timestamp-pg_postmaster_start_time() from events;") pg_stats = cur.fetchone() last = pg_stats[0] pg_uptime = pg_stats[1] uptime = subprocess.check_output(["uptime", "-p"]).decode('utf-8')[0:-1] # Summary about last 10000 events (what, last, count, sources) cur.execute("SELECT row_to_json(stat) from (SELECT events_what as what, left(max(upper(events_when))::text,19) as last, count(*) as count, array_agg(distinct(regexp_replace(regexp_replace(events_tags ->> 'source','^(http://|https://)',''),'/.*',''))) as source from (select * from events order by lastupdate desc limit 10000) as last group by 1 order by 2 desc) as stat;") recent = cur.fetchall() resp.text = dumps(dict(events_count=count, last_updated=last, uptime=uptime, db_uptime=pg_uptime, recent=recent)) resp.status = falcon.HTTP_200 logger.success("Successfully processed GET request to /stats") except Exception as e: logger.error(f"Error processing GET request to /stats: {e}") resp.status = falcon.HTTP_500 resp.text = dumps({"error": str(e)}) finally: cur.close() db.close()