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 miaplicacion/config/settings.yml

prod:
 .settings:
    error_reporting:  257

dev:
  .settings:
    error_reporting:  4095

Los números que se indican son una forma abreviada de referirse a los distintos niveles de error (la documentación de PHP contiene toda la información relativa a estos niveles). Básicamente, el valor 4095 es la forma abreviada del valor E_ALL | E_STRICT, y el valor 257 se refiere a E_ERROR | E_USER_ERROR (que es el valor por defecto de cualquier nuevo entorno definido).

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 miaplicacion sería miaplicacion_dev.log y el archivo de log del entorno de producción de la misma aplicación se llamaría miaplicacion_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/miaplicacion_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.

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 logging.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-3.

Listado 16-3 - Configuración por defecto de los archivos de log en Symfony, en miaplicacion/config/logging.yml

prod:
  enabled: off
  level:   err
  rotate:  on
  purge:   off

dev:

test:

#all:
#  enabled:  on
#  level:    debug
#  rotate:   off
#  period:   7
#  history:  10
#  purge:    on

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, no se utilizan por defecto los archivos de log. Además, en este mismo entorno, si se activan los logs asignando el valor on a la opción enabled, solamente se guardan los mensajes más importantes (de crit a emerg).

En el archivo logging.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. Las opciones rotate, period, history y purge se describen más adelante en la sección "Borrando y rotando archivos de log".

Truco Los valores de las opciones de log son accesibles durante la ejecución de la aplicación mediante el objeto sfConfig y el uso del prefijo sf_logging_. Para determinar si están habilitados los archivos de log, se utilizaría por ejemplo la siguiente llamada: 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-4.

Listado 16-4 - 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-5. Los métodos disponibles comparten el mismo nombre que los niveles de log definidos.

Listado 16-5 - 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-purge para este propósito, y se puede ejecutar de forma periódica manualmente o mediante una tarea programada. El siguiente comando borra los archivos de log de todas las aplicaciones y entornos para los que el archivo logging.yml especifique un valor on a la opción purge (que es el valor por defecto):

> symfony log-purge

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 se puede activar desde el archivo de configuración logging.yml. Si se establece por ejemplo un period de 7 días y un history (número de copias de seguridad) de 10, como se muestra en el listado 16-6, es posible trabajar con un archivo de log activo y tener otras 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-6 - Configurando la rotación de logs, en miaplicacion/config/logging.yml

prod:
  rotate:  on
  period:  7       ## Por defecto, los archivos se rotan cada 7 días
  history: 10      ## Se mantienen 10 archivos de log como copia de seguridad

Para ejecutar la rotación de los logs, se debe utilizar periódicamente la tarea log-rotate. Esta tarea sólo borra los archivos para los que la opción rotate vale on. Se puede indicar una aplicación y un entorno específicos al utilizar esta tarea:

> symfony log-rotate miaplicacion prod

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.