1d and 1m

This commit is contained in:
weicao 2025-09-23 16:23:59 +08:00
parent 6fc505ebb2
commit 5b521c4ec4
2 changed files with 100 additions and 43 deletions

View File

@ -92,6 +92,7 @@ class StarRocksMetricsService:
self,
product_id: str,
metric_name: str,
step: str,
start_date: Union[str, date],
end_date: Union[str, date]
) -> List[Dict[str, Any]]:
@ -162,6 +163,14 @@ class StarRocksMetricsService:
else:
end_dt = end_date
# Normalize and validate step (default '1d')
step = step or '1d'
if step not in {"1d", "1m"}:
raise HTTPException(
status_code=400,
detail="Invalid step. Supported values are '1d' and '1m'"
)
# Validate date range
if start_dt >= end_dt:
raise HTTPException(
@ -191,7 +200,14 @@ class StarRocksMetricsService:
)
# Parse the result and format it
formatted_data = self._format_query_result(result, metric_name, product_id, start_dt, end_dt)
formatted_data = self._format_query_result(
starrocks_result=result,
metric_name=metric_name,
product_id=product_id,
step=step,
start_date=start_dt,
end_date=end_dt
)
await self.module_logger.log_info(
f"Successfully queried metric '{metric_name}' with {len(formatted_data)} data points")
@ -201,7 +217,7 @@ class StarRocksMetricsService:
await self.module_logger.log_error(f"Failed to query metric '{metric_name}': {e}")
raise
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]]:
def _format_query_result(self, starrocks_result: List[Dict[str, Any]], metric_name: str, product_id: str, step: str, start_date: datetime, end_date: datetime) -> List[Dict[str, Any]]:
"""
Format StarRocks query result into the required format and fill missing dates with 0 values.
@ -219,25 +235,42 @@ class StarRocksMetricsService:
result_dict = {}
for row in starrocks_result:
# Format the date
# Normalize the date according to step granularity
date_value = row.get("date")
if date_value:
if isinstance(date_value, str):
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:
date_str = str(date_value)
else:
if not date_value:
continue
def month_start(d: datetime) -> datetime:
return datetime(d.year, d.month, 1)
# Parse and normalize
if isinstance(date_value, str):
parsed_dt = None
for fmt in ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d'):
try:
parsed_dt = datetime.strptime(date_value, fmt)
break
except ValueError:
continue
if parsed_dt is None:
date_str = str(date_value)
else:
if step == '1m':
date_str = month_start(parsed_dt).strftime('%Y-%m-01 00:00:00')
else:
date_str = parsed_dt.strftime('%Y-%m-%d') + ' 00:00:00'
else:
if hasattr(date_value, 'strftime'):
dt_obj = date_value
if step == '1m':
date_str = month_start(dt_obj).strftime('%Y-%m-01 00:00:00')
else:
if hasattr(dt_obj, 'date'):
dt_obj = dt_obj.date()
date_str = dt_obj.strftime('%Y-%m-%d') + ' 00:00:00'
else:
date_str = str(date_value)
# Get the value
value = row.get("value", 0)
if value is None:
@ -256,32 +289,54 @@ class StarRocksMetricsService:
"labels": labels
}
# Generate complete date range and fill missing dates with 0
# Generate complete range and fill missing points 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
})
current_date += timedelta(days=1)
if step == '1d':
current_dt = datetime(start_date.year, start_date.month, start_date.day)
end_dt_exclusive = datetime(end_date.year, end_date.month, end_date.day)
while current_dt < end_dt_exclusive:
date_str = current_dt.strftime('%Y-%m-%d') + ' 00:00:00'
if date_str in result_dict:
formatted_data.append(result_dict[date_str])
else:
labels = {
"product_id": product_id,
"metric_type": metric_name
}
formatted_data.append({
"date": date_str,
"value": 0,
"metric": metric_name,
"labels": labels
})
current_dt += timedelta(days=1)
elif step == '1m':
def month_start(d: datetime) -> datetime:
return datetime(d.year, d.month, 1)
def add_one_month(d: datetime) -> datetime:
year = d.year + (1 if d.month == 12 else 0)
month = 1 if d.month == 12 else d.month + 1
return datetime(year, month, 1)
current_dt = month_start(start_date)
end_month_exclusive = month_start(end_date)
while current_dt < end_month_exclusive:
date_str = current_dt.strftime('%Y-%m-01 00:00:00')
if date_str in result_dict:
formatted_data.append(result_dict[date_str])
else:
labels = {
"product_id": product_id,
"metric_type": metric_name
}
formatted_data.append({
"date": date_str,
"value": 0,
"metric": metric_name,
"labels": labels
})
current_dt = add_one_month(current_dt)
return formatted_data

View File

@ -26,6 +26,7 @@ class MetricQueryRequest(BaseModel):
"""Request model for metric 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")
step: str = Field(..., description="Aggregation step, e.g., 1d or 1m")
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 HH:MM:SS format")
@ -53,6 +54,7 @@ async def metrics_query(
data_points = await starrocks_service.query_metric_by_time_range(
product_id=request.product_id,
metric_name=request.metric_name,
step=request.step,
start_date=request.start_date,
end_date=request.end_date
)