php

Loguear errores y mensajes en PHP en archivo de texto con un logger

Crear un simple logger en PHP para depurar y escribir errores en archivo de texto

Depurar nuestro código de PHP es uno de los pasos más importantes de la programación. Una gran ayuda que tenemos a nuestra disposición son los logs o archivos de log.

Hoy veremos cómo escribir mensajes de error y depuración (o debug) en archivos de texto usando PHP sin usar librerías externas, únicamente funciones nativas y un poco de código al inicio de nuestro script.

Gracias a esto podremos escribir mensajes de información y también llevar un registro de errores sin mostrarlos al usuario, con fecha y hora de llamada así como el script de llamada.

Un ejemplo del log que vamos a crear (esto dependerá de tu app pero para que te des una idea) es este:

[07-Feb-2019 09:37:29 America/Mexico_City] Soy un mensaje
[07-Feb-2019 09:37:29 America/Mexico_City] PHP Warning:  Division by zero in D:\desarrollo_php\htdocs\loguear\index.php on line 9
[07-Feb-2019 09:37:29 America/Mexico_City] Mensaje desde la línea 12 del archivo D:\desarrollo_php\htdocs\loguear\index.php
[07-Feb-2019 09:37:29 America/Mexico_City] Hola, yo soy parzibyte y mi sitio es parzibyte.me
[07-Feb-2019 09:37:29 America/Mexico_City] Los personajes son: a:4:{i:0;s:5:"Crash";i:1;s:10:"Fake Crash";i:2;s:4:"Pura";i:3;s:5:"Polar";}
[07-Feb-2019 09:37:29 America/Mexico_City] La mascota: array (
  'nombre' => 'Maggie',
  'edad' => 3,
  'amigos' => 
  array (
    0 => 
    array (
      'nombre' => 'Guayaba',
      'edad' => 2,
    ),
    1 => 
    array (
      'nombre' => 'Meca',
      'edad' => 5,
    ),
    2 => 
    array (
      'nombre' => 'Snowball',
      'edad' => 2,
    ),
  ),
)
[07-Feb-2019 09:37:29 America/Mexico_City] PHP Fatal error:  Uncaught Exception: Yo soy una excepción muy malvada in D:\desarrollo_php\htdocs\loguear\index.php:48
Stack trace:
#0 {main}
  thrown in D:\desarrollo_php\htdocs\loguear\index.php on line 48

Veamos entonces cómo loguear con PHP, además de evitar mostrar los errores al usuario, asegurando nuestras aplicaciones web.

Configurar archivo de log y ocultar errores al usuario

El propósito de un error log es:

  • No mostrar mensajes de error que un atacante podría aprovechar
  • Depurar código imprimiendo mensajes al archivo
  • Atrapar todos los errores y llevar un registro de los mismos con fecha y hora así como toda la pila de errores y stack trace

Entonces nuestro archivo en donde configuramos todo eso debe quedar así:

<?php
/**
 * Un simple archivo que configura el log, oculta
 * los errores y crea un nuevo archivo cada día
 *
 * @author parzibyte
 */# El directorio o carpeta en donde se van a crear los logs
# da algo como C:\xampp\esta_carpeta\logs
define("RUTA_LOGS", __DIR__ . "/logs");
# Crear carpeta si no existe
if (!file_exists(RUTA_LOGS)) {
    mkdir(RUTA_LOGS);
}
# Poner fecha y hora de México, esto es por si el servidor tiene
# otra zona horaria
date_default_timezone_set("America/Mexico_City");

# Configuramos el ini para que...
# No muestre errores
ini_set('display_errors', 0);
# Los ponga en un archivo
ini_set("log_errors", 1);
# Y le indicamos en dónde los va a poner, sería en algo como:
# RUTA_LOGS/2019-02-07.log
# Así cada día tenemos un archivo de log distinto
ini_set("error_log", RUTA_LOGS . "/" . date("Y-m-d") . ".log");

# Listo, ahora asegúrate de incluir lo de arriba en el encabezado o un archivo
# común que se ejecute siempre al inicio

Para usarlo simplemente hay que incluirlo en la parte superior de nuestros archivos en donde lo vamos a ocupar y, a partir de ello, cualquier error se va a ocultar al usuario y en su lugar se va a imprimir en el archivo.

Como vemos, cada día se creará un nuevo archivo y tendrá como nombre la fecha que indicará el año, mes y día. De esta manera, podemos ver los errores que han ocurrido con el paso del tiempo.

Recuerda que todos los archivos de log serán creados en la carpeta definida por RUTA_LOGS, puedes cambiarla según tus necesidades.

Explicación del logger

