Spaces:
Running
Running
""" | |
Dashboard Performance Layout. | |
This module provides detailed performance monitoring layout including | |
latency analysis, throughput metrics, and component performance breakdown. | |
""" | |
from typing import Dict, Any, List | |
from dash import html, dcc | |
import plotly.graph_objs as go | |
import plotly.express as px | |
def create_performance_layout(dashboard_data: Dict[str, Any]) -> html.Div: | |
""" | |
Create performance monitoring dashboard layout. | |
Args: | |
dashboard_data: Real-time dashboard data | |
Returns: | |
Performance layout component | |
""" | |
performance = dashboard_data.get("performance", {}) | |
time_series = dashboard_data.get("time_series", {}) | |
components = dashboard_data.get("components", {}) | |
backends = dashboard_data.get("backends", {}) | |
# Performance summary | |
summary_section = _create_performance_summary(performance) | |
# Time series charts | |
time_series_section = _create_time_series_section(time_series) | |
# Component performance | |
component_section = _create_component_performance_section(components) | |
# Backend performance | |
backend_section = _create_backend_performance_section(backends) | |
return html.Div([ | |
summary_section, | |
time_series_section, | |
component_section, | |
backend_section | |
], className="performance-layout") | |
def _create_performance_summary(performance: Dict[str, Any]) -> html.Div: | |
"""Create performance summary section.""" | |
latency_percentiles = performance.get("latency_percentiles", {}) | |
throughput = performance.get("throughput", {}) | |
component_latencies = performance.get("component_latencies", {}) | |
# Key performance metrics | |
perf_cards = [ | |
_create_perf_card( | |
"P50 Latency", | |
f"{latency_percentiles.get('p50', 0):.1f}ms", | |
"📊", | |
"good" if latency_percentiles.get('p50', 0) < 200 else "warning" | |
), | |
_create_perf_card( | |
"P95 Latency", | |
f"{latency_percentiles.get('p95', 0):.1f}ms", | |
"📈", | |
"good" if latency_percentiles.get('p95', 0) < 500 else "warning" | |
), | |
_create_perf_card( | |
"P99 Latency", | |
f"{latency_percentiles.get('p99', 0):.1f}ms", | |
"🔴", | |
"good" if latency_percentiles.get('p99', 0) < 1000 else "warning" | |
), | |
_create_perf_card( | |
"Current QPS", | |
f"{throughput.get('current_qps', 0):.2f}", | |
"⚡", | |
"good" | |
), | |
_create_perf_card( | |
"Peak QPS", | |
f"{throughput.get('peak_qps', 0):.2f}", | |
"🚀", | |
"good" | |
) | |
] | |
return html.Div([ | |
html.H2("Performance Summary", className="section-title"), | |
html.Div(perf_cards, className="perf-cards") | |
], className="performance-summary") | |
def _create_perf_card(title: str, value: str, icon: str, status: str) -> html.Div: | |
"""Create performance metric card.""" | |
status_colors = { | |
"good": "#4CAF50", | |
"warning": "#FF9800", | |
"critical": "#F44336" | |
} | |
return html.Div([ | |
html.Div([ | |
html.Span(icon, className="perf-icon"), | |
html.Div([ | |
html.H3(value, className="perf-value", style={"color": status_colors.get(status, "#333")}), | |
html.P(title, className="perf-title") | |
], className="perf-text") | |
], className="perf-content") | |
], className="perf-card") | |
def _create_time_series_section(time_series: Dict[str, Any]) -> html.Div: | |
"""Create time series performance charts.""" | |
latency_chart = _create_latency_time_series(time_series) | |
qps_chart = _create_qps_time_series(time_series) | |
success_rate_chart = _create_success_rate_time_series(time_series) | |
return html.Div([ | |
html.H3("Performance Trends", className="subsection-title"), | |
# Latency over time | |
html.Div([ | |
dcc.Graph(figure=latency_chart, config={'displayModeBar': False}) | |
], className="chart-container-full"), | |
# QPS and Success Rate | |
html.Div([ | |
html.Div([ | |
dcc.Graph(figure=qps_chart, config={'displayModeBar': False}) | |
], className="chart-container"), | |
html.Div([ | |
dcc.Graph(figure=success_rate_chart, config={'displayModeBar': False}) | |
], className="chart-container") | |
], className="charts-row") | |
], className="time-series-section") | |
def _create_latency_time_series(time_series: Dict[str, Any]) -> go.Figure: | |
"""Create latency time series chart.""" | |
timestamps = time_series.get("timestamps", []) | |
latencies = time_series.get("latency", []) | |
fig = go.Figure() | |
if timestamps and latencies: | |
fig.add_trace(go.Scatter( | |
x=timestamps, | |
y=latencies, | |
mode='lines', | |
name='Latency', | |
line=dict(color='#2E86AB', width=2), | |
fill='tonexty', | |
fillcolor='rgba(46, 134, 171, 0.1)' | |
)) | |
fig.update_layout( | |
title="Latency Over Time", | |
xaxis_title="Time", | |
yaxis_title="Latency (ms)", | |
height=400, | |
margin=dict(l=50, r=50, t=50, b=50), | |
plot_bgcolor='rgba(0,0,0,0)', | |
paper_bgcolor='rgba(0,0,0,0)', | |
showlegend=False | |
) | |
return fig | |
def _create_qps_time_series(time_series: Dict[str, Any]) -> go.Figure: | |
"""Create QPS time series chart.""" | |
timestamps = time_series.get("timestamps", []) | |
qps_values = time_series.get("qps", []) | |
fig = go.Figure() | |
if timestamps and qps_values: | |
fig.add_trace(go.Scatter( | |
x=timestamps, | |
y=qps_values, | |
mode='lines+markers', | |
name='QPS', | |
line=dict(color='#4CAF50', width=3), | |
marker=dict(size=4) | |
)) | |
fig.update_layout( | |
title="Queries Per Second", | |
xaxis_title="Time", | |
yaxis_title="QPS", | |
height=300, | |
margin=dict(l=50, r=50, t=50, b=50), | |
plot_bgcolor='rgba(0,0,0,0)', | |
paper_bgcolor='rgba(0,0,0,0)', | |
showlegend=False | |
) | |
return fig | |
def _create_success_rate_time_series(time_series: Dict[str, Any]) -> go.Figure: | |
"""Create success rate time series chart.""" | |
timestamps = time_series.get("timestamps", []) | |
success_rates = time_series.get("success_rate", []) | |
fig = go.Figure() | |
if timestamps and success_rates: | |
fig.add_trace(go.Scatter( | |
x=timestamps, | |
y=success_rates, | |
mode='lines', | |
name='Success Rate', | |
line=dict(color='#FF9800', width=3), | |
fill='tozeroy', | |
fillcolor='rgba(255, 152, 0, 0.1)' | |
)) | |
fig.update_layout( | |
title="Success Rate (%)", | |
xaxis_title="Time", | |
yaxis_title="Success Rate (%)", | |
yaxis=dict(range=[0, 100]), | |
height=300, | |
margin=dict(l=50, r=50, t=50, b=50), | |
plot_bgcolor='rgba(0,0,0,0)', | |
paper_bgcolor='rgba(0,0,0,0)', | |
showlegend=False | |
) | |
return fig | |
def _create_component_performance_section(components: Dict[str, Any]) -> html.Div: | |
"""Create component performance analysis section.""" | |
if not components: | |
return html.Div([ | |
html.H3("Component Performance", className="subsection-title"), | |
html.P("No component data available", className="no-data") | |
]) | |
# Component metrics table | |
component_table = _create_component_table(components) | |
# Component latency comparison chart | |
component_chart = _create_component_comparison_chart(components) | |
return html.Div([ | |
html.H3("Component Performance", className="subsection-title"), | |
# Component comparison chart | |
html.Div([ | |
dcc.Graph(figure=component_chart, config={'displayModeBar': False}) | |
], className="chart-container-full"), | |
# Component details table | |
component_table | |
], className="component-performance-section") | |
def _create_component_table(components: Dict[str, Any]) -> html.Div: | |
"""Create component performance table.""" | |
table_rows = [] | |
for component_name, metrics in components.items(): | |
status = metrics.get("status", "unknown") | |
status_color = { | |
"healthy": "#4CAF50", | |
"warning": "#FF9800", | |
"error": "#F44336", | |
"unknown": "#9E9E9E" | |
}.get(status, "#9E9E9E") | |
row = html.Tr([ | |
html.Td(component_name, className="component-name-cell"), | |
html.Td([ | |
html.Span("●", style={"color": status_color}), | |
html.Span(f" {status.title()}") | |
], className="status-cell"), | |
html.Td(f"{metrics.get('total_calls', 0):,}", className="number-cell"), | |
html.Td(f"{metrics.get('avg_latency_ms', 0):.1f}ms", className="number-cell"), | |
html.Td(f"{metrics.get('error_rate', 0):.1f}%", className="number-cell") | |
]) | |
table_rows.append(row) | |
table = html.Table([ | |
html.Thead([ | |
html.Tr([ | |
html.Th("Component"), | |
html.Th("Status"), | |
html.Th("Total Calls"), | |
html.Th("Avg Latency"), | |
html.Th("Error Rate") | |
]) | |
]), | |
html.Tbody(table_rows) | |
], className="component-table") | |
return table | |
def _create_component_comparison_chart(components: Dict[str, Any]) -> go.Figure: | |
"""Create component performance comparison chart.""" | |
component_names = list(components.keys()) | |
latencies = [metrics.get("avg_latency_ms", 0) for metrics in components.values()] | |
error_rates = [metrics.get("error_rate", 0) for metrics in components.values()] | |
fig = go.Figure() | |
# Latency bars | |
fig.add_trace(go.Bar( | |
x=component_names, | |
y=latencies, | |
name='Latency (ms)', | |
marker=dict(color='#2E86AB'), | |
yaxis='y1' | |
)) | |
# Error rate line | |
fig.add_trace(go.Scatter( | |
x=component_names, | |
y=error_rates, | |
name='Error Rate (%)', | |
mode='lines+markers', | |
line=dict(color='#F44336', width=3), | |
marker=dict(size=8), | |
yaxis='y2' | |
)) | |
fig.update_layout( | |
title="Component Latency vs Error Rate", | |
xaxis_title="Component", | |
yaxis=dict( | |
title="Latency (ms)", | |
titlefont=dict(color='#2E86AB'), | |
tickfont=dict(color='#2E86AB') | |
), | |
yaxis2=dict( | |
title="Error Rate (%)", | |
titlefont=dict(color='#F44336'), | |
tickfont=dict(color='#F44336'), | |
anchor='x', | |
overlaying='y', | |
side='right' | |
), | |
height=400, | |
margin=dict(l=50, r=80, t=50, b=50), | |
plot_bgcolor='rgba(0,0,0,0)', | |
paper_bgcolor='rgba(0,0,0,0)', | |
legend=dict(x=0.01, y=0.99) | |
) | |
return fig | |
def _create_backend_performance_section(backends: Dict[str, Any]) -> html.Div: | |
"""Create backend performance section.""" | |
if not backends: | |
return html.Div([ | |
html.H3("Backend Performance", className="subsection-title"), | |
html.P("No backend data available", className="no-data") | |
]) | |
# Backend comparison chart | |
backend_chart = _create_backend_comparison_chart(backends) | |
# Backend metrics cards | |
backend_cards = [] | |
for backend_name, metrics in backends.items(): | |
success_rate = metrics.get("success_rate", 0) | |
total_queries = metrics.get("total_queries", 0) | |
avg_latency = metrics.get("avg_latency_ms", 0) | |
status = "good" if success_rate > 95 else "warning" if success_rate > 80 else "critical" | |
card = html.Div([ | |
html.H4(f"{backend_name.title()} Backend", className="backend-title"), | |
html.Div([ | |
html.Div([ | |
html.Span(f"{total_queries:,}", className="backend-metric-value"), | |
html.Span("Total Queries", className="backend-metric-label") | |
], className="backend-metric"), | |
html.Div([ | |
html.Span(f"{success_rate:.1f}%", className="backend-metric-value"), | |
html.Span("Success Rate", className="backend-metric-label") | |
], className="backend-metric"), | |
html.Div([ | |
html.Span(f"{avg_latency:.1f}ms", className="backend-metric-value"), | |
html.Span("Avg Latency", className="backend-metric-label") | |
], className="backend-metric") | |
], className="backend-metrics") | |
], className="backend-card") | |
backend_cards.append(card) | |
return html.Div([ | |
html.H3("Backend Performance", className="subsection-title"), | |
# Backend cards | |
html.Div(backend_cards, className="backend-cards"), | |
# Backend comparison chart | |
html.Div([ | |
dcc.Graph(figure=backend_chart, config={'displayModeBar': False}) | |
], className="chart-container-full") | |
], className="backend-performance-section") | |
def _create_backend_comparison_chart(backends: Dict[str, Any]) -> go.Figure: | |
"""Create backend performance comparison chart.""" | |
backend_names = list(backends.keys()) | |
success_rates = [metrics.get("success_rate", 0) for metrics in backends.values()] | |
latencies = [metrics.get("avg_latency_ms", 0) for metrics in backends.values()] | |
fig = go.Figure() | |
# Success rate bars | |
fig.add_trace(go.Bar( | |
x=backend_names, | |
y=success_rates, | |
name='Success Rate (%)', | |
marker=dict(color='#4CAF50'), | |
yaxis='y1' | |
)) | |
# Latency line | |
fig.add_trace(go.Scatter( | |
x=backend_names, | |
y=latencies, | |
name='Latency (ms)', | |
mode='lines+markers', | |
line=dict(color='#2E86AB', width=3), | |
marker=dict(size=8), | |
yaxis='y2' | |
)) | |
fig.update_layout( | |
title="Backend Success Rate vs Latency", | |
xaxis_title="Backend", | |
yaxis=dict( | |
title="Success Rate (%)", | |
titlefont=dict(color='#4CAF50'), | |
tickfont=dict(color='#4CAF50'), | |
range=[0, 100] | |
), | |
yaxis2=dict( | |
title="Latency (ms)", | |
titlefont=dict(color='#2E86AB'), | |
tickfont=dict(color='#2E86AB'), | |
anchor='x', | |
overlaying='y', | |
side='right' | |
), | |
height=400, | |
margin=dict(l=50, r=80, t=50, b=50), | |
plot_bgcolor='rgba(0,0,0,0)', | |
paper_bgcolor='rgba(0,0,0,0)', | |
legend=dict(x=0.01, y=0.99) | |
) | |
return fig |