Built-in UI Dashboard¶
Profilis includes a real-time dashboard for monitoring application performance, errors, and metrics.
Quick Start¶
from flask import Flask
from profilis.flask.ui import make_ui_blueprint
from profilis.core.stats import StatsStore
app = Flask(__name__)
stats = StatsStore() # 15-minute rolling window
# Mount the dashboard at /_profilis
ui_bp = make_ui_blueprint(stats, ui_prefix="/_profilis")
app.register_blueprint(ui_bp)
# Visit http://localhost:5000/_profilis for the dashboard
Features¶
Real-time Metrics¶
- Request Latency: P50, P95, P99 percentiles
- Throughput: Requests per second
- Error Rates: Error percentage by route
- Response Times: Distribution of response times
Error Tracking¶
- Recent Errors: Last 100 errors with details
- Exception Types: Breakdown by exception class
- Route Analysis: Error rates per endpoint
- Stack Traces: Full error context when available
Performance Monitoring¶
- Database Queries: Query performance metrics
- Function Calls: Profiled function timing
- Resource Usage: Memory and CPU utilization
- Trend Analysis: Performance over time
Dashboard Components¶
Main Dashboard¶
The primary dashboard provides an overview of application health:
┌─────────────────────────────────────────────────────────────┐
│ Profilis Dashboard │
├─────────────────────────────────────────────────────────────┤
│ Requests/sec: 1,234 │ Avg Latency: 45ms │ Errors: 2% │
├─────────────────────────────────────────────────────────────┤
│ [Latency Chart] │ [Throughput Chart] │
│ P50: 25ms │ P95: 120ms │
│ P99: 250ms │ P99.9: 500ms │
├─────────────────────────────────────────────────────────────┤
│ [Error Rate Chart] │ [Route Performance] │
│ Recent Errors: 5 │ Top Routes by Latency │
└─────────────────────────────────────────────────────────────┘
Metrics API¶
Programmatic access to dashboard data:
# Get metrics as JSON
GET /_profilis/metrics.json
# Response format
{
"requests": {
"total": 1234,
"errors": 25,
"error_rate": 0.02,
"latency": {
"p50": 25000000, # 25ms in nanoseconds
"p95": 120000000, # 120ms in nanoseconds
"p99": 250000000 # 250ms in nanoseconds
}
},
"routes": {
"/api/users": {
"count": 456,
"errors": 5,
"avg_latency": 30000000
}
},
"errors": [
{
"ts_ns": 1703123456789000000,
"route": "/api/users",
"status": 500,
"exception_type": "ValueError",
"exception_value": "Invalid user ID"
}
]
}
Configuration¶
Basic Setup¶
from profilis.flask.ui import make_ui_blueprint
from profilis.core.stats import StatsStore
# Create stats store
stats = StatsStore(
window_minutes=15, # Rolling window size
max_errors=100 # Maximum errors to track
)
# Create UI blueprint
ui_bp = make_ui_blueprint(
stats,
ui_prefix="/_profilis" # URL prefix
)
Advanced Configuration¶
# Production configuration with authentication
ui_bp = make_ui_blueprint(
stats,
ui_prefix="/_profilis",
ui_auth_token="secret123", # Bearer token authentication
ui_title="Production Dashboard",
ui_theme="dark" # Dark theme
)
# Custom configuration
ui_bp = make_ui_blueprint(
stats,
ui_prefix="/monitoring",
ui_auth_token="prod-token-456",
ui_title="MyApp Monitoring",
ui_theme="light",
ui_refresh_interval=5000 # 5 second refresh
)
StatsStore Configuration¶
# Configure stats collection
stats = StatsStore(
window_minutes=30, # 30-minute rolling window
max_errors=500, # Track up to 500 errors
max_routes=1000, # Track up to 1000 routes
precision_ns=1000000 # 1ms precision
)
Integration Patterns¶
With Flask Adapter¶
from flask import Flask
from profilis.flask.adapter import ProfilisFlask
from profilis.flask.ui import make_ui_blueprint
from profilis.core.stats import StatsStore
app = Flask(__name__)
# Setup Profilis profiling
exporter = JSONLExporter(dir="./logs")
collector = AsyncCollector(exporter)
profilis = ProfilisFlask(app, collector=collector)
# Add dashboard
stats = StatsStore()
ui_bp = make_ui_blueprint(stats, ui_prefix="/_profilis")
app.register_blueprint(ui_bp)
# Now both profiling and dashboard are available
With Custom Stats¶
from profilis.core.stats import StatsStore
from profilis.core.emitter import Emitter
# Custom stats collection
stats = StatsStore()
emitter = Emitter(collector)
# Record custom metrics
def record_custom_metric(name: str, value: float):
stats.record_custom(name, value)
# Use in your application
@app.route('/api/process')
def process_data():
start_time = time.time_ns()
# Process data...
result = expensive_operation()
# Record custom metric
duration = time.time_ns() - start_time
record_custom_metric("process_duration", duration)
return result
Dashboard Features¶
Real-time Updates¶
The dashboard automatically refreshes to show current metrics:
- Auto-refresh: Configurable refresh intervals
- Live Updates: Real-time metric updates
- Historical Data: Rolling window statistics
- Trend Analysis: Performance over time
Interactive Charts¶
Visual representation of performance data:
- Latency Distribution: Histogram of response times
- Throughput Trends: Requests per second over time
- Error Patterns: Error rates and types
- Route Performance: Endpoint-specific metrics
Error Analysis¶
Comprehensive error tracking and analysis:
- Error Details: Full exception information
- Route Correlation: Errors by endpoint
- Time Analysis: When errors occur
- Pattern Recognition: Common error types
Security and Access Control¶
Authentication¶
# Enable bearer token authentication
ui_bp = make_ui_blueprint(
stats,
ui_prefix="/_profilis",
ui_auth_token="your-secret-token"
)
# Access with Authorization header
# Authorization: Bearer your-secret-token
Access Control¶
# Custom authentication middleware
from functools import wraps
from flask import request, abort
def require_auth(f):
@wraps(f)
def decorated_function(*args, **kwargs):
token = request.headers.get('Authorization')
if not token or token != 'Bearer your-token':
abort(401)
return f(*args, **kwargs)
return decorated_function
# Apply to dashboard routes
@app.route('/_profilis')
@require_auth
def dashboard():
return render_template('dashboard.html')
Production Security¶
# Production configuration
ui_bp = make_ui_blueprint(
stats,
ui_prefix="/_profilis",
ui_auth_token=os.environ.get('PROFILIS_TOKEN'),
ui_https_only=True,
ui_cors_origins=['https://yourdomain.com']
)
Customization¶
Custom Themes¶
# Custom CSS styling
custom_css = """
.dashboard-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.metric-card {
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
"""
ui_bp = make_ui_blueprint(
stats,
ui_prefix="/_profilis",
ui_custom_css=custom_css
)
Custom Metrics¶
# Extend StatsStore for custom metrics
class CustomStatsStore(StatsStore):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.custom_metrics = {}
def record_custom(self, name: str, value: float):
"""Record custom metric"""
if name not in self.custom_metrics:
self.custom_metrics[name] = []
self.custom_metrics[name].append({
'ts_ns': time.time_ns(),
'value': value
})
def get_custom_metrics(self):
"""Get custom metrics summary"""
summary = {}
for name, values in self.custom_metrics.items():
if values:
summary[name] = {
'count': len(values),
'avg': sum(v['value'] for v in values) / len(values),
'min': min(v['value'] for v in values),
'max': max(v['value'] for v in values)
}
return summary
# Use custom stats store
custom_stats = CustomStatsStore()
ui_bp = make_ui_blueprint(custom_stats, ui_prefix="/_profilis")
Monitoring and Alerting¶
Health Checks¶
@app.route('/_profilis/health')
def dashboard_health():
"""Check dashboard health"""
return {
"status": "healthy",
"stats_store": {
"window_minutes": stats.window_minutes,
"total_requests": stats.total_requests,
"total_errors": stats.total_errors,
"error_rate": stats.error_rate
},
"collector": {
"queue_size": collector.queue.qsize(),
"queue_max": collector.queue.maxsize
}
}
Integration with External Monitoring¶
# Prometheus metrics endpoint
@app.route('/_profilis/metrics')
def prometheus_metrics():
"""Prometheus-formatted metrics"""
metrics = []
# Request metrics
metrics.append(f"profilis_requests_total {stats.total_requests}")
metrics.append(f"profilis_errors_total {stats.total_errors}")
metrics.append(f"profilis_error_rate {stats.error_rate}")
# Latency metrics
if stats.latency_percentiles:
p50 = stats.latency_percentiles.get(50, 0)
p95 = stats.latency_percentiles.get(95, 0)
p99 = stats.latency_percentiles.get(99, 0)
metrics.append(f"profilis_latency_p50 {p50}")
metrics.append(f"profilis_latency_p95 {p95}")
metrics.append(f"profilis_latency_p99 {p99}")
return '\n'.join(metrics), 200, {'Content-Type': 'text/plain'}
Troubleshooting¶
Common Issues¶
- Dashboard Not Loading: Check blueprint registration and routes
- No Data Displayed: Verify StatsStore is receiving data
- Authentication Errors: Check bearer token configuration
- Performance Issues: Monitor dashboard refresh intervals
Debug Mode¶
import os
os.environ['PROFILIS_DEBUG'] = '1'
# This will enable debug logging for the dashboard
ui_bp = make_ui_blueprint(stats, ui_prefix="/_profilis")
Performance Optimization¶
# Optimize for high-traffic applications
stats = StatsStore(
window_minutes=5, # Shorter window for real-time updates
max_errors=50, # Limit error storage
max_routes=100 # Limit route tracking
)
# Reduce refresh frequency
ui_bp = make_ui_blueprint(
stats,
ui_prefix="/_profilis",
ui_refresh_interval=10000 # 10 second refresh
)
Best Practices¶
- Use Appropriate Window Sizes: Balance real-time updates with memory usage
- Implement Authentication: Always secure dashboard access in production
- Monitor Dashboard Performance: Watch for dashboard impact on application
- Regular Cleanup: Monitor StatsStore memory usage
- Custom Metrics: Extend with application-specific monitoring
- Integration: Connect with existing monitoring infrastructure