Visualizzazione post con etichetta Log. Mostra tutti i post
Visualizzazione post con etichetta Log. Mostra tutti i post

19 febbraio 2010

Eseguire il redirect degli output di un batch in un file di log su Windows

Qualche semplice suggerimento per eseguire il redirect degli output dell'esecuzione di un file batch su windows.

E' necessario sapere che ci sono 2 livelli di output in maniera analoga ai sistemi Linux/Unix, il primo livello è lo STANDARD OUTPUT mentre il secondo livello è lo STANDARD ERROR.
Per cui le applicazioni ridirezionano gli output su questi 2 livelli a seconda delle esigenze.

Come è possibile salvare gli output dell'esecuzione di un batch?

Per poter eseguire delle prove creare con blocco note un nuovo di nome "test.bat" e copiare al suo interno i seguenti comandi :


@ECHO OFF
ECHO This text goes to Standard Output
ECHO This text goes to Standard Error 1>&2


Eseguendo il file "test.bat" da riga di comando (Start->Esegui..->cmd) otterremo il seguente risultato :

C:\>test.bat
This text goes to Standard Output
This text goes to Standard Error


REDIRECT DEGLI STANDARD OUTPUT SU FILE DI LOG

Eseguendo il comando "test.bat > logFile.log" otterremo il seguente risultato :
C:\>test.bat > logFile.log
This text goes to Standard Error


nel file di log logFile.log il contenuto sarà il seguente :
This text goes to Standard Output



REDIRECT DEGLI STANDARD ERORR SU FILE DI LOG

Eseguendo il comando "test.bat 2> logFile.log" otterremo il seguente risultato :
C:\>test.bat 2> logFile.log
This text goes to Standard Output


nel file di log logFile.log il contenuto sarà il seguente :
This text goes to Standard Error


REDIRECT DI TUTTI GLI OUTPUT SU UN UNICO FILE DI LOG

Eseguendo il comando "test.bat > logFile.log 2>&1" otterremo il seguente risultato :
C:\>test.bat > logFile.log 2>&1


nel file di log logFile.log il contenuto sarà il seguente :
This text goes to Standard Output
This text goes to Standard Error


N.B : è possibile loggare separatamente errori e output su 2 files differenti con il comando "test.bat > logFile.log 2> logFile.2.log"

E' possibile anche evitare che errori o output non siano visualizzati nè loggati. Nel seguente esempio verranno visualizzati solo gli errori tramite il comando "test.bat > NUL"

C:\>test.bat > NUL
This text goes to Standard Error

11 gennaio 2009

Scrivere file di log con php

E' indispensabile sia in fase di sviluppo che di manutenzione di un sito php utilizzare dei files di log per intercettare gli errori o comunque ricostruire il comportamento o il valore delle variabili prima che lo stesso si verifichi.
Per venire in contro agli sviluppatori ci sono framework come log4j tramite cui è possibile "smistare" la scrittura dei log su diversi files.
Personalmente ho ritenuto più semplice e leggero implementare una mia versione di un manager per i log.

Innanzitutto vediamo i parametri di configurazione che utilizzerà il Manager dei log:
 // logging 
$log_path = "log/";
$debugLogFile = "debug.log";
$errorLogFile = "error.log";

define("LOGPATH", $log_path);
define("DEBUGFILE", $debugLogFile);
define("DEBUGLOG", 'DEBUGLOG');
define("ERRLOG", 'ERRLOG');
define("ERRORFILE", $errorLogFile);

Le righe relative alle define hanno essenzialmente lo scopo di dichiarare delle costanti utilizzabili in qualsiasi scope dell'applicazione.

Di seguito l'implementazione del Manager vero e proprio:
/***
* Classe per il logger
*
* @author Alessandro Franzi
*
*/
Class ManageLogger{

private $FILELIST = array();
private $HANDLER = array();
private $ROOT = "";
private $WIN32 = false;
private $FORMAT = "%b %d %H:%M:%S";
private $DEBUG = true;

/***
* Costruttore della classe logger
*/
public function ManageLogger ( $LogRoot, $FileArray = "" ){
if(empty($LogRoot)){
// se non è stata specificata la root del logger
if($this->DEBUG){
error_log("[ErrorLog]: C'è bisogno della Root Folder per creare il logger",0);
}
return;
}
$this->set_root($LogRoot);
if(!empty($FileArray)){
// se non è vuoto l'array contenente i nomi dei files di log
$this->initialize($FileArray);
}
return;
}

/***
* Inizializza l'array dei file di log
*/
public function initialize ($FileArray){
if ( (gettype($FileArray)) != "array"){
if($this->DEBUG){
error_log("[ErrorLog]: Tipo di Array per i file di log invalido",0);
}
return;
}
while ( list ($key,$val) = each ($FileArray) ){
if ( (!empty($key)) and (!empty($val)) ){
// associo i vari file di log al relativo compito
$val = "$this->ROOT"."$val";
$this->FILELIST[$key] = $val;
$this->HANDLER[$key] = null;
}
}
return;
}

/***
* Metodo per scrivere il log
*
*/
public function log ($Handle,$LogEntry)
{
global $php_errormsg;

$filename = $this->FILELIST[$Handle];
$TimeStamp = strftime($this->FORMAT,time());
// associo la mia formattazione alla stringa
$LogEntry = "$TimeStamp - $LogEntry";

if (!$this->HANDLER[$Handle]){
$fd = fopen($filename,"a");
if ( (!$fd) or (empty($fd)) ){
if($this->DEBUG)
{
error_log("[ErrorLog]: Errore fatale sul file: $php_errormsg",0);
}
return;
}
fwrite($fd,"$LogEntry\n");
$this->HANDLER[$Handle] = $fd;
}else{
fwrite($this->HANDLER[$Handle],"$LogEntry\n");
}
return;
}

/***
* Metodo per chiudere i file di log
*/
public function close_logs (){
while ( list ($Handle, $Val) = each ($this->FILELIST) ){
if($this->HANDLER[$Handle]){
$TimeStamp = strftime($this->FORMAT,time());
fclose($this->HANDLER[$Handle]);
unset($this->HANDLER[$Handle]);
}
}
}

/***
* Metodo per settare la root dei file di log
*/
public function set_root ($root){
if(!$this->WIN32){
if(!ereg("\/$",$root)){
$root = "$root"."/";
}
if(is_dir($root)){
$this->ROOT = $root;
}else{
$this->ROOT = "";
if($this->DEBUG){
error_log("La root specificata: [$root] non è una directory",0);
}
}
}else{
// Macchine Winzozz
if(!ereg("\\$",$root)){
$root = "$root"."\\";
}
$this->ROOT = $root;
}
}
/***
* Metodo per loggare messaggi di errore
*
*/
public function error ($messaggio){
$this->log(ERRLOG,"[".pagina::getNomePagina()."] - ".$messaggio);
}
/***
* Metodo per loggare messaggi di debug
*
*/
public function debug ($messaggio){
$this->log(DEBUGLOG,"[".pagina::getNomePagina()."] - ".$messaggio);
}

/***
* Distruttore della classe che invoca la chiusura dei file di log
*/
public function __destruct() {
$this->close_logs();
}
}

Osserviamo come istanziare e inizializzare il ManageLogger :
$ManageLogger = new ManageLogger("./".LOGPATH);
$ManageLogger->initialize(array('ERRLOG' => ERRORFILE ,'DEBUGLOG' => DEBUGFILE));

E' chiaro che se si volessero utilizzare altri appender per i file di log, basterebbe aggiungerli all'array.
Queste sezioni di codice sarebbero sufficienti per poter avere un logger funzionante, richiamando i metodi opportuni (debug e error) sul manager, ma è sicuramente più comodo implementare una classe mediante cui interfacciarsi con il manager.
Il compito della classe Logger infatti è proprio quella di utilizzare i metodi del manageLogger da noi facilmente raggiungibile mediante i suoi metodi statici.
Ecco infine l'implementazione :
/**
* Depends : ManageLogger
* Classe di controllo per l'istanza dell'oggetto ManageLogger
*
* @author Alessandro Franzi
*
*/
class Logger{
/***
* Metodo statico per la stampa del log di debug
*/
public static function debug ($msg) {
global $ManageLogger;
$ManageLogger->debug($msg);
}
/***
* Metodo statico per la stampa del log di errore
*/
public static function error ($msg,$e=null) {
global $ManageLogger;
$ManageLogger->error($msg);
if ($e!=null){
$ManageLogger->error("Causa : ".$e->getMessage()."\nStackTrace : ".$e->getTraceAsString());
}
}
}

Vediamo quindi come poter utilizzare nel nostro codice i log:
// esempio di logging dell'errore in un blocco try/catch
try{
....
}catch(Exception $e){
logger::error("Eccezione",$e);
}
// esempio di logging per il debug
Logger::debug("Il valore della variabile a è ".$a);

Un buon utilizzo dei logger in fase di sviluppo certamente renderà molto più semplice eseguire manutenzioni correttive sullo stesso. Spero che questo codice sia semplice da comprendere, naturalmente sono ben accetti consigli o correzioni sullo stesso.