TigerZF
🌐Español

44.2. Escritores

Un Escritor (Writer) es un objeto que hereda de Zend_Log_Writer_Abstract. La responsabilidad de un Escritor es registrar los datos de log en un backend de almacenamiento.

44.2.1. Escritura en flujos (Streams)

Zend_Log_Writer_Stream envía los datos de log a un flujo (stream) de PHP.

Para escribir datos de log en el búfer de salida de PHP, utilice la URL php://output. Alternativamente, puede enviar los datos de log directamente a un flujo como STDERR (php://stderr).

$writer = new Zend_Log_Writer_Stream('php://output');
$logger = new Zend_Log($writer);

$logger->info('Informational message');

Para escribir datos en un archivo, utilice una de las URLs del sistema de archivos:

$writer = new Zend_Log_Writer_Stream('/path/to/logfile');
$logger = new Zend_Log($writer);

$logger->info('Informational message');

Por defecto, el flujo se abre en modo de anexado ("a"). Para abrirlo con un modo diferente, el constructor de Zend_Log_Writer_Stream acepta un segundo parámetro opcional para el modo.

El constructor de Zend_Log_Writer_Stream también acepta un recurso de flujo existente:

$stream = @fopen('/path/to/logfile', 'a', false);
if (! $stream) {
    throw new Exception('Failed to open stream');
}

$writer = new Zend_Log_Writer_Stream($stream);
$logger = new Zend_Log($writer);

$logger->info('Informational message');

No puede especificar el modo para recursos de flujo existentes. Hacerlo provoca que se lance una Zend_Log_Exception.

44.2.2. Escritura en bases de datos

Zend_Log_Writer_Db escribe la información de log en una tabla de la base de datos usando Zend_Db. El constructor de Zend_Log_Writer_Db recibe una instancia de Zend_Db_Adapter, un nombre de tabla, y una asignación de las columnas de la base de datos a los elementos de datos del evento:

$params = array ('host'     => '127.0.0.1',
                 'username' => 'malory',
                 'password' => '******',
                 'dbname'   => 'camelot');
$db = Zend_Db::factory('PDO_MYSQL', $params);

$columnMapping = array('lvl' => 'priority', 'msg' => 'message');
$writer = new Zend_Log_Writer_Db($db, 'log_table_name', $columnMapping);

$logger = new Zend_Log($writer);

$logger->info('Informational message');

El ejemplo anterior escribe una única fila de datos de log en la tabla de la base de datos llamada 'log_table_name'. La columna de la base de datos llamada 'lvl' recibe el número de prioridad y la columna llamada 'msg' recibe el mensaje de log.

44.2.3. Escritura en Firebug

Zend_Log_Writer_Firebug envía los datos de log a la Consola de Firebug.

Todos los datos se envían a través del componente Zend_Wildfire_Channel_HttpHeaders que utiliza cabeceras HTTP para asegurar que el contenido de la página no se vea alterado. Es posible depurar peticiones AJAX que requieren respuestas JSON y XML limpias con este enfoque.

Requisitos:

Ejemplo 44.1. Registro con Zend_Controller_Front

// Place this in your bootstrap file before dispatching your front controller
$writer = new Zend_Log_Writer_Firebug();
$logger = new Zend_Log($writer);

// Use this in your model, view and controller files
$logger->log('This is a log message!', Zend_Log::INFO);

Ejemplo 44.2. Registro sin Zend_Controller_Front

$writer = new Zend_Log_Writer_Firebug();
$logger = new Zend_Log($writer);

$request = new Zend_Controller_Request_Http();
$response = new Zend_Controller_Response_Http();
$channel = Zend_Wildfire_Channel_HttpHeaders::getInstance();
$channel->setRequest($request);
$channel->setResponse($response);

// Start output buffering
ob_start();

// Now you can make calls to the logger

$logger->log('This is a log message!', Zend_Log::INFO);

// Flush log data to browser
$channel->flush();
$response->sendHeaders();

44.2.3.1. Definir estilos para las prioridades

Las prioridades integradas y las definidas por el usuario pueden ser estilizadas con el método setPriorityStyle().

$logger->addPriority('FOO', 8);
$writer->setPriorityStyle(8, 'TRACE');
$logger->foo('Foo Message');

El estilo por defecto para las prioridades definidas por el usuario se puede establecer con el método setDefaultPriorityStyle().