Los ajustes en donde llamamos a ini_set son para modificar el archivo ini de PHP y, en el orden en el que aparecen hacen lo siguiente:

  1. Ocultan los errores, es decir, no muestran el mensaje en la página web. Esto se logra poniendo display_errors en 0
  2. Indicar que sí queremos loguear los errores, poniendo log_errors en 1
  3. Guardar la ruta del archivo en donde se van a escribir los errores o mensajes configurando error_log y pasándole la ruta del fichero.

Más abajo veremos un ejemplo. Te recomiendo ver cómo trabajar con archivos en PHP.

Ejemplo de uso de logger que acabamos de crear

Podemos depurar llamando a error_log y pasándole un mensaje. En caso de que se genere un error, será impreso en el archivo.

Finalmente, si se produce una excepción no controlada, también se pondrá en el log y se le mostrará al usuario el mensaje de “Esta página no funciona”.

Para usar el logger simplemente inclúyelo en donde lo vas a usar, recomiendo incluirlo antes que todo. En mi caso queda así y hago algunas pruebas:

<?php
/**
 * Probar logger que acabamos de crear, imprimiendo algunos
 * mensajes de depuración, produciendo errores o lanzando
 * excepciones
 *
 * @author parzibyte
 */# Incluir "logger"
include_once "logger.php";

# Probemos enviando un simple error...
error_log("Soy un mensaje");

# División entre 0
$resultado = 1 / 0;

# Loguear cualquier cosa, incluso con la línea
error_log("Mensaje desde la línea " . __LINE__ . " del archivo " . __FILE__);

# ¿Variables? claro, al final simplemente debes pasar un string
$usuario = "parzibyte";
$sitio_web = "parzibyte.me";
error_log("Hola, yo soy $usuario y mi sitio es $sitio_web");

# También se pueden serializar algunas cosas, pero no serán legibles
# Recomiendo: https://parzibyte.me/blog/2018/10/11/sintaxis-corta-array-php/
$personajes = ["Crash", "Fake Crash", "Pura", "Polar"];
error_log("Los personajes son: " . serialize($personajes));

# Y si quieres un var_dump para detalles de cualquier variable,
# usa var_export como lo menciono en mi post:
# https://parzibyte.me/blog/2018/05/18/alternativa-var_dump-php-detalles-variable/
$mascota = [
    "nombre" => "Maggie",
    "edad" => 3,
    "amigos" => [
        [
            "nombre" => "Guayaba",
            "edad" => 2,
        ],
        [
            "nombre" => "Meca",
            "edad" => 5,
        ],
        [
            "nombre" => "Snowball",
            "edad" => 2,
        ],
    ],
];
error_log("La mascota: " . var_export($mascota, true));

# Lanzar excepción, lo ponemos al final porque detiene el script
throw new Exception("Yo soy una excepción muy malvada");

error_log("Esto no se escribe porque la excepción de arriba detiene el script");

El script fue para probar, pero si alguna función o clase produce un error, será logueado en el archivo. De esta manera tendrás un registro de todos los movimientos que se hacen.

Te invito a ver más sobre var_export y la notación corta de los arreglos.

Sobre la seguridad

Por cierto, cabe mencionar que nunca en tu vida debes loguear contraseñas o claves de acceso en un log, es una mala práctica y una posible vulnerabilidad.

Bonus: proteger acceso a carpeta de logs

Ya lo dije hace un momento, puedes mover la carpeta de logs a un directorio no público, pero en caso de que lo dejes en el mismo, debes protegerlo y restringirlo, porque cualquier usuario podría ver la carpeta (y su contenido) desde el navegador:

Directorio de logs expuesto al público

Dependiendo de tu servidor puedes aplicar distintas configuraciones, en este caso lo haré con Apache. Creamos un archivo llamado .htaccess (mira cómo habilitarlo si no lo está) y su contenido es el siguiente:

Allow from None
Order allow,deny

Ahora cuando alguien quiere entrar a la carpeta, se muestra esto:

Acesso prohibido a logs creados con PHP

Mira más sobre denegar o proteger acceso a carpetas y archivos con Apache.

Y no te preocupes, tampoco se puede acceder a los archivos individuales; pero tú sí podrás verlos desde FTP o el sistema de archivos, además de que PHP podrá seguir escribiendo. En resumen, los archivos de log se restringen al público.

Conclusiones

¿Quieres leer más sobre PHP? haz click aquí.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Ver comentarios

Entradas recientes

Tramitar acta de nacimiento en línea de manera instantánea

En este post te quiero compartir mi experiencia tramitando un acta de nacimiento de México…

1 min hace

Creador de credenciales web – Aplicación gratuita

Hoy te voy a presentar un creador de credenciales que acabo de programar y que…

2 semanas hace

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

2 semanas hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

2 semanas hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

2 semanas hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

2 semanas hace

Esta web usa cookies.