Merge branch 'master' into tania_authentication_local

This commit is contained in:
freeleaps-admin 2025-09-23 05:19:53 +00:00
commit 4e9412e48b
7 changed files with 115 additions and 45 deletions

View File

@ -1,3 +1,17 @@
# [1.9.0](https://gitea.freeleaps.mathmast.com/freeleaps/freeleaps-service-hub/compare/v1.8.0...v1.9.0) (2025-09-22)
### Features
* enable metrics ([afb90e5](https://gitea.freeleaps.mathmast.com/freeleaps/freeleaps-service-hub/commit/afb90e55e69ee995c7f9785505d97c94c25f5cc7))
# [1.8.0](https://gitea.freeleaps.mathmast.com/freeleaps/freeleaps-service-hub/compare/v1.7.1...v1.8.0) (2025-09-22)
### Features
* enable metrics ([459e56c](https://gitea.freeleaps.mathmast.com/freeleaps/freeleaps-service-hub/commit/459e56c7bfac627826dc5e77f042038ad60a870e))
## [1.7.1](https://gitea.freeleaps.mathmast.com/freeleaps/freeleaps-service-hub/compare/v1.7.0...v1.7.1) (2025-09-19) ## [1.7.1](https://gitea.freeleaps.mathmast.com/freeleaps/freeleaps-service-hub/compare/v1.7.0...v1.7.1) (2025-09-19)

View File

@ -1 +1 @@
1.7.1 1.9.0

View File

@ -17,17 +17,29 @@ class StarRocksMetricsService:
# Global dictionary mapping metric names to their corresponding SQL queries # Global dictionary mapping metric names to their corresponding SQL queries
METRIC_SQL_MAP: Dict[str, Dict[str, str]] = { METRIC_SQL_MAP: Dict[str, Dict[str, str]] = {
"freeleaps": { "freeleaps": {
"daily_registered_users": """ "dru": """
SELECT SELECT
date_id, date,
product_id, product_id,
registered_cnt, value,
updated_at updated_date
FROM dws_daily_registered_users FROM dws_dru
WHERE date_id >= %s WHERE date >= %s
AND date_id < %s AND date < %s
AND product_id = %s AND product_id = %s
ORDER BY date_id ASC ORDER BY date ASC
""",
"mru": """
SELECT
date,
product_id,
value,
updated_date
FROM dws_mru
WHERE date >= %s
AND date < %s
AND product_id = %s
ORDER BY date ASC
""", """,
}, },
"magicleaps": { "magicleaps": {
@ -86,6 +98,9 @@ class StarRocksMetricsService:
""" """
Query metric data for a specific date range. Query metric data for a specific date range.
This method will fill missing dates in the range with 0 values to ensure
a complete time series with no gaps.
Args: Args:
product_id: Product ID to identify which product's metrics to query product_id: Product ID to identify which product's metrics to query
metric_name: Name of the metric to query metric_name: Name of the metric to query
@ -93,7 +108,8 @@ class StarRocksMetricsService:
end_date: End date for the query (ISO string or date) end_date: End date for the query (ISO string or date)
Returns: Returns:
List of dictionaries with 'date' and 'value' keys List of dictionaries with 'date' and 'value' keys. Missing dates
in the range will be filled with 0 values.
Raises: Raises:
ValueError: If product_id or metric_name is not found in the SQL mapping ValueError: If product_id or metric_name is not found in the SQL mapping
@ -106,7 +122,8 @@ class StarRocksMetricsService:
start_date=date.today() - timedelta(days=30), start_date=date.today() - timedelta(days=30),
end_date=date.today() end_date=date.today()
) )
# Returns: [{"date": "2024-01-01", "value": 45, "labels": {...}}, ...] # Returns: [{"date": "2024-01-01", "value": 45, "labels": {...}},
# {"date": "2024-01-02", "value": 0, "labels": {...}}, ...]
""" """
# Check if product_id exists in the mapping # Check if product_id exists in the mapping
if product_id not in self.METRIC_SQL_MAP: if product_id not in self.METRIC_SQL_MAP:
@ -125,22 +142,22 @@ class StarRocksMetricsService:
# Parse date strings if they are strings # Parse date strings if they are strings
if isinstance(start_date, str): if isinstance(start_date, str):
try: try:
start_dt = datetime.strptime(start_date, '%Y-%m-%d').date() start_dt = datetime.strptime(start_date, '%Y-%m-%d %H:%M:%S')
except ValueError: except ValueError:
raise HTTPException( raise HTTPException(
status_code=400, status_code=400,
detail="Invalid start_date format. Expected YYYY-MM-DD" detail="Invalid start_date format. Expected YYYY-MM-DD HH:MM:SS"
) )
else: else:
start_dt = start_date start_dt = start_date
if isinstance(end_date, str): if isinstance(end_date, str):
try: try:
end_dt = datetime.strptime(end_date, '%Y-%m-%d').date() end_dt = datetime.strptime(end_date, '%Y-%m-%d %H:%M:%S')
except ValueError: except ValueError:
raise HTTPException( raise HTTPException(
status_code=400, status_code=400,
detail="Invalid end_date format. Expected YYYY-MM-DD" detail="Invalid start_date format. Expected YYYY-MM-DD HH:MM:SS"
) )
else: else:
end_dt = end_date end_dt = end_date
@ -174,7 +191,7 @@ class StarRocksMetricsService:
) )
# Parse the result and format it # Parse the result and format it
formatted_data = self._format_query_result(result, metric_name, product_id) formatted_data = self._format_query_result(result, metric_name, product_id, start_dt, end_dt)
await self.module_logger.log_info( await self.module_logger.log_info(
f"Successfully queried metric '{metric_name}' with {len(formatted_data)} data points") f"Successfully queried metric '{metric_name}' with {len(formatted_data)} data points")
@ -184,33 +201,45 @@ class StarRocksMetricsService:
await self.module_logger.log_error(f"Failed to query metric '{metric_name}': {e}") await self.module_logger.log_error(f"Failed to query metric '{metric_name}': {e}")
raise raise
def _format_query_result(self, starrocks_result: List[Dict[str, Any]], metric_name: str, product_id: str) -> List[Dict[str, Any]]: def _format_query_result(self, starrocks_result: List[Dict[str, Any]], metric_name: str, product_id: str, start_date: datetime, end_date: datetime) -> List[Dict[str, Any]]:
""" """
Format StarRocks query result into the required format. Format StarRocks query result into the required format and fill missing dates with 0 values.
Args: Args:
starrocks_result: Raw result from StarRocks query starrocks_result: Raw result from StarRocks query
metric_name: Name of the metric being queried metric_name: Name of the metric being queried
product_id: Product ID for the metric product_id: Product ID for the metric
start_date: Start date of the query range
end_date: End date of the query range
Returns: Returns:
List of dictionaries with 'date' and 'value' keys List of dictionaries with 'date' and 'value' keys, with missing dates filled with 0
""" """
formatted_data = [] # First, process the query results and create a dictionary for quick lookup
result_dict = {}
for row in starrocks_result: for row in starrocks_result:
# Format the date # Format the date
date_value = row.get("date_id") date_value = row.get("date")
if date_value: if date_value:
if isinstance(date_value, str): if isinstance(date_value, str):
date_str = date_value date_str = date_value
else:
# If it's a datetime object, format it as a string
if hasattr(date_value, 'strftime'):
# Convert to date first, then format consistently
if hasattr(date_value, 'date'):
date_obj = date_value.date() if hasattr(date_value, 'date') else date_value
else:
date_obj = date_value
date_str = date_obj.strftime('%Y-%m-%d') + ' 00:00:00'
else: else:
date_str = str(date_value) date_str = str(date_value)
else: else:
continue continue
# Get the value # Get the value
value = row.get("registered_cnt", 0) value = row.get("value", 0)
if value is None: if value is None:
value = 0 value = 0
@ -220,15 +249,39 @@ class StarRocksMetricsService:
"metric_type": metric_name "metric_type": metric_name
} }
formatted_data.append({ result_dict[date_str] = {
"date": date_str, "date": date_str,
"value": int(value) if value is not None else 0, "value": int(value) if value is not None else 0,
"metric": metric_name, "metric": metric_name,
"labels": labels "labels": labels
}
# Generate complete date range and fill missing dates with 0
formatted_data = []
current_date = start_date.date()
end_date_only = end_date.date()
while current_date < end_date_only:
date_str = current_date.strftime('%Y-%m-%d') + ' 00:00:00'
if date_str in result_dict:
# Use existing data
formatted_data.append(result_dict[date_str])
else:
# Fill missing date with 0 value
labels = {
"product_id": product_id,
"metric_type": metric_name
}
formatted_data.append({
"date": date_str,
"value": 0,
"metric": metric_name,
"labels": labels
}) })
# Sort by date current_date += timedelta(days=1)
formatted_data.sort(key=lambda x: x["date"])
return formatted_data return formatted_data

View File

@ -24,7 +24,7 @@ class AppSettings(BaseSettings):
# Prometheus settings # Prometheus settings
PROMETHEUS_ENDPOINT: str = "http://localhost:9090" PROMETHEUS_ENDPOINT: str = "http://localhost:9090"
METRICS_ENABLED: bool = False METRICS_ENABLED: bool = True
PROBES_ENABLED: bool = True PROBES_ENABLED: bool = True

View File

@ -3,7 +3,7 @@ SERVER_HOST=0.0.0.0
SERVER_PORT=8009 SERVER_PORT=8009
SERVICE_API_ACCESS_PORT=8009 SERVICE_API_ACCESS_PORT=8009
SERVICE_API_ACCESS_HOST=0.0.0.0 SERVICE_API_ACCESS_HOST=0.0.0.0
APP_NAME=1
# starrocks settings # starrocks settings
STARROCKS_HOST=freeleaps-starrocks-cluster-fe-service.freeleaps-data-platform.svc STARROCKS_HOST=freeleaps-starrocks-cluster-fe-service.freeleaps-data-platform.svc
STARROCKS_PORT=9030 STARROCKS_PORT=9030
@ -17,3 +17,5 @@ BACKEND_LOG_FILE_NAME=metrics
APPLICATION_ACTIVITY_LOG=metrics-activity APPLICATION_ACTIVITY_LOG=metrics-activity
PROMETHEUS_ENDPOINT=http://localhost:9090 PROMETHEUS_ENDPOINT=http://localhost:9090
METRICS_ENABLED=True

View File

@ -1,13 +1,14 @@
import logging import logging
from prometheus_fastapi_instrumentator import Instrumentator from prometheus_fastapi_instrumentator import Instrumentator
from common.config.app_settings import app_settings
def register(app): def register(app):
# Prometheus metric prefix is : freeleaps_metrics
instrumentator = ( instrumentator = (
Instrumentator().instrument( Instrumentator().instrument(
app, app,
metric_namespace="freeleaps-mertics", metric_namespace="freeleaps",
metric_subsystem=app_settings.APP_NAME) metric_subsystem="metrics", )
) )
@app.on_event("startup") @app.on_event("startup")

View File

@ -26,8 +26,8 @@ class MetricQueryRequest(BaseModel):
"""Request model for metric query.""" """Request model for metric query."""
product_id: str = Field(..., description="Product ID to identify which product's data to query") product_id: str = Field(..., description="Product ID to identify which product's data to query")
metric_name: str = Field(..., description="Name of the metric to query") metric_name: str = Field(..., description="Name of the metric to query")
start_date: str = Field(..., description="Start date in YYYY-MM-DD format") start_date: str = Field(..., description="Start date in YYYY-MM-DD HH:MM:SS format")
end_date: str = Field(..., description="End date in YYYY-MM-DD format") end_date: str = Field(..., description="End date in YYYY-MM-DD HH:MM:SS format")
router = APIRouter() router = APIRouter()