Skip to content

Commit 8ad0ac0

Browse files
authored
Merge pull request #26 from saichandrapandraju/prometheus-publishing
feat(RHOAIENG-21044): Metrics: Prometheus publishing
2 parents 00aef58 + 6ec663d commit 8ad0ac0

32 files changed

+3369
-13
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ dependencies = [
2020
[project.optional-dependencies]
2121
dev = [
2222
"pytest>=7.4.2,<9",
23+
"pytest-asyncio>=0.26.0,<2",
2324
"isort>=5.12.0,<7",
2425
"flake8>=6.1.0,<8",
2526
"mypy>=1.5.1,<2",
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import logging
2+
from typing import Callable, Dict
3+
4+
from pandas import DataFrame
5+
6+
from src.service.payloads.metrics.base_metric_request import BaseMetricRequest
7+
from src.service.prometheus.metric_value_carrier import MetricValueCarrier
8+
9+
logger: logging.Logger = logging.getLogger(__name__)
10+
11+
12+
class MetricsDirectory:
13+
def __init__(self) -> None:
14+
self.calculator_directory: Dict[
15+
str, Callable[[DataFrame, BaseMetricRequest], MetricValueCarrier]
16+
] = {}
17+
18+
def register(
19+
self,
20+
name: str,
21+
calculator: Callable[[DataFrame, BaseMetricRequest], MetricValueCarrier],
22+
) -> None:
23+
if name not in self.calculator_directory:
24+
self.calculator_directory[name] = calculator
25+
logger.debug(f"Registered calculator for metric: {name}")
26+
else:
27+
logger.warning(
28+
f"Attempted to register duplicate calculator for metric: {name}. "
29+
"Ignoring duplicate registration."
30+
)
31+
32+
def get_calculator(
33+
self, name: str
34+
) -> Callable[[DataFrame, BaseMetricRequest], MetricValueCarrier]:
35+
return self.calculator_directory.get(name)

src/main.py

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,37 @@
1-
import os
1+
import asyncio
2+
import logging
3+
from contextlib import asynccontextmanager
24

35
import uvicorn
46
from fastapi import FastAPI, Request, Response
7+
from fastapi.middleware.cors import CORSMiddleware
58
from fastapi.responses import JSONResponse
9+
from fastapi_utils.tasks import repeat_every
610
from prometheus_client import CONTENT_TYPE_LATEST, generate_latest
7-
from fastapi.middleware.cors import CORSMiddleware
8-
import logging
911

1012
# Endpoint routers
1113
from src.endpoints.consumer.consumer_endpoint import router as consumer_router
12-
from src.endpoints.metrics.fairness.group.dir import router as dir_router
14+
from src.endpoints.data.data_download import router as data_download_router
1315
from src.endpoints.data.data_upload import router as data_upload_router
1416

17+
# from src.endpoints.explainers import router as explainers_router
18+
from src.endpoints.explainers.global_explainer import router as explainers_global_router
19+
from src.endpoints.explainers.local_explainer import router as explainers_local_router
20+
from src.endpoints.metadata import router as metadata_router
21+
1522
# from src.endpoints.drift_metrics import router as drift_metrics_router
1623
from src.endpoints.metrics.drift.approx_ks_test import (
1724
router as drift_approx_ks_test_router,
1825
)
1926
from src.endpoints.metrics.drift.fourier_mmd import router as drift_fourier_mmd_router
2027
from src.endpoints.metrics.drift.ks_test import router as drift_ks_test_router
2128
from src.endpoints.metrics.drift.meanshift import router as drift_meanshift_router
22-
23-
# from src.endpoints.explainers import router as explainers_router
24-
from src.endpoints.explainers.global_explainer import router as explainers_global_router
25-
from src.endpoints.explainers.local_explainer import router as explainers_local_router
29+
from src.endpoints.metrics.fairness.group.dir import router as dir_router
2630
from src.endpoints.metrics.fairness.group.spd import router as spd_router
2731
from src.endpoints.metrics.identity.identity_endpoint import router as identity_router
28-
from src.endpoints.metadata import router as metadata_router
2932
from src.endpoints.metrics.metrics_info import router as metrics_info_router
30-
from src.endpoints.data.data_download import router as data_download_router
33+
34+
from src.service.prometheus.prometheus_scheduler import PrometheusScheduler
3135

3236
try:
3337
from src.endpoints.evaluation.lm_evaluation_harness import (
@@ -44,10 +48,36 @@
4448
)
4549
logger = logging.getLogger(__name__)
4650

51+
prometheus_scheduler = PrometheusScheduler()
52+
53+
54+
@repeat_every(
55+
seconds=prometheus_scheduler.service_config.get("metrics_schedule", 30),
56+
logger=logger,
57+
raise_exceptions=False,
58+
)
59+
async def schedule_metrics_calculation():
60+
await prometheus_scheduler.calculate()
61+
62+
63+
@asynccontextmanager
64+
async def lifespan(app: FastAPI):
65+
task = asyncio.create_task(schedule_metrics_calculation())
66+
67+
yield
68+
69+
task.cancel()
70+
try:
71+
await task
72+
except asyncio.CancelledError:
73+
logger.info("Prometheus metrics calculation task cancelled during shutdown")
74+
75+
4776
app = FastAPI(
4877
title="TrustyAI Service API",
4978
version="1.0.0rc0",
5079
description="TrustyAI Service API",
80+
lifespan=lifespan,
5181
)
5282

5383
# CORS

src/service/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# Place all external packages and service algorithms here
22
# The main REST server should only call
33
# - modules directly related to the service HTTP, data, prometheus, etc.
4-
# - This service module
4+
# - This service module

src/service/constants.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44
METADATA_SUFFIX = "_metadata"
55
PROTECTED_DATASET_SUFFIX = "trustyai_internal_"
66
PARTIAL_PAYLOAD_DATASET_NAME = "partial_payloads"
7-
7+
GROUND_TRUTH_SUFFIX = "-ground-truths"
8+
METADATA_FILENAME = "metadata.json"
9+
INTERNAL_DATA_FILENAME = "internal_data.csv"
810
# Payload parsing
911
TRUSTYAI_TAG_PREFIX = "_trustyai"
1012
SYNTHETIC_TAG = f"{TRUSTYAI_TAG_PREFIX}_synthetic"
1113
UNLABELED_TAG = f"{TRUSTYAI_TAG_PREFIX}_unlabeled"
12-
BIAS_IGNORE_PARAM = "bias-ignore"
14+
BIAS_IGNORE_PARAM = "bias-ignore"
15+
# Prometheus constants
16+
PROMETHEUS_METRIC_PREFIX = "trustyai_"

0 commit comments

Comments
 (0)