{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Ejercicios con ficheros de log\n",
        "\n",
        "Este notebook permite practicar la lectura, filtrado y análisis de un fichero de registro utilizando Python y expresiones regulares.\n",
        "\n",
        "Cada línea de `servidor.log` sigue esta estructura:\n",
        "\n",
        "```text\n",
        "FECHA HORA NIVEL MENSAJE\n",
        "```\n",
        "\n",
        "Ejecuta las celdas en orden, de arriba abajo.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 1. Importar la librería necesaria\n",
        "\n",
        "La librería estándar `re` permite buscar patrones mediante expresiones regulares.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {},
      "outputs": [],
      "source": [
        "import re\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 2. Crear el fichero servidor.log\n",
        "\n",
        "Esta celda genera automáticamente un fichero de ejemplo con cuatro mensajes `INFO`, dos `WARNING` y tres `ERROR`.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Se ha creado el fichero servidor.log\n"
          ]
        }
      ],
      "source": [
        "contenido_log = \"\"\"2026-09-11 08:15:10 INFO Usuario ane ha iniciado sesión desde 192.168.1.10\n",
        "2026-09-11 08:18:42 INFO Petición procesada correctamente desde 192.168.1.15\n",
        "2026-09-11 08:21:03 WARNING Espacio en disco por debajo del 20%\n",
        "2026-09-11 08:23:17 ERROR Error de conexión con la base de datos desde 192.168.1.21\n",
        "2026-09-11 08:25:34 INFO Usuario jon ha iniciado sesión desde 192.168.1.10\n",
        "2026-09-11 08:27:50 ERROR No se pudo abrir el fichero de configuración\n",
        "2026-09-11 08:29:12 WARNING Intento de acceso no autorizado desde 192.168.1.15\n",
        "2026-09-11 08:32:05 INFO Copia de seguridad completada\n",
        "2026-09-11 08:35:41 ERROR Conexión perdida con el servidor 192.168.1.21\n",
        "\"\"\"\n",
        "\n",
        "with open(\"servidor.log\", \"w\", encoding=\"utf-8\") as fichero:\n",
        "    fichero.write(contenido_log)\n",
        "\n",
        "print(\"Se ha creado el fichero servidor.log\")\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Ejercicio 1. Leer todo el fichero\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2026-09-11 08:15:10 INFO Usuario ane ha iniciado sesión desde 192.168.1.10\n",
            "2026-09-11 08:18:42 INFO Petición procesada correctamente desde 192.168.1.15\n",
            "2026-09-11 08:21:03 WARNING Espacio en disco por debajo del 20%\n",
            "2026-09-11 08:23:17 ERROR Error de conexión con la base de datos desde 192.168.1.21\n",
            "2026-09-11 08:25:34 INFO Usuario jon ha iniciado sesión desde 192.168.1.10\n",
            "2026-09-11 08:27:50 ERROR No se pudo abrir el fichero de configuración\n",
            "2026-09-11 08:29:12 WARNING Intento de acceso no autorizado desde 192.168.1.15\n",
            "2026-09-11 08:32:05 INFO Copia de seguridad completada\n",
            "2026-09-11 08:35:41 ERROR Conexión perdida con el servidor 192.168.1.21\n"
          ]
        }
      ],
      "source": [
        "with open(\"servidor.log\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    for linea in fichero:\n",
        "        print(linea.strip())\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Ejercicio 2. Mostrar solamente las líneas con ERROR\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2026-09-11 08:23:17 ERROR Error de conexión con la base de datos desde 192.168.1.21\n",
            "2026-09-11 08:27:50 ERROR No se pudo abrir el fichero de configuración\n",
            "2026-09-11 08:35:41 ERROR Conexión perdida con el servidor 192.168.1.21\n"
          ]
        }
      ],
      "source": [
        "with open(\"servidor.log\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    for linea in fichero:\n",
        "        if \"ERROR\" in linea:\n",
        "            print(linea.strip())\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Ejercicio 3. Mostrar solamente las líneas con WARNING\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2026-09-11 08:21:03 WARNING Espacio en disco por debajo del 20%\n",
            "2026-09-11 08:29:12 WARNING Intento de acceso no autorizado desde 192.168.1.15\n"
          ]
        }
      ],
      "source": [
        "with open(\"servidor.log\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    for linea in fichero:\n",
        "        if \"WARNING\" in linea:\n",
        "            print(linea.strip())\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Ejercicio 4. Contar los mensajes INFO, WARNING y ERROR\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "{'INFO': 4, 'WARNING': 2, 'ERROR': 3}\n"
          ]
        }
      ],
      "source": [
        "contador = {\n",
        "    \"INFO\": 0,\n",
        "    \"WARNING\": 0,\n",
        "    \"ERROR\": 0\n",
        "}\n",
        "\n",
        "with open(\"servidor.log\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    for linea in fichero:\n",
        "        if \"INFO\" in linea:\n",
        "            contador[\"INFO\"] += 1\n",
        "        elif \"WARNING\" in linea:\n",
        "            contador[\"WARNING\"] += 1\n",
        "        elif \"ERROR\" in linea:\n",
        "            contador[\"ERROR\"] += 1\n",
        "\n",
        "print(contador)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Ejercicio 5. Mostrar únicamente los mensajes\n",
        "\n",
        "`split(\" \", 3)` divide cada línea en un máximo de cuatro partes: fecha, hora, nivel y mensaje.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Usuario ane ha iniciado sesión desde 192.168.1.10\n",
            "Petición procesada correctamente desde 192.168.1.15\n",
            "Espacio en disco por debajo del 20%\n",
            "Error de conexión con la base de datos desde 192.168.1.21\n",
            "Usuario jon ha iniciado sesión desde 192.168.1.10\n",
            "No se pudo abrir el fichero de configuración\n",
            "Intento de acceso no autorizado desde 192.168.1.15\n",
            "Copia de seguridad completada\n",
            "Conexión perdida con el servidor 192.168.1.21\n"
          ]
        }
      ],
      "source": [
        "with open(\"servidor.log\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    for linea in fichero:\n",
        "        partes = linea.strip().split(\" \", 3)\n",
        "        \n",
        "        if len(partes) == 4:\n",
        "            fecha = partes[0]\n",
        "            hora = partes[1]\n",
        "            nivel = partes[2]\n",
        "            mensaje = partes[3]\n",
        "\n",
        "            print(mensaje)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Ejercicio 6. Buscar líneas relacionadas con un usuario\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2026-09-11 08:15:10 INFO Usuario ane ha iniciado sesión desde 192.168.1.10\n"
          ]
        }
      ],
      "source": [
        "usuario_buscar = \"ane\"\n",
        "\n",
        "with open(\"servidor.log\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    for linea in fichero:\n",
        "        if usuario_buscar in linea:\n",
        "            print(linea.strip())\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Ejercicio 7. Extraer direcciones IP\n",
        "\n",
        "La expresión regular localiza cuatro grupos de entre uno y tres dígitos separados por puntos.\n",
        "Para los patrones:\n",
        "    r\"...\": expresiones regulares\n",
        "    \\b: inicio o final de una palabra.\n",
        "    \\d{1,3}: entre 1 y 3 dígitos.\n",
        "    \\.: un punto.\n",
        "    {3}: repite tres veces la parte anterior\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "192.168.1.10\n",
            "192.168.1.15\n",
            "192.168.1.21\n",
            "192.168.1.10\n",
            "192.168.1.15\n",
            "192.168.1.21\n"
          ]
        }
      ],
      "source": [
        "patron_ip = r\"\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b\"\n",
        "\n",
        "with open(\"servidor.log\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    for linea in fichero:\n",
        "        ips = re.findall(patron_ip, linea)\n",
        "\n",
        "        for ip in ips:\n",
        "            print(ip)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Ejercicio 8. Extraer fechas\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2026-09-11\n",
            "2026-09-11\n",
            "2026-09-11\n",
            "2026-09-11\n",
            "2026-09-11\n",
            "2026-09-11\n",
            "2026-09-11\n",
            "2026-09-11\n",
            "2026-09-11\n"
          ]
        }
      ],
      "source": [
        "patron_fecha = r\"\\d{4}-\\d{2}-\\d{2}\"\n",
        "\n",
        "with open(\"servidor.log\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    for linea in fichero:\n",
        "        resultado = re.search(patron_fecha, linea)\n",
        "\n",
        "        if resultado:\n",
        "            print(resultado.group())\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Ejercicio 9. Extraer horas\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "08:15:10\n",
            "08:18:42\n",
            "08:21:03\n",
            "08:23:17\n",
            "08:25:34\n",
            "08:27:50\n",
            "08:29:12\n",
            "08:32:05\n",
            "08:35:41\n"
          ]
        }
      ],
      "source": [
        "patron_hora = r\"\\d{2}:\\d{2}:\\d{2}\"\n",
        "\n",
        "with open(\"servidor.log\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    for linea in fichero:\n",
        "        resultado = re.search(patron_hora, linea)\n",
        "\n",
        "        if resultado:\n",
        "            print(resultado.group())\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Ejercicio 10. Guardar los errores en otro fichero\n",
        "\n",
        "Las líneas con nivel `ERROR` se guardan en `errores.log`.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Se ha creado el fichero errores.log\n"
          ]
        }
      ],
      "source": [
        "errores = []\n",
        "\n",
        "with open(\"servidor.log\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    for linea in fichero:\n",
        "        if \"ERROR\" in linea:\n",
        "            errores.append(linea)\n",
        "\n",
        "with open(\"errores.log\", \"w\", encoding=\"utf-8\") as fichero:\n",
        "    fichero.writelines(errores)\n",
        "\n",
        "print(\"Se ha creado el fichero errores.log\")\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Ejercicio 11. Crear un resumen del log\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Se ha creado el fichero resumen_log.txt\n"
          ]
        }
      ],
      "source": [
        "info = 0\n",
        "warning = 0\n",
        "error = 0\n",
        "\n",
        "with open(\"servidor.log\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    for linea in fichero:\n",
        "        if \"INFO\" in linea:\n",
        "            info += 1\n",
        "        elif \"WARNING\" in linea:\n",
        "            warning += 1\n",
        "        elif \"ERROR\" in linea:\n",
        "            error += 1\n",
        "\n",
        "with open(\"resumen_log.txt\", \"w\", encoding=\"utf-8\") as fichero:\n",
        "    fichero.write(\"RESUMEN DEL LOG\\n\")\n",
        "    fichero.write(\"----------------\\n\")\n",
        "    fichero.write(f\"INFO: {info}\\n\")\n",
        "    fichero.write(f\"WARNING: {warning}\\n\")\n",
        "    fichero.write(f\"ERROR: {error}\\n\")\n",
        "\n",
        "print(\"Se ha creado el fichero resumen_log.txt\")\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Ejercicio 12. Buscar mensajes dentro de un rango horario\n",
        "\n",
        "Como las horas utilizan el formato fijo `HH:MM:SS`, pueden compararse como cadenas de texto.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2026-09-11 08:21:03 WARNING Espacio en disco por debajo del 20%\n",
            "2026-09-11 08:23:17 ERROR Error de conexión con la base de datos desde 192.168.1.21\n",
            "2026-09-11 08:25:34 INFO Usuario jon ha iniciado sesión desde 192.168.1.10\n",
            "2026-09-11 08:27:50 ERROR No se pudo abrir el fichero de configuración\n",
            "2026-09-11 08:29:12 WARNING Intento de acceso no autorizado desde 192.168.1.15\n"
          ]
        }
      ],
      "source": [
        "hora_inicio = \"08:20:00\"\n",
        "hora_fin = \"08:30:00\"\n",
        "\n",
        "with open(\"servidor.log\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    for linea in fichero:\n",
        "        partes = linea.split()\n",
        "\n",
        "        if len(partes) >= 2:\n",
        "            hora = partes[1]\n",
        "\n",
        "            if hora_inicio <= hora <= hora_fin:\n",
        "                print(linea.strip())\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Ejercicio 13. Contar cuántas veces aparece cada IP\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "{'192.168.1.10': 2, '192.168.1.15': 2, '192.168.1.21': 2}\n"
          ]
        }
      ],
      "source": [
        "ips_contador = {}\n",
        "\n",
        "with open(\"servidor.log\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    for linea in fichero:\n",
        "        ips = re.findall(patron_ip, linea)\n",
        "\n",
        "        for ip in ips:\n",
        "            if ip in ips_contador:\n",
        "                ips_contador[ip] += 1\n",
        "            else:\n",
        "                ips_contador[ip] = 1\n",
        "\n",
        "print(ips_contador)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Ejercicio 14. Mostrar el nivel y el mensaje\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "INFO: Usuario ane ha iniciado sesión desde 192.168.1.10\n",
            "INFO: Petición procesada correctamente desde 192.168.1.15\n",
            "WARNING: Espacio en disco por debajo del 20%\n",
            "ERROR: Error de conexión con la base de datos desde 192.168.1.21\n",
            "INFO: Usuario jon ha iniciado sesión desde 192.168.1.10\n",
            "ERROR: No se pudo abrir el fichero de configuración\n",
            "WARNING: Intento de acceso no autorizado desde 192.168.1.15\n",
            "INFO: Copia de seguridad completada\n",
            "ERROR: Conexión perdida con el servidor 192.168.1.21\n"
          ]
        }
      ],
      "source": [
        "with open(\"servidor.log\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    for linea in fichero:\n",
        "        partes = linea.strip().split(\" \", 3)\n",
        "\n",
        "        if len(partes) == 4:\n",
        "            nivel = partes[2]\n",
        "            mensaje = partes[3]\n",
        "\n",
        "            print(f\"{nivel}: {mensaje}\")\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Ejercicio 15. Detectar errores de conexión\n",
        "\n",
        "Se combinan dos condiciones: la línea debe contener `ERROR` y también la palabra `conexión`.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2026-09-11 08:23:17 ERROR Error de conexión con la base de datos desde 192.168.1.21\n",
            "2026-09-11 08:35:41 ERROR Conexión perdida con el servidor 192.168.1.21\n"
          ]
        }
      ],
      "source": [
        "with open(\"servidor.log\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    for linea in fichero:\n",
        "        if \"ERROR\" in linea and \"conexión\" in linea.lower():\n",
        "            print(linea.strip())\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Comprobar los ficheros generados\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Contenido de errores.log:\n",
            "\n",
            "2026-09-11 08:23:17 ERROR Error de conexión con la base de datos desde 192.168.1.21\n",
            "2026-09-11 08:27:50 ERROR No se pudo abrir el fichero de configuración\n",
            "2026-09-11 08:35:41 ERROR Conexión perdida con el servidor 192.168.1.21\n",
            "\n",
            "Contenido de resumen_log.txt:\n",
            "\n",
            "RESUMEN DEL LOG\n",
            "----------------\n",
            "INFO: 4\n",
            "WARNING: 2\n",
            "ERROR: 3\n",
            "\n"
          ]
        }
      ],
      "source": [
        "print(\"Contenido de errores.log:\\n\")\n",
        "with open(\"errores.log\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    print(fichero.read())\n",
        "\n",
        "print(\"Contenido de resumen_log.txt:\\n\")\n",
        "with open(\"resumen_log.txt\", \"r\", encoding=\"utf-8\") as fichero:\n",
        "    print(fichero.read())\n"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": ".venv (3.14.7.final.0)",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.14.7"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
