La única forma de comprender lo sucedido cuando falla la ejecución de una petición, consiste en echar un vistazo a la traza generada por el proceso que se ejecuta. Afortunadamente, y como se va a ver en esta sección, tanto PHP como Symfony guardan mucha información de este tipo en archivos de log.

16.1.1. Logs de PHP

PHP dispone de una directiva llamada error_reporting, que se define en el archivo de configuración php.ini, y que especifica los eventos de PHP que se guardan en el archivo de log. Symfony permite redefinir el valor de esta opción, tanto a nivel de aplicación como de entorno, en el archivo settings.yml, tal y como se muestra en el listado 16-1.

Listado 16-1 - Indicando el valor de la directiva error_reporting, en frontend/config/settings.yml

prod:
 .settings:
    error_reporting:  <?php echo (E_PARSE | E_COMPILE_ERROR | E_ERROR | E_CORE_ERROR | E_USER_ERROR)."\n" ?>

dev:
  .settings:
    error_reporting:  <?php echo (E_ALL | E_STRICT)."\n" ?>

Para no penalizar el rendimiento de la aplicación en el entorno de producción, el servidor solamente guarda en el archivo de log los errores críticos de PHP. No obstante, en el entorno de desarrollo, se guardan en el log todos los tipos de eventos, de forma que el programador puede disponer de la máxima información para seguir la pista a los errores.

El lugar en el que se guardan los archivos de log de PHP depende de la configuración del archivo php.ini. Si no se ha modificado su valor, PHP utiliza las herramientas de log del servidor web (como por ejemplo los logs de error del servidor Apache). En este caso, los archivos de log de PHP se encuentran en el directorio de logs del servidor web.

16.1.2. Logs de Symfony

Además de los archivos de log creados por PHP, Symfony también guarda mucha información de sus propios eventos en otros archivos de log. Los archivos de log creados por Symfony se encuentran en el directorio miproyecto/log/. Symfony crea un archivo por cada aplicación y cada entorno. El archivo del entorno de desarrollo de una aplicación llamada frontend sería frontend_dev.log y el archivo de log del entorno de producción de la misma aplicación se llamaría frontend_prod.log.

Si se dispone de una aplicación Symfony ejecutándose, se puede observar que la sintaxis de los archivos de log generados es muy sencilla. Cada evento resulta en una nueva línea en el archivo de log de la aplicación. Cada línea incluye la fecha y hora a la que se ha producido, el tipo de evento, el objeto que ha sido procesado y otros detalles relevantes que dependen de cada tipo de evento y/o objeto procesado. El listado 16-2 muestra un ejemplo del contenido de un archivo de log de Symfony.

Listado 16-2 - Contenido de un archivo de log de Symfony, en log/frontend_dev.php

