Skip to content
Mindset & Code edited this page Aug 18, 2026 · 5 revisions

Security Log Analysis — Wiki

🇬🇧 English first · 🇪🇸 Español más abajo.

Two Python scripts, 115 lines between them: one writes 5.000 synthetic log lines, the other reads them back and summarises them into an incident report. The exercise is the parsing and the reporting — it does not detect anything, and this wiki says so rather than implying otherwise.

Repo: mindset-code/project-security-log-analysis


Pages in this wiki


The honest summary

generate_logs.py picks an event at random from five, with fixed weights. log_analysis.py reads the file back and counts how many times each label appeared.

That means the classification is written by the generator and read by the analyser. BRUTE_FORCE_ATTEMPT is not a conclusion the analyser reaches — it is a string the generator already put in the line. There is no threshold, no time window, no correlation between events and no comparison against a baseline. The line

**Intentos de Fuerza Bruta Detectados:** 246

is a count of a field, not a detection.

This is worth stating plainly because it is the difference between a log-parsing exercise — which this is, and does correctly — and a SIEM, which it is not.


The real log format

One line, space-separated, with the event in square brackets:

2026-01-05 02:50:25 192.168.1.83 [LOGIN_SUCCESS] User admin logged in successfully.
2026-01-05 02:50:31 192.168.1.185 [LOGIN_FAILED] User admin failed to log in.

Five event types exist, and no others:

Event Weight in the generator Count in the committed file Share
LOGIN_SUCCESS 0.60 3.057 61,1 %
LOGIN_FAILED 0.20 969 19,4 %
ACCESS_DENIED 0.10 478 9,6 %
PORT_SCAN_DETECTED 0.05 250 5,0 %
BRUTE_FORCE_ATTEMPT 0.05 246 4,9 %

The observed shares track the weights closely, which is what you would expect from 5.000 independent draws and is itself the clearest evidence that nothing in this data is an attack.


Flow

flowchart LR
    A["generate_logs.py<br/>5.000 lines, 5 events by weight"] --> B["security_logs.txt<br/>426 KB, committed"]
    B --> C["log_analysis.py<br/>1 regex + Counter"]
    C --> D["security_analysis_report.md<br/>4 tables"]
Loading

Running it

python generate_logs.py    # writes security_logs.txt
python log_analysis.py     # writes security_analysis_report.md

Standard library only: re, random, collections.Counter, datetime. No dependencies, no configuration, no arguments.

Both the log file and the report are committed, so every number on this wiki can be checked without running anything.

Where the security framing comes from

The vocabulary — event triage, indicators, incident write-up — follows the Security Operations domain of the ISC2 Certified in Cybersecurity (CC). What the code exercises from that domain is the last part: turning a pile of events into a document somebody can read. The monitoring and the identification of indicators are not implemented, and Reglas de deteccion explains exactly what would have to be added.


🇪🇸 Español

Dos scripts de Python, 115 líneas entre los dos: uno escribe 5.000 líneas de log sintéticas y el otro las vuelve a leer y las resume en un informe de incidentes. El ejercicio está en el parseo y en la redacción del informe — no detecta nada, y esta wiki lo dice en vez de dejar entender otra cosa.

Repo: mindset-code/project-security-log-analysis


Páginas de esta wiki


El resumen honesto

generate_logs.py elige un evento al azar entre cinco, con pesos fijos. log_analysis.py vuelve a leer el fichero y cuenta cuántas veces apareció cada etiqueta.

Es decir: la clasificación la escribe el generador y la lee el analizador. BRUTE_FORCE_ATTEMPT no es una conclusión a la que llegue el analizador — es una cadena que el generador ya había puesto en la línea. No hay umbral, ni ventana temporal, ni correlación entre eventos, ni comparación contra una línea base. La línea

**Intentos de Fuerza Bruta Detectados:** 246

es el recuento de un campo, no una detección.

Merece la pena decirlo sin rodeos, porque ahí está la diferencia entre un ejercicio de parseo de logs —que es lo que esto es, y lo hace bien— y un SIEM, que no lo es.


El formato real del log

Una línea, separada por espacios, con el evento entre corchetes:

2026-01-05 02:50:25 192.168.1.83 [LOGIN_SUCCESS] User admin logged in successfully.
2026-01-05 02:50:31 192.168.1.185 [LOGIN_FAILED] User admin failed to log in.

Existen cinco tipos de evento, y ninguno más:

Evento Peso en el generador Recuento en el fichero commiteado Porcentaje
LOGIN_SUCCESS 0,60 3.057 61,1 %
LOGIN_FAILED 0,20 969 19,4 %
ACCESS_DENIED 0,10 478 9,6 %
PORT_SCAN_DETECTED 0,05 250 5,0 %
BRUTE_FORCE_ATTEMPT 0,05 246 4,9 %

Los porcentajes observados siguen de cerca a los pesos, que es lo que cabe esperar de 5.000 tiradas independientes y es en sí mismo la prueba más clara de que en estos datos no hay ningún ataque.


Flujo

Ver el diagrama de arriba: el generador escribe security_logs.txt, el analizador lo lee con una expresión regular y un Counter, y de ahí sale security_analysis_report.md con cuatro tablas.

Cómo se ejecuta

python generate_logs.py    # escribe security_logs.txt
python log_analysis.py     # escribe security_analysis_report.md

Solo biblioteca estándar: re, random, collections.Counter y datetime. Sin dependencias, sin configuración y sin argumentos.

Tanto el fichero de logs como el informe están commiteados, así que todos los números de esta wiki se pueden comprobar sin ejecutar nada.

De dónde sale el marco de seguridad

El vocabulario —triaje de eventos, indicadores, redacción del incidente— sigue el dominio Security Operations de la certificación ISC2 Certified in Cybersecurity (CC). De ese dominio, lo que el código ejercita es la última parte: convertir un montón de eventos en un documento que alguien pueda leer. La monitorización y la identificación de indicadores no están implementadas, y Reglas de deteccion explica exactamente qué habría que añadir.