Skip to content

Commit cd98107

Browse files
committed
✨ feat: enhance metrics calculations and logging
✨ feat: enhance metrics calculations and logging ✨ Improvements: - Refined calculation of days active to ensure a minimum of 1 day. - Added calculation for average commits and costs per day. - Defaulted metrics to reasonable values in case of calculation failure. 🐛 Bug Fixes: - Fixed potential errors in metric filtering logic. - Improved logging messages for clarity on metric loading failures. ♻️ Refactoring: - Streamlined token and cost accumulation for model stats. - Ensured at least one time unit is always displayed in output. Enhanced metrics calculations and improved logging for better reliability.
1 parent cc330ab commit cd98107

File tree

1 file changed

+27
-13
lines changed

1 file changed

+27
-13
lines changed

commitloom/services/metrics.py

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -268,14 +268,22 @@ def get_statistics(self) -> dict[str, Any]:
268268
try:
269269
first = datetime.fromisoformat(stats["first_used_at"])
270270
last = datetime.fromisoformat(stats["last_used_at"])
271-
days_active = (last - first).days + 1
271+
272+
# Calculate days active (at least 1)
273+
days_active = max(1, (last.date() - first.date()).days + 1)
272274
stats["days_active"] = days_active
273275

274276
if days_active > 0:
277+
# Calculate average commits per day
275278
stats["avg_commits_per_day"] = stats["total_commits"] / days_active
279+
280+
# Calculate average cost per day (ensure it's not zero)
276281
stats["avg_cost_per_day"] = stats["total_cost_in_eur"] / days_active
277282
except (ValueError, TypeError):
278-
pass
283+
# Default values if calculation fails
284+
stats["days_active"] = 1
285+
stats["avg_commits_per_day"] = stats["total_commits"]
286+
stats["avg_cost_per_day"] = stats["total_cost_in_eur"]
279287

280288
return stats
281289

@@ -301,10 +309,12 @@ def get_recent_metrics(self, days: int = 30) -> list[dict[str, Any]]:
301309
cutoff_date = datetime.now() - timedelta(days=days)
302310
cutoff_str = cutoff_date.isoformat()
303311

304-
metrics_list = [m for m in all_metrics if m.get("timestamp", "") >= cutoff_str]
312+
for metric in all_metrics:
313+
if "timestamp" in metric and metric["timestamp"] >= cutoff_str:
314+
metrics_list.append(metric)
305315

306316
return metrics_list
307-
except (json.JSONDecodeError, FileNotFoundError, KeyError) as e:
317+
except (json.JSONDecodeError, FileNotFoundError) as e:
308318
logger.warning(f"Failed to load metrics: {str(e)}")
309319
return []
310320

@@ -374,17 +384,19 @@ def get_model_usage_stats(self) -> dict[str, dict[str, Any]]:
374384
}
375385

376386
model_stats[model_name]["commits"] += 1
377-
model_stats[model_name]["tokens"] += metric.get("tokens_used", 0)
378-
model_stats[model_name]["cost"] += metric.get("cost_in_eur", 0.0)
387+
tokens = metric.get("tokens_used", 0)
388+
model_stats[model_name]["tokens"] += tokens
389+
cost = metric.get("cost_in_eur", 0.0)
390+
model_stats[model_name]["cost"] += cost
379391

380392
# Calculate averages
381-
for _, stats in model_stats.items():
393+
for model, stats in model_stats.items():
382394
if stats["commits"] > 0:
383395
stats["avg_tokens_per_commit"] = stats["tokens"] / stats["commits"]
384396

385397
return model_stats
386398
except (json.JSONDecodeError, FileNotFoundError, KeyError) as e:
387-
logger.warning(f"Failed to load metrics for model usage stats: {str(e)}")
399+
logger.warning(f"Failed to load metrics for model stats: {str(e)}")
388400
return {}
389401

390402
def get_repository_stats(self) -> dict[str, dict[str, Any]]:
@@ -445,12 +457,14 @@ def _format_timedelta(td: timedelta) -> str:
445457
parts.append(f"{days} day{'s' if days != 1 else ''}")
446458
if hours > 0:
447459
parts.append(f"{hours} hour{'s' if hours != 1 else ''}")
448-
if minutes > 0:
460+
if minutes > 0 or (days == 0 and hours == 0):
449461
parts.append(f"{minutes} minute{'s' if minutes != 1 else ''}")
450-
if seconds > 0 and not parts: # Only show seconds if no larger units
451-
parts.append(f"{seconds} second{'s' if seconds != 1 else ''}")
452-
453-
return ", ".join(parts)
462+
463+
# Always include at least one unit (default to minutes if everything is 0)
464+
if not parts:
465+
parts.append("0 minutes")
466+
467+
return " ".join(parts)
454468

455469

456470
# Singleton instance

0 commit comments

Comments
 (0)