Spaces:
Running
Running
File size: 7,894 Bytes
b7f41b7 cf8a984 1d16b92 cf8a984 1d16b92 cf8a984 1d16b92 cf8a984 1d16b92 cf8a984 1d16b92 b7f41b7 1d16b92 7e1d35a cf8a984 1d16b92 cf8a984 1d16b92 cf8a984 705d3ec cf8a984 1d16b92 cf8a984 1d16b92 cf8a984 1d16b92 cf8a984 1d16b92 cf8a984 705d3ec b7f41b7 cf8a984 1d16b92 cf8a984 1d16b92 cf8a984 1d16b92 cf8a984 1d16b92 cf8a984 b7f41b7 7e1d35a 1d16b92 cf8a984 1d16b92 cf8a984 1d16b92 cf8a984 1d16b92 cf8a984 705d3ec cf8a984 1d16b92 705d3ec cf8a984 705d3ec 1d16b92 705d3ec 1d16b92 705d3ec cf8a984 1d16b92 cf8a984 b7f41b7 cf8a984 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
import gradio as gr
import pandas as pd
import re
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.ensemble import IsolationForest
from sklearn.neighbors import LocalOutlierFactor
from sklearn.svm import OneClassSVM
import matplotlib.pyplot as plt
import seaborn as sns
import traceback
# --- FUNCIÓN DE ANÁLISIS MEJORADA PARA ACEPTAR LA ELECCIÓN DEL MODELO ---
def analizar_logs_completo(archivo_log, model_name):
if archivo_log is None:
return "Por favor, sube un archivo de log para comenzar el análisis.", None, None, None, None, None
try:
# --- Lectura y Preparación de Datos ---
with open(archivo_log.name, 'r', encoding='utf-8', errors='ignore') as f:
lines = f.readlines()
df_logs = pd.DataFrame(lines, columns=['raw_log'])
df_logs['raw_log'] = df_logs['raw_log'].str.strip()
df_logs.dropna(subset=['raw_log'], inplace=True)
df_logs = df_logs[df_logs['raw_log'] != '']
if df_logs.empty:
return "El archivo de log está vacío o no se pudo leer.", None, None, None, None, None
def preprocesar_log(log_message):
message = str(log_message)
message = re.sub(r'^\[.*?\]\s*(INFO|ERROR|DEBUG|WARN|FATAL|WARNING):\s*', '', message, flags=re.IGNORECASE)
message = re.sub(r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(,\d{3})?\s*', '', message, flags=re.IGNORECASE)
message = re.sub(r'\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b', '<IP>', message)
message = re.sub(r'\b\d+\b', '<NUM>', message)
message = re.sub(r'[a-f0-9-]{8,}', '<HASH_ID>', message)
message = re.sub(r'/(?:[a-zA-Z0-9_.-]+/)*[a-zA-Z0-9_.-]+', '<PATH>', message)
return message.lower().strip()
df_logs['log_template'] = df_logs['raw_log'].apply(preprocesar_log)
vectorizer = TfidfVectorizer(max_features=5000, stop_words=None)
X = vectorizer.fit_transform(df_logs['log_template'])
X_array = X.toarray()
# --- Detección de Errores por Reglas ---
error_keywords = ['error', 'fatal', 'failed', 'exception', 'nullpointer', 'timeout', 'denied']
def detectar_error_por_regla(log_message):
return any(keyword in str(log_message).lower() for keyword in error_keywords)
df_logs['error_por_regla'] = df_logs['raw_log'].apply(detectar_error_por_regla)
# --- SELECCIÓN Y ENTRENAMIENTO DEL MODELO DE ML ---
model_info = f"Resultados generados con el modelo: **{model_name}**"
if model_name == "Isolation Forest":
model = IsolationForest(n_estimators=100, contamination='auto', random_state=42)
model.fit(X_array)
elif model_name == "Local Outlier Factor":
# Usamos novelty=True para que se comporte como los otros modelos (fit/predict)
model = LocalOutlierFactor(n_neighbors=20, contamination='auto', novelty=True)
model.fit(X_array)
elif model_name == "One-Class SVM":
model = OneClassSVM(nu=0.05, kernel="rbf", gamma='auto')
model.fit(X_array)
df_logs['anomaly_score'] = model.decision_function(X_array)
df_logs['anomaly_prediction'] = model.predict(X_array)
df_logs['anomaly_ml'] = df_logs['anomaly_prediction'] == -1
# --- GENERACIÓN DE SALIDAS ---
total_logs = len(df_logs)
errores_reglas = df_logs['error_por_regla'].sum()
anomalias_ml = df_logs['anomaly_ml'].sum()
summary_md = f"""
## 📊 Resumen General del Análisis
- **Total de Líneas de Log Analizadas:** {total_logs}
- **Errores Detectados por Reglas:** `{errores_reglas}`
- **Anomalías Detectadas por Machine Learning:** `{anomalias_ml}`
"""
top_templates = df_logs['log_template'].value_counts().head(10)
templates_md = "## 📋 Plantillas de Log Más Comunes\n\n" + top_templates.to_markdown()
top_anomalies = df_logs[df_logs['anomaly_ml']].sort_values(by='anomaly_score').head(10)
anomalies_md = f"## ❗ Ejemplos de Anomalías Detectadas (ML)\n*Ordenadas por la más anómala (score más bajo)*\n\n"
if not top_anomalies.empty:
anomalies_md += top_anomalies[['raw_log', 'anomaly_score']].to_markdown(index=False)
else:
anomalies_md += "No se detectaron anomalías con el modelo de Machine Learning."
fig1, ax1 = plt.subplots(figsize=(10, 5))
sns.histplot(df_logs['anomaly_score'], bins=50, kde=True, ax=ax1)
ax1.set_title(f'Distribución de Scores de Anomalía ({model_name})')
ax1.set_xlabel('Score (más bajo = más anómalo)')
ax1.set_ylabel('Frecuencia')
plt.tight_layout()
combined_detections = df_logs.groupby(['error_por_regla', 'anomaly_ml']).size().unstack(fill_value=0)
fig2, ax2 = plt.subplots(figsize=(8, 6))
if not combined_detections.empty:
combined_detections.plot(kind='bar', stacked=True, ax=ax2, colormap='viridis')
ax2.set_title('Comparación: Detección por Reglas vs. ML')
ax2.set_xlabel('Detectado como Error por Reglas')
ax2.set_ylabel('Número de Logs')
ax2.tick_params(axis='x', rotation=0)
ax2.legend(['ML: Normal', 'ML: Anomalía'])
else:
ax2.text(0.5, 0.5, 'No hay datos para graficar.', ha='center', va='center')
plt.tight_layout()
return model_info, summary_md, templates_md, anomalies_md, fig1, fig2
except Exception as e:
error_message = f"Ha ocurrido un error durante el análisis:\n\n{traceback.format_exc()}"
return error_message, None, None, None, None, None
# --- CONSTRUCCIÓN DE LA INTERFAZ DE GRADIO CON LA OPCIÓN DE ELEGIR MODELO ---
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("# 🔍 Analizador Avanzado de Logs con Machine Learning")
gr.Markdown("Sube un archivo de log (.log, .txt) para realizar un análisis completo. Puedes elegir entre diferentes modelos de ML para la detección de anomalías.")
with gr.Row():
with gr.Column(scale=1):
log_file_input = gr.File(label="1. Sube tu archivo de log", file_types=[".log", ".txt"])
model_choice_input = gr.Radio(
["Isolation Forest", "Local Outlier Factor", "One-Class SVM"],
label="2. Elige el modelo de ML",
value="Isolation Forest"
)
analyze_button = gr.Button("🚀 Analizar Archivo", variant="primary")
with gr.Column(scale=3):
model_info_output = gr.Markdown()
summary_output = gr.Markdown(label="Resumen General")
with gr.Row():
plot_output_1 = gr.Plot(label="Distribución de Scores de Anomalía")
plot_output_2 = gr.Plot(label="Comparación de Detecciones")
templates_output = gr.Markdown(label="Plantillas Comunes")
anomalies_output = gr.Markdown(label="Anomalías Detectadas")
# Lista de salidas para no repetirla
outputs_list = [model_info_output, summary_output, templates_output, anomalies_output, plot_output_1, plot_output_2]
gr.Examples(
examples=[
["sample.log", "Isolation Forest"],
["sample_uniform.log", "Isolation Forest"],
["sample.log", "Local Outlier Factor"]
],
inputs=[log_file_input, model_choice_input],
outputs=outputs_list,
fn=analizar_logs_completo,
cache_examples=True,
label="O prueba con un archivo de ejemplo"
)
analyze_button.click(
fn=analizar_logs_completo,
inputs=[log_file_input, model_choice_input],
outputs=outputs_list
)
if __name__ == "__main__":
demo.launch() |