Metrics Dashboard
The Email Assistant includes a comprehensive metrics dashboard for tracking performance, API usage, and errors.
Overviewโ
Tracked Metricsโ
Performance Metricsโ
| Metric | Description | Periods |
|---|---|---|
| Total Emails Processed | Count of processed emails | 24h, 7d, All |
| Average Execution Time | Script execution duration | 24h, 7d, All |
| Cache Hit Rate | Percentage of cache hits | 24h, 7d, All |
| Success Rate | Percentage of successful runs | 24h, 7d, All |
API Metricsโ
| Metric | Description | Periods |
|---|---|---|
| API Calls Made | Number of Gemini API calls | 24h, 7d, All |
| Average Response Time | API call latency | 24h, 7d, All |
| Estimated API Cost | Cost at $0.01/call | 24h, 7d, All |
System Metricsโ
| Metric | Description | Periods |
|---|---|---|
| Script Run Count | Number of executions | 24h, 7d, All |
| Error Count | Errors in period | 24h, 7d, All |
| Cache Utilization | Current vs max size | Current |
| Recent Errors | Last 10 errors | N/A |
Dashboard Interfaceโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๐ Metrics Dashboard โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ [Last 24 Hours] [Last 7 Days] [All Time] โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โ โ ๐ง 45 โ โ ๐ฏ 98.2% โ โ ๐ก 127 โ โ
โ โ Emails โ โ Success Rate โ โ API Calls โ โ
โ โ Processed โ โ โ โ โ โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โ โ โก 8.2s โ โ ๐พ 87.5% โ โ ๐ฐ $1.27 โ โ
โ โ Avg Time โ โ Cache Hit โ โ Est. Cost โ โ
โ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ ๐ Emails by Category (All Time) โ
โ โ
โ Need-Action โโโโโโโโโโโโโโโโโโโโ 45% โ
โ FYI โโโโโโโโโโโโโโ 30% โ
โ Newsletter โโโโโโโโ 15% โ
โ Promotional โโโ 7% โ
โ Social โ 3% โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ ๏ธ Recent Errors โ
โ โ
โ 2024-12-22 09:15:23 | gemini_utils | APIError โ
โ Rate limit exceeded, retrying... โ
โ โ
โ 2024-12-21 14:30:45 | email_utils | ConnectionError โ
โ Failed to connect to Gmail API โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Implementationโ
Metrics Collectionโ
# metrics_utils.py
import sqlite3
from datetime import datetime
class MetricsTracker:
def __init__(self, db_path: str = 'data/metrics/metrics.db'):
self.db_path = db_path
self._init_db()
def _init_db(self):
"""Initialize SQLite database."""
with sqlite3.connect(self.db_path) as conn:
conn.execute('''
CREATE TABLE IF NOT EXISTS metrics (
id INTEGER PRIMARY KEY,
timestamp TEXT NOT NULL,
metric_type TEXT NOT NULL,
value REAL NOT NULL,
metadata TEXT
)
''')
def record(self, metric_type: str, value: float, metadata: dict = None):
"""Record a metric."""
with sqlite3.connect(self.db_path) as conn:
conn.execute(
'INSERT INTO metrics (timestamp, metric_type, value, metadata) VALUES (?, ?, ?, ?)',
(datetime.now().isoformat(), metric_type, value, json.dumps(metadata))
)
Recording Metricsโ
# During email processing
metrics = MetricsTracker()
# Record execution time
start = time.time()
process_emails()
elapsed = time.time() - start
metrics.record('execution_time', elapsed)
# Record API call
metrics.record('api_call', 1, {'model': 'gemini-2.5-flash-lite'})
# Record cache hit
metrics.record('cache_hit', 1 if cached else 0)
# Record error
metrics.record('error', 1, {'type': 'APIError', 'message': str(e)})
API Endpointsโ
# server.py
@app.route('/api/metrics')
def get_metrics():
"""Get all metrics."""
period = request.args.get('period', '24h')
metrics = {
'emails_processed': get_count('email_processed', period),
'api_calls': get_count('api_call', period),
'cache_hit_rate': get_rate('cache_hit', period),
'avg_execution_time': get_average('execution_time', period),
'success_rate': get_rate('success', period),
'estimated_cost': get_count('api_call', period) * 0.01,
}
return jsonify(metrics)
@app.route('/api/errors')
def get_errors():
"""Get recent errors."""
errors = get_recent('error', limit=10)
return jsonify(errors)
Querying Metricsโ
By Time Periodโ
def get_count(metric_type: str, period: str) -> int:
"""Get metric count for period."""
cutoff = get_period_cutoff(period)
with sqlite3.connect(db_path) as conn:
result = conn.execute('''
SELECT COUNT(*) FROM metrics
WHERE metric_type = ? AND timestamp > ?
''', (metric_type, cutoff.isoformat()))
return result.fetchone()[0]
def get_period_cutoff(period: str) -> datetime:
"""Get datetime cutoff for period."""
now = datetime.now()
if period == '24h':
return now - timedelta(hours=24)
elif period == '7d':
return now - timedelta(days=7)
else:
return datetime.min # All time
Aggregationsโ
def get_average(metric_type: str, period: str) -> float:
"""Get average value for period."""
cutoff = get_period_cutoff(period)
with sqlite3.connect(db_path) as conn:
result = conn.execute('''
SELECT AVG(value) FROM metrics
WHERE metric_type = ? AND timestamp > ?
''', (metric_type, cutoff.isoformat()))
return result.fetchone()[0] or 0.0
def get_rate(metric_type: str, period: str) -> float:
"""Get success/hit rate for period."""
cutoff = get_period_cutoff(period)
with sqlite3.connect(db_path) as conn:
result = conn.execute('''
SELECT AVG(value) * 100 FROM metrics
WHERE metric_type = ? AND timestamp > ?
''', (metric_type, cutoff.isoformat()))
return result.fetchone()[0] or 0.0
Error Trackingโ
Error Recordingโ
def record_error(error: Exception, module: str):
"""Record error with context."""
metrics.record('error', 1, {
'type': type(error).__name__,
'message': str(error),
'module': module,
'traceback': traceback.format_exc(),
})
Error Displayโ
def get_recent_errors(limit: int = 10) -> list[dict]:
"""Get recent errors for display."""
with sqlite3.connect(db_path) as conn:
result = conn.execute('''
SELECT timestamp, metadata FROM metrics
WHERE metric_type = 'error'
ORDER BY timestamp DESC
LIMIT ?
''', (limit,))
return [
{
'timestamp': row[0],
**json.loads(row[1])
}
for row in result.fetchall()
]
Cost Estimationโ
# Pricing: $0.01 per API call (approximate)
API_COST_PER_CALL = 0.01
def get_estimated_cost(period: str) -> float:
"""Calculate estimated API cost."""
api_calls = get_count('api_call', period)
return api_calls * API_COST_PER_CALL
Dashboard Tabsโ
Frontend Implementationโ
// script.js
const periods = ['24h', '7d', 'all'];
let currentPeriod = '24h';
async function loadMetrics(period) {
currentPeriod = period;
updateTabStyles();
const response = await fetch(`/api/metrics?period=${period}`);
const metrics = await response.json();
updateDashboard(metrics);
}
function updateDashboard(metrics) {
document.getElementById('emails-count').textContent = metrics.emails_processed;
document.getElementById('api-calls').textContent = metrics.api_calls;
document.getElementById('success-rate').textContent = `${metrics.success_rate.toFixed(1)}%`;
document.getElementById('avg-time').textContent = `${metrics.avg_execution_time.toFixed(1)}s`;
document.getElementById('cache-rate').textContent = `${metrics.cache_hit_rate.toFixed(1)}%`;
document.getElementById('est-cost').textContent = `$${metrics.estimated_cost.toFixed(2)}`;
}