import streamlit as st import pandas as pd import plotly.graph_objects as go import pickle from statsmodels.tsa.arima.model import ARIMA import os from datetime import datetime, timedelta # Page configuration with custom theme st.set_page_config( page_title="ERROR Log Analytics Dashboard", layout="wide", initial_sidebar_state="expanded" ) # Custom CSS to enhance the UI st.markdown(""" """, unsafe_allow_html=True) # Sidebar for controls and information with st.sidebar: st.image("https://www.svgrepo.com/show/374111/log.svg", width=100) st.markdown("## ERROR Log Analytics") st.markdown("---") st.markdown("### Model Configuration") # File selection (keeping default path but making it look configurable) file_path = st.text_input("Log file path", value="augmented_logs.csv") # ARIMA parameters st.markdown("### ARIMA Parameters") p = st.slider("Auto-regression (p)", min_value=0, max_value=5, value=1) d = st.slider("Differencing (d)", min_value=0, max_value=2, value=1) q = st.slider("Moving Average (q)", min_value=0, max_value=5, value=1) # Forecast range st.markdown("### Forecast Settings") forecast_days = st.slider("Forecast Horizon (days)", min_value=1, max_value=30, value=7) st.markdown("---") st.markdown("*This dashboard analyzes ERROR logs and forecasts future error rates using ARIMA modeling.*") # Main content st.markdown('
📊 ERROR Log Analysis & Forecasting
', unsafe_allow_html=True) if not os.path.exists(file_path): st.error(f"❌ File not found: {file_path}") else: try: # Main app container with st.container(): # Load and prep data df = pd.read_csv(file_path) df['timestamp'] = pd.to_datetime(df['timestamp']) df['date'] = df['timestamp'].dt.date # Group by date and count ERRORs daily_errors = df[df['log_level'] == 'ERROR'].groupby('date').size() daily_errors_ts = daily_errors.asfreq('D').fillna(0) # Display key metrics st.markdown('
Key Metrics
', unsafe_allow_html=True) col1, col2, col3 = st.columns(3) with col1: st.markdown('
', unsafe_allow_html=True) st.metric("Total ERRORs", f"{int(daily_errors_ts.sum())}") st.markdown('
', unsafe_allow_html=True) with col2: st.markdown('
', unsafe_allow_html=True) st.metric("Average Daily ERRORs", f"{daily_errors_ts.mean():.2f}") st.markdown('
', unsafe_allow_html=True) with col3: st.markdown('
', unsafe_allow_html=True) if len(daily_errors_ts) >= 7: last_week = daily_errors_ts[-7:].mean() previous_week = daily_errors_ts[-14:-7].mean() delta = ((last_week - previous_week) / previous_week * 100) if previous_week > 0 else 0 st.metric("7-Day Trend", f"{last_week:.2f}", f"{delta:.1f}%") else: st.metric("7-Day Trend", "Insufficient data") st.markdown('
', unsafe_allow_html=True) # Historical data visualization st.markdown('
Historical ERROR Trends
', unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) chart_tab1, chart_tab2 = st.tabs(["Line Chart", "Bar Chart"]) with chart_tab1: st.line_chart(daily_errors_ts) with chart_tab2: st.bar_chart(daily_errors_ts) st.markdown('
', unsafe_allow_html=True) # Model training st.markdown('
ARIMA Model Training
', unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) try: with st.spinner("Training ARIMA model..."): # Use the parameters from sidebar model = ARIMA(daily_errors_ts, order=(p, d, q)) model_fit = model.fit() # Save model with open("arima_model.pkl", "wb") as f: pickle.dump(model_fit, f) st.markdown('
✅ ARIMA model trained and saved successfully!
', unsafe_allow_html=True) # Display model summary in expander with st.expander("View Model Details"): st.code(str(model_fit.summary())) except Exception as arima_error: st.error(f"⚠️ ARIMA training failed: {arima_error}") st.markdown('
', unsafe_allow_html=True) # Forecast visualization st.markdown('
ERROR Forecast Analysis
', unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) forecast = model_fit.forecast(steps=forecast_days) forecast_dates = pd.date_range(start=daily_errors_ts.index[-1] + pd.Timedelta(days=1), periods=forecast_days) # Create forecast dataframe for additional analysis forecast_df = pd.DataFrame({ 'date': forecast_dates, 'forecast': forecast.values, # Use a fixed standard deviation estimate instead of se_mean 'lower_ci': forecast.values - 2 * forecast.values.std() if len(forecast) > 1 else forecast.values, 'upper_ci': forecast.values + 2 * forecast.values.std() if len(forecast) > 1 else forecast.values * 1.2 }) # Round negative values to 0 for logical consistency forecast_df['lower_ci'] = forecast_df['lower_ci'].clip(lower=0) forecast_df['forecast'] = forecast_df['forecast'].clip(lower=0) # Enhanced plotly visualization fig = go.Figure() # Historical data fig.add_trace(go.Scatter( x=daily_errors_ts.index, y=daily_errors_ts.values, mode='lines+markers', name='Historical ERRORs', line=dict(color='#3B82F6', width=2) )) # Forecast fig.add_trace(go.Scatter( x=forecast_df['date'], y=forecast_df['forecast'], mode='lines+markers', name='Forecasted ERRORs', line=dict(color='#EF4444', width=2, dash='dash') )) # Confidence interval fig.add_trace(go.Scatter( x=forecast_df['date'].tolist() + forecast_df['date'].tolist()[::-1], y=forecast_df['upper_ci'].tolist() + forecast_df['lower_ci'].tolist()[::-1], fill='toself', fillcolor='rgba(239, 68, 68, 0.1)', line=dict(color='rgba(0,0,0,0)'), hoverinfo='skip', showlegend=False )) fig.update_layout( title='ERROR Log Forecast with Confidence Intervals', xaxis_title='Date', yaxis_title='ERROR Count', hovermode='x unified', legend=dict(x=0.01, y=0.99), template='plotly_white', height=500 ) st.plotly_chart(fig, use_container_width=True) # Forecast data table with st.expander("View Forecast Data"): forecast_df['date'] = forecast_df['date'].dt.date forecast_df['forecast'] = forecast_df['forecast'].round(2) forecast_df['lower_ci'] = forecast_df['lower_ci'].round(2) forecast_df['upper_ci'] = forecast_df['upper_ci'].round(2) st.dataframe(forecast_df) # Download forecast as CSV csv = forecast_df.to_csv(index=False) st.download_button( label="Download Forecast CSV", data=csv, file_name=f"error_forecast_{datetime.now().strftime('%Y%m%d')}.csv", mime="text/csv" ) st.markdown('
', unsafe_allow_html=True) except Exception as e: st.error(f"❌ Error processing data: {e}")