$writer->setDefaultPriorityStyle('TRACE');

Los estilos admitidos son los siguientes:

Tabla 44.2. Estilos de registro de Firebug

Estilo Descripción
LOG Muestra un mensaje de log sencillo
INFO Muestra un mensaje de log informativo
WARN Muestra un mensaje de log de advertencia
ERROR Muestra un mensaje de log de error que incrementa el contador de errores de Firebug
TRACE Muestra un mensaje de log con una traza de pila desplegable
EXCEPTION Muestra un mensaje de error largo con una traza de pila desplegable
TABLE Muestra un mensaje de log con una tabla desplegable


44.2.3.2. Preparación de datos para el registro

Aunque cualquier variable PHP puede registrarse con las prioridades integradas, se requiere un formato especial si se utilizan algunos de los estilos de log más especializados.

Los estilos LOG, INFO, WARN, ERROR y TRACE no requieren formato especial.

44.2.3.3. Registro de excepciones

Para registrar una Zend_Exception simplemente pase el objeto de excepción al registrador (logger). No importa qué prioridad o estilo haya establecido, ya que la excepción es reconocida automáticamente.

$exception = new Zend_Exception('Test exception');
$logger->err($exception);

44.2.3.4. Registro en formato de tabla

También puede registrar datos y formatearlos con estilo de tabla. Las columnas se reconocen automáticamente y la primera fila de datos se convierte automáticamente en el encabezado.

$writer->setPriorityStyle(8, 'TABLE');
$logger->addPriority('TABLE', 8);

$table = array('Summary line for the table',
             array(
                 array('Column 1', 'Column 2'),
                 array('Row 1 c 1',' Row 1 c 2'),
                 array('Row 2 c 1',' Row 2 c 2')
             )
            );
$logger->table($table);

44.2.4. Escritura por correo electrónico

Zend_Log_Writer_Mail escribe las entradas de log en un mensaje de correo electrónico utilizando Zend_Mail. El constructor de Zend_Log_Writer_Mail recibe un objeto Zend_Mail, y un objeto opcional de Zend_Layout.

El caso de uso principal de Zend_Log_Writer_Mail es notificar a los desarrolladores, administradores de sistemas, o a cualquier parte interesada sobre errores que puedan estar ocurriendo con scripts basados en PHP. Zend_Log_Writer_Mail nació de la idea de que si algo está roto, un ser humano necesita ser alertado de inmediato para que pueda tomar medidas correctivas.

A continuación se describe el uso básico:

$mail = new Zend_Mail();
$mail->setFrom('errors@example.org')
     ->addTo('project_developers@example.org');

$writer = new Zend_Log_Writer_Mail($mail);

// Set subject text for use; summary of number of errors is appended to the
// subject line before sending the message.
$writer->setSubjectPrependText('Errors with script foo.php');

// Only email warning level entries and higher.
$writer->addFilter(Zend_Log::WARN);

$log = new Zend_Log();
$log->addWriter($writer);

// Something bad happened!
$log->error('unable to connect to database');

// On writer shutdown, Zend_Mail::send() is triggered to send an email with
// all log entries at or above the Zend_Log filter level.

Zend_Log_Writer_Mail renderizará el cuerpo del correo como texto plano por defecto.

Se envía un único correo electrónico que contiene todas las entradas de log al nivel del filtro o superiores. Por ejemplo, si se van a enviar por correo las entradas de nivel de advertencia en adelante, y ocurren dos advertencias y cinco errores, el correo resultante contendrá un total de siete entradas de log.

44.2.4.1. Uso de Zend_Layout

Se puede utilizar una instancia de Zend_Layout para generar la parte HTML de un correo multipart. Si se está utilizando una instancia de Zend_Layout, Zend_Log_Writer_Mail asume que se está usando para renderizar HTML y establece el cuerpo HTML del mensaje como el valor renderizado por Zend_Layout.

Cuando se utiliza Zend_Log_Writer_Mail con una instancia de Zend_Layout, tiene la opción de establecer un formateador personalizado mediante el método setLayoutFormatter(). Si no se especificó ningún formateador de entrada específico para Zend_Layout, se utilizará el formateador actualmente en uso. A continuación se describe el uso completo de Zend_Layout con un formateador personalizado.

$mail = new Zend_Mail();
$mail->setFrom('errors@example.org')
     ->addTo('project_developers@example.org');
