Improved metrics handling
All checks were successful
Build Docker Image / build-and-deploy-image (push) Successful in 40s
All checks were successful
Build Docker Image / build-and-deploy-image (push) Successful in 40s
This commit is contained in:
64
app.py
64
app.py
@@ -1,6 +1,6 @@
|
||||
import asyncio
|
||||
import contextlib
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
import aiofiles
|
||||
import orjson
|
||||
@@ -12,60 +12,50 @@ env.read_env()
|
||||
unit_log_file: str = env.str("UNIT_LOG_FILE")
|
||||
|
||||
|
||||
async def process_log_entry(log_entry):
|
||||
with contextlib.suppress(Exception):
|
||||
log_data = orjson.loads(log_entry)
|
||||
request_time = float(log_data["request_time"])
|
||||
url = log_data["url"]
|
||||
http_method = log_data["http_method"]
|
||||
key = (url, http_method)
|
||||
return key, {"count": 1, "sum": request_time}
|
||||
return None
|
||||
def escape_label_value(value):
|
||||
return value.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n")
|
||||
|
||||
|
||||
async def read_and_process_logs():
|
||||
metrics_data = {}
|
||||
metric_lines = []
|
||||
|
||||
if os.path.exists(unit_log_file):
|
||||
async with aiofiles.open(unit_log_file, mode="r+") as f:
|
||||
lines = await f.readlines()
|
||||
await f.truncate(0)
|
||||
|
||||
tasks = [process_log_entry(line) for line in lines]
|
||||
results = await asyncio.gather(*tasks)
|
||||
for line in lines:
|
||||
with contextlib.suppress(Exception):
|
||||
log_data = orjson.loads(line)
|
||||
request_time = float(log_data["request_time"])
|
||||
url = log_data["url"]
|
||||
http_method = log_data["http_method"]
|
||||
datetime_str = log_data["datetime"]
|
||||
|
||||
for result in results:
|
||||
if not result:
|
||||
continue
|
||||
key, data = result
|
||||
if key in metrics_data:
|
||||
metrics_data[key]["count"] += data["count"]
|
||||
metrics_data[key]["sum"] += data["sum"]
|
||||
else:
|
||||
metrics_data[key] = data
|
||||
# Parse datetime_str to Unix timestamp in milliseconds
|
||||
dt = datetime.strptime(datetime_str, "%d/%b/%Y:%H:%M:%S %z")
|
||||
timestamp_ms = int(dt.timestamp() * 1000)
|
||||
|
||||
return metrics_data
|
||||
labels = (
|
||||
f'url="{escape_label_value(url)}",'
|
||||
f'http_method="{escape_label_value(http_method)}"'
|
||||
)
|
||||
|
||||
# Generate the metric line
|
||||
metric_line = f"request_duration_seconds{{{labels}}} {request_time} {timestamp_ms}"
|
||||
metric_lines.append(metric_line)
|
||||
return metric_lines
|
||||
|
||||
|
||||
async def generate_metrics_text():
|
||||
lines = [
|
||||
"# HELP request_duration_seconds_total Request duration in seconds",
|
||||
"# TYPE request_duration_seconds_total counter",
|
||||
"# HELP request_duration_seconds_count Number of requests",
|
||||
"# TYPE request_duration_seconds_count counter",
|
||||
"# HELP request_duration_seconds Request duration in seconds",
|
||||
"# TYPE request_duration_seconds gauge",
|
||||
]
|
||||
|
||||
metrics_data = await read_and_process_logs()
|
||||
metric_lines = await read_and_process_logs()
|
||||
|
||||
for key, data in metrics_data.items():
|
||||
url, http_method = key
|
||||
count = data["count"]
|
||||
sum_values = data["sum"]
|
||||
|
||||
labels = f'url="{url}",http_method="{http_method}"'
|
||||
|
||||
lines.append(f"request_duration_seconds_count{{{labels}}} {count}")
|
||||
lines.append(f"request_duration_seconds_total{{{labels}}} {sum_values}")
|
||||
lines.extend(metric_lines)
|
||||
|
||||
return "\n".join(lines) + "\n"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user