Nov 15 16:30:25 symfony [info ] {sfAction} call "barActions->executemessages()"
Nov 15 16:30:25 symfony [debug] SELECT bd_message.ID, bd_message.SENDER_ID, bd_...
Nov 15 16:30:25 symfony [info ] {sfCreole} executeQuery(): SELECT bd_message.ID...
Nov 15 16:30:25 symfony [info ] {sfView} set slot "leftbar" (bar/index)
Nov 15 16:30:25 symfony [info ] {sfView} set slot "messageblock" (bar/mes...
Nov 15 16:30:25 symfony [info ] {sfView} execute view for template "messa...
Nov 15 16:30:25 symfony [info ] {sfView} render "/home/production/miproyecto/...
Nov 15 16:30:25 symfony [info ] {sfView} render to client

Estos archivos de log contienen mucha información, como por ejemplo las consultas SQL enviadas a la base de datos, las plantillas que se han procesado, las llamadas realizadas entre objetos, etc.

A partir de Symfony 1.1 es posible personalizar el formato de los mensajes de log redefiniendo las opciones format y/o time_format en el archivo de configuración factories.yml, tal y como muestra el listado 16-3.

Listado 16-3 - Modificando el formato de los mensajes de log

all:
  logger:
    param:
      sf_file_debug:
        param:
          format:      %time% %type% [%priority%] %message%%EOL%
          time_format: %b %d %H:%M:%S

16.1.2.1. Configuración del nivel de log de Symfony

Symfony define ocho niveles diferentes para los mensajes de log: emerg, alert, crit, err, warning, notice, info y debug, que son los mismos niveles que define el paquete PEAR::Log (http://pear.php.net/package/Log/). El archivo de configuración factories.yml de cada aplicación permite definir el nivel de los mensajes que se guardan en el archivo de log, como se muestra en el listado 16-4.

Listado 16-4 - Configuración por defecto de los archivos de log en Symfony, en frontend/config/factories.yml

prod:
  logger:
    param:
      level: err

Por defecto, en todos los entornos salvo en el de producción, se guardan en los archivos de log todos los mensajes (hasta el nivel menos importante, el nivel debug). En el entorno de producción, los archivos de log están deshabilitados. Además, en este mismo entorno, si se activan los logs asignando el valor on a la opción logging_enabled en el archivo de configuración settings.yml, solamente se guardan los mensajes más importantes (de crit a emerg).

En el archivo factories.yml se puede modificar el nivel de los mensajes guardados para cada entorno de ejecución, de forma que se limite el tipo de mensajes que se guardan en el archivo de log.

Truco Para determinar si están habilitados los archivos de log, se puede utilizar la instrucción sfConfig::get('sf_logging_enabled').

16.1.2.2. Añadiendo un mensaje de log

Además de los mensajes generados por Symfony, también es posible añadir mensajes propios en el archivo de log desde el código de la aplicación, utilizando alguna de las técnicas mostradas en el listado 16-5.

Listado 16-5 - Añadiendo un mensaje de log propio

// Desde la acción
$this->logMessage($mensaje, $nivel);

// Desde una plantilla
<?php use_helper('Debug') ?>
<?php log_message($mensaje, $nivel) ?>

El valor de la opción $nivel puede ser uno de los valores definidos para los mensajes de log de Symfony.

Además, para escribir un mensaje en el log desde cualquier punto de la aplicación, se pueden utilizar directamente los métodos de sfLogger, como se muestra en el listado 16-6. Los métodos disponibles comparten el mismo nombre que los niveles de log definidos.

Listado 16-6 - Añadiendo un mensaje de log propio desde cualquier punto de la aplicación

if (sfConfig::get('sf_logging_enabled'))
{
  sfContext::getInstance()->getLogger()->info($mensaje);
}

16.1.2.3. Borrando y rotando archivos de log

Periódicamente es necesario borrar los archivos del directorio log/ de las aplicaciones, ya que estos archivos suelen crecer en tamaño varios MB cada pocos días, aunque todo depende del tráfico de la aplicación. Symfony proporciona la tarea log:clear para este propósito, y se puede ejecutar de forma periódica manualmente o mediante una tarea programada. El siguiente comando por ejemplo borra todos los archivos de log:

> php symfony log:clear

Para mejorar el rendimiento y la seguridad de la aplicación, suele ser habitual almacenar los archivos de log de Symfony en varios archivos pequeños en vez de en un solo archivo muy grande. La estrategia de almacenamiento ideal para los archivos de log es la de vaciar y hacer una copia de seguridad cada poco tiempo del archivo de log principal y mantener un número limitado de copias de seguridad.

Esta estrategia se denomina rotación de archivos de log y el listado 16-7 muestra cómo activar una rotación con un período (period) de 7 días y un historial o número de copias de seguridad (history) de 10. De esta forma, se trabaja con un archivo de log activo y se dispone de 10 copias de seguridad, cada una con los mensajes de log de 7 días diferentes. Cuando transcurren otros 7 días, el archivo de log activo se transforma en una copia de seguridad y se borra el archivo de la copia de seguridad más antigua.

Listado 16-7 - Ejecutando la rotación de logs

> php symfony log:rotate frontend prod --period=7 --history=10

Las copias de seguridad de los archivos de log se almacenan en el directorio logs/history/ y a su nombre se les añade un sufijo con la fecha completa en la que fueron guardados.