// Note that a subject line is not being set on the Zend_Mail instance!

// Use a simple Zend_Layout instance with its defaults.
$layout = new Zend_Layout();

// Create a formatter that wraps the entry in a listitem tag.
$layoutFormatter = new Zend_Log_Formatter_Simple(
    '<li>' . Zend_Log_Formatter_Simple::DEFAULT_FORMAT . '</li>'
);

$writer = new Zend_Log_Writer_Mail($mail, $layout);

// Apply the formatter for entries as rendered with Zend_Layout.
$writer->setLayoutFormatter($layoutFormatter);
$writer->setSubjectPrependText('Errors with script foo.php');
$writer->addFilter(Zend_Log::WARN);

$log = new Zend_Log();
$log->addWriter($writer);

// Something bad happened!
$log->error('unable to connect to database');

// On writer shutdown, Zend_Mail::send() is triggered to send an email with
// all log entries at or above the Zend_Log filter level. The email will
// contain both plain text and HTML parts.

44.2.4.2. Resumen del nivel de error en la línea de asunto

El método setSubjectPrependText() puede utilizarse en lugar de Zend_Mail::setSubject() para que la línea de asunto del correo se escriba dinámicamente antes de enviar el correo. Por ejemplo, si el texto anteponible al asunto dice "Errors from script", el asunto de un correo generado por Zend_Log_Writer_Mail con dos advertencias y cinco errores sería "Errors from script (warn = 2; error = 5)". Si no se está utilizando texto anteponible al asunto mediante Zend_Log_Writer_Mail, se utiliza la línea de asunto de Zend_Mail, si la hubiera.

44.2.4.3. Advertencias

Enviar entradas de log por correo electrónico puede ser peligroso. Si las condiciones de error no se gestionan adecuadamente en su script, o si está haciendo un mal uso de los niveles de error, podría encontrarse en una situación en la que esté enviando cientos o miles de correos electrónicos a los destinatarios dependiendo de la frecuencia de sus errores.

Por el momento, Zend_Log_Writer_Mail no proporciona ningún mecanismo para regular o agrupar los mensajes de otra manera. Dicha funcionalidad debería ser implementada por el consumidor si es necesario.

Nuevamente, el objetivo principal de Zend_Log_Writer_Mail es notificar proactivamente a un ser humano sobre condiciones de error. Si esos errores se están gestionando de manera oportuna, y se están implementando salvaguardas para prevenir esas circunstancias en el futuro, entonces la notificación de errores por correo electrónico puede ser una herramienta valiosa.

44.2.5. Escritura en el log del sistema

Zend_Log_Writer_Syslog escribe las entradas de log en el log del sistema (syslog). Internamente, actúa como proxy de las funciones openlog(), closelog(), y syslog() de PHP.

Un caso útil para Zend_Log_Writer_Syslog es la agregación de logs de máquinas agrupadas (clustered) mediante la funcionalidad del log del sistema. Muchos sistemas permiten el registro remoto de eventos del sistema, lo que permite a los administradores de sistemas monitorizar un clúster de máquinas desde un único archivo de log.

Por defecto, todos los mensajes de syslog generados llevan el prefijo de la cadena "Zend_Log". Puede especificar un nombre de "aplicación" diferente con el que identificar dichos mensajes de log ya sea pasando el nombre de la aplicación al constructor o al método de acceso de la aplicación:

// At instantiation, pass the "application" key in the options:
$writer = new Zend_Log_Writer_Syslog(array('application' => 'FooBar'));

// Any other time:
$writer->setApplicationName('BarBaz');

El log del sistema también le permite identificar la "facilidad" (facility), o tipo de aplicación, que registra el mensaje; muchos registradores del sistema en realidad generan diferentes archivos de log por facilidad, lo que de nuevo ayuda a los administradores a monitorizar la actividad del servidor.

Puede especificar la facilidad del log ya sea en el constructor o mediante un método de acceso. Debe ser una de las constantes de openlog() definidas en la página del manual de openlog().

// At instantiation, pass the "facility" key in the options:
$writer = new Zend_Log_Writer_Syslog(array('facility' => LOG_AUTH));

// Any other time:
$writer->setFacility(LOG_USER);

Al registrar, puede seguir usando las constantes de prioridad por defecto de Zend_Log; internamente, se asignan a las constantes de prioridad de syslog() correspondientes.

44.2.6. Escritura en Zend Server Monitor

Zend_Log_Writer_ZendMonitor le permite registrar eventos mediante la API Monitor de Zend Server. Esto le permite agregar mensajes de log de todo su entorno de aplicación en una única ubicación. Internamente, simplemente utiliza la función monitor_custom_event() de la API de Zend Monitor.

Una característica particularmente útil de la API Monitor es que le permite especificar información personalizada arbitraria junto con el mensaje de log. Por ejemplo, si desea registrar una excepción, puede registrar no solo el mensaje de la excepción, sino pasar el objeto de excepción completo a la función, y luego inspeccionar el objeto dentro del monitor de eventos de Zend Server.

[Note] Zend Monitor debe estar instalado y habilitado

Para utilizar este escritor de log, Zend Monitor debe estar instalado y habilitado. Sin embargo, está diseñado de forma que si no se detecta Zend Monitor, simplemente actuará como un registrador NULL.

Instanciar el escritor de log ZendMonitor es trivial:

$writer = new Zend_Log_Writer_ZendMonitor();
$log    = new Zend_Log($writer);

Luego, simplemente registre mensajes como de costumbre:

$log->info('This is a message');

Si desea especificar información adicional para registrar junto con el evento, pase esa información en un segundo parámetro:

$log->info('Exception occurred', $e);

El segundo parámetro puede ser un escalar, objeto, o array; si necesita pasar múltiples piezas de información, la mejor manera de hacerlo es pasar un array asociativo.

$log->info('Exception occurred', array(
    'request'   => $request,
    'exception' => $e,
));

Dentro de Zend Server, su evento se registra como un "evento personalizado". Desde la pestaña "Monitor", seleccione el subelemento "Events", y luego filtre por "Custom" para ver los eventos personalizados.

Eventos en el panel Monitor de Zend Server

En esta captura de pantalla, los primeros dos eventos listados son eventos personalizados registrados mediante el escritor de log ZendMonitor. Puede entonces hacer clic en un evento para ver toda la información relacionada con él.

Detalle del evento en el Monitor de Zend Server

Al hacer clic en la subpestaña "Custom" se detallará cualquier información adicional que haya registrado al pasar el segundo argumento al método de registro. Esta información se registrará como la subclave info; puede ver que el objeto de la petición se registró en este ejemplo.

[Note] Integración con Zend_Application

Por defecto, los comandos zf.sh y zf.bat añaden la configuración para el recurso log de Zend_Application, que incluye la configuración para el escritor de log ZendMonitor. Adicionalmente, el ErrorController utiliza el registrador configurado para registrar las excepciones de la aplicación -- proporcionándole integración con eventos de Zend Monitor por defecto.

Como se señaló anteriormente, si la API Monitor no se detecta en su instalación de PHP, el registrador simplemente actuará como un registrador NULL.

44.2.7. Anular el escritor (stub)

El Zend_Log_Writer_Null es un stub que no escribe datos de log a ningún destino. Es útil para deshabilitar el registro o simular el registro durante las pruebas:

$writer = new Zend_Log_Writer_Null;
$logger = new Zend_Log($writer);

// goes nowhere
$logger->info('Informational message');

44.2.8. Pruebas con el Mock

El Zend_Log_Writer_Mock es un escritor muy simple que registra los datos en bruto que recibe en un array expuesto como propiedad pública.

$mock = new Zend_Log_Writer_Mock;
$logger = new Zend_Log($mock);

$logger->info('Informational message');

var_dump($mock->events[0]);

// Array
// (
//    [timestamp] => 2007-04-06T07:16:37-07:00
//    [message] => Informational message
//    [priority] => 6
//    [priorityName] => INFO
// )

Para limpiar los eventos registrados por el mock, simplemente establezca $mock->events = array().

44.2.9. Composición de escritores

No existe un objeto Escritor compuesto. Sin embargo, una instancia de Log puede escribir en cualquier número de Escritores. Para hacerlo, utilice el método addWriter():

$writer1 = new Zend_Log_Writer_Stream('/path/to/first/logfile');
$writer2 = new Zend_Log_Writer_Stream('/path/to/second/logfile');

$logger = new Zend_Log();
$logger->addWriter($writer1);
$logger->addWriter($writer2);

// goes to both writers
$logger->info('Informational message');