Skip to main content

Metrics Dashboard

The Email Assistant includes a comprehensive metrics dashboard for tracking performance, API usage, and errors.

Overviewโ€‹

Tracked Metricsโ€‹

Performance Metricsโ€‹

MetricDescriptionPeriods
Total Emails ProcessedCount of processed emails24h, 7d, All
Average Execution TimeScript execution duration24h, 7d, All
Cache Hit RatePercentage of cache hits24h, 7d, All
Success RatePercentage of successful runs24h, 7d, All

API Metricsโ€‹

MetricDescriptionPeriods
API Calls MadeNumber of Gemini API calls24h, 7d, All
Average Response TimeAPI call latency24h, 7d, All
Estimated API CostCost at $0.01/call24h, 7d, All

System Metricsโ€‹

MetricDescriptionPeriods
Script Run CountNumber of executions24h, 7d, All
Error CountErrors in period24h, 7d, All
Cache UtilizationCurrent vs max sizeCurrent
Recent ErrorsLast 10 errorsN/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)}`;
}