Add global report generation
This commit is contained in:
parent
11d6e5e4ba
commit
a3f06fd9e2
3 changed files with 83 additions and 0 deletions
|
@ -24,6 +24,7 @@ python scripts/generate_reports.py hourly
|
||||||
python scripts/generate_reports.py daily
|
python scripts/generate_reports.py daily
|
||||||
python scripts/generate_reports.py weekly
|
python scripts/generate_reports.py weekly
|
||||||
python scripts/generate_reports.py monthly
|
python scripts/generate_reports.py monthly
|
||||||
|
python scripts/generate_reports.py global
|
||||||
|
|
||||||
# Generate reports for each individual domain
|
# Generate reports for each individual domain
|
||||||
echo "[INFO] Generating per-domain reports..."
|
echo "[INFO] Generating per-domain reports..."
|
||||||
|
|
|
@ -101,6 +101,10 @@ def _generate_interval(interval: str, domain: Optional[str] = None) -> None:
|
||||||
|
|
||||||
report_list = []
|
report_list = []
|
||||||
for definition in cfg:
|
for definition in cfg:
|
||||||
|
if "{bucket}" not in definition["query"] or definition.get("global"):
|
||||||
|
# Global reports are generated separately
|
||||||
|
continue
|
||||||
|
|
||||||
name = definition["name"]
|
name = definition["name"]
|
||||||
query = definition["query"].replace("{bucket}", bucket)
|
query = definition["query"].replace("{bucket}", bucket)
|
||||||
query = query.replace("FROM logs", "FROM logs_view")
|
query = query.replace("FROM logs", "FROM logs_view")
|
||||||
|
@ -154,6 +158,50 @@ def _generate_root_index() -> None:
|
||||||
typer.echo(f"Generated root index at {out_path}")
|
typer.echo(f"Generated root index at {out_path}")
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_global() -> None:
|
||||||
|
"""Generate reports that do not depend on an interval."""
|
||||||
|
cfg = _load_config()
|
||||||
|
if not cfg:
|
||||||
|
typer.echo("No report definitions found")
|
||||||
|
return
|
||||||
|
|
||||||
|
conn = sqlite3.connect(DB_PATH)
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
out_dir = OUTPUT_DIR / "global"
|
||||||
|
out_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
report_list = []
|
||||||
|
for definition in cfg:
|
||||||
|
if "{bucket}" in definition["query"] and not definition.get("global"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
name = definition["name"]
|
||||||
|
query = definition["query"]
|
||||||
|
cur.execute(query)
|
||||||
|
rows = cur.fetchall()
|
||||||
|
headers = [c[0] for c in cur.description]
|
||||||
|
data = [dict(zip(headers, row)) for row in rows]
|
||||||
|
json_path = out_dir / f"{name}.json"
|
||||||
|
_save_json(json_path, data)
|
||||||
|
entry = {
|
||||||
|
"name": name,
|
||||||
|
"label": definition.get("label", name.title()),
|
||||||
|
"chart": definition.get("chart", "line"),
|
||||||
|
"json": f"{name}.json",
|
||||||
|
"html": f"{name}.html",
|
||||||
|
}
|
||||||
|
if "color" in definition:
|
||||||
|
entry["color"] = definition["color"]
|
||||||
|
if "colors" in definition:
|
||||||
|
entry["colors"] = definition["colors"]
|
||||||
|
_render_snippet(entry, out_dir)
|
||||||
|
report_list.append(entry)
|
||||||
|
|
||||||
|
_save_json(out_dir / "reports.json", report_list)
|
||||||
|
typer.echo("Generated global reports")
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def hourly(
|
def hourly(
|
||||||
domain: Optional[str] = typer.Option(
|
domain: Optional[str] = typer.Option(
|
||||||
|
@ -218,6 +266,12 @@ def monthly(
|
||||||
_generate_interval("monthly", domain)
|
_generate_interval("monthly", domain)
|
||||||
|
|
||||||
|
|
||||||
|
@app.command("global")
|
||||||
|
def global_reports() -> None:
|
||||||
|
"""Generate global reports."""
|
||||||
|
_generate_global()
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def index() -> None:
|
def index() -> None:
|
||||||
"""Generate the root index page linking all reports."""
|
"""Generate the root index page linking all reports."""
|
||||||
|
|
|
@ -80,6 +80,14 @@ def sample_reports(tmp_path):
|
||||||
FROM logs
|
FROM logs
|
||||||
GROUP BY bucket
|
GROUP BY bucket
|
||||||
ORDER BY bucket
|
ORDER BY bucket
|
||||||
|
- name: domain_totals
|
||||||
|
global: true
|
||||||
|
query: |
|
||||||
|
SELECT host AS bucket,
|
||||||
|
COUNT(*) AS value
|
||||||
|
FROM logs
|
||||||
|
GROUP BY host
|
||||||
|
ORDER BY value DESC
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
return cfg
|
return cfg
|
||||||
|
@ -161,3 +169,23 @@ def test_generate_root_index(tmp_path, sample_reports, monkeypatch):
|
||||||
# check for domain options
|
# check for domain options
|
||||||
assert '<option value="foo.com">' in content
|
assert '<option value="foo.com">' in content
|
||||||
assert '<option value="bar.com">' in content
|
assert '<option value="bar.com">' in content
|
||||||
|
|
||||||
|
|
||||||
|
def test_global_reports_once(tmp_path, sample_reports, monkeypatch):
|
||||||
|
db_path = tmp_path / "database" / "ngxstat.db"
|
||||||
|
setup_db(db_path)
|
||||||
|
|
||||||
|
monkeypatch.setattr(gr, "DB_PATH", db_path)
|
||||||
|
monkeypatch.setattr(gr, "OUTPUT_DIR", tmp_path / "output")
|
||||||
|
monkeypatch.setattr(gr, "REPORT_CONFIG", sample_reports)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
gr, "TEMPLATE_DIR", Path(__file__).resolve().parents[1] / "templates"
|
||||||
|
)
|
||||||
|
|
||||||
|
gr._generate_global()
|
||||||
|
gr._generate_interval("hourly")
|
||||||
|
|
||||||
|
global_snippet = tmp_path / "output" / "global" / "domain_totals.html"
|
||||||
|
assert global_snippet.exists()
|
||||||
|
assert not (tmp_path / "output" / "hourly" / "domain_totals.html").exists()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue