Newsgroup: it.comp.lang.c++
Titolo: quale log library

Avete dei consigli per una libreria di log in C/C++?
Come minimo deve potere "funzionare" sia sotto Linux che sotto Windows, 
meglio se anche sotto Solaris e BSD. Deve essere possibile scrivere i 
log almeno su console, file e in rete (di scrivere su syslog o nel log 
degli eventi non mi interessa molto). Sarebbe bello se oltre a potere 
scrivere dei testi nel log, potessi scrivere degli oggetti binari. Cosa 
non necessariamente banale dei log distribuiti su rete. Sarebbe bello 
che dopo x giorni i file di log siano cancellati, e che i log "vecchi" 
siano compressi.
Con google saltano fuori molte librerie. Se avete qualche consiglio su 
qualcosa che è bene che valuti prima, saranno molto ben accetti. Do per 
scontato che non ci sia tutto quello che voglio io nella libreia, e che 
quindi debba metterci le mani. Tra l'altro, se ne scelgo uno e 
abbandono la mia, la prima cosa che farò sarà "esportarla" in python e 
in dotnet.
-- 
Articolo 33 della Costituzione italiana: L'arte e la scienza sono 
libere e libero ne è l'insegnamento

 Avete dei consigli per una libreria di log in C/C++?
Ho trovato l'analogo a log4j per C++ :
http://log4cplus.sourceforge.net/
Puoi provare a vedere se ha tutto quello che ti serve.

 Puoi provare a vedere se ha tutto quello che ti serve.
Grazie, la guarderò per prima. Di librerie di log ce ne sono veramente 
a bizzeffe. Ho visto che ce né una in preparazione "dentro" boost, e 
avevo adocchiato quella di apache.


Io la usai 2 anni fa .... pero` ti avviso che per compilarla con forte`
per solaris ho smadonnato parecchio .... spero non debba usarla su
sun ...:) 
ciao
Pier Paolo


 sun ...:)
Spero proprio di no. Per fortuna pochissimi nostri clienti lavorano
con SUN, anche se ahime tra di essi c'è la Rai e ci capita di fare del
software per loro.
Però non mi hai detto come ti sei trovato con quella libreria. Bene?

 in dotnet.
python ha già una libreria di logging. Come mai vuoi fare il porting
di di una libreria c++?


 di di una libreria c++?
Oggi ho una mia libreria C++ parzialmente portabile. Mentre stavo
lavorando per completare la portabilità mi sono scontrato con la
libreria dei log. Pochi in azienda usano la mia libreria, quasi
nessuno usa una libreria decente, i più usano degli accrocchio
indegni.
Da queste considerazioni mi è venuta l'idea di rendere la mia libreria
multipiattaforma e multilinguaggio. Il multi linguaggio mi serve per
renderla sexy, ma poi mi spiego meglio. L'ipotesi di abbandonare il
mio codice la sto facendo in questo periodo per vedere se riesco a
fare un salto di qualità. Alla peggio mi tengo la mia, che già ho.
Due sono i punti cruciali di questa libreria.
Il primo punto è riuscire ad avere unico codice da mantenere e una
libreria dal codice uniforme su qualsiasi piattaforma e con qualsiasi
linguaggio. Esportare una libreria c++ in modo "nativo" sotto dotnet o
in python ho visto che è relativamente facile. Quindi non è un freno.
Tra l'altro pensando ai punti di prima ho cassato boost.python perché
il punto 4 era veramente problematico. Peccato perché il codice è
magico, ma qui esagero con le divagazioni.
Il secondo punto è che venga usata aziendalmente da un numero maggiore
di persone. Io non trovo molto saggio usare dotnet per molto nostro
software, ma di fatto spesso viene fatta questa scelta. Da qui la mia
"necessità" di esportare questa la libreria in dotnet. In python
invece lo voglio fare per motivi di evangelizzazione. Già adesso ho
convinto varie persone ad usare python per affrontare certe
problematiche, e vorrei continuare.
Tra le varie cose da cui potevo iniziare mi è sembrato che il problema
più urgente aziendalmente fosse adottare una libreria di log decente.
In realtà una libreria di log e di dump decente, anche a me spesso
capita di confondere le cose. Non sono un capo, quindi non posso
imporre ma solo convincere. Convincere magari con una libreria che fa
le cose fondamentali "bene" e sia "semplice" da usare. Tra l'altro
"personalmente" incomincio ad avere il problema che se scrivo su FS il
disco non ci sta dietro, da cui la necessità di potere "sparare" su
rete il trace del programmi in modo da potere scrivere su una batteria
di server di log in rete. Poi avrei un'idea personale per il dump dei
programmi che vanno in crash, ma non voglio divagare. Viste queste
necessità ho deciso di guardarmi intorno per vedere cosa c'è.
Quindi ho fatto la cosa più intelligente che potessi fare, intanto
chiedere.

 chiedere.

 vada in crash?
Su unix e` possibile intercettare i segnali tipo SIGFAULT e mandarli su 
un handler che puo` fare per esempio il dump dello stack trace nel file 
di log, alcune nostre applicazioni lo fanno, la cosa puo` non funzionare 
bene nel caso la memoria sia stata sporcata a tal punto che la libreria 
di log non sia in grado di funzionare, in tal caso si possono prendere 
provvedimenti x evitare che il crash handler si inloopi (tipicamente si 
disarma il segnale come PRIMA istruzione del crash handler).
Noi usiamo una libreria di log basata su "policy", ispirata dal libro di 
Alexandrescu. La libreria ha una policy di locking configurabile (posix, 
win32, none), una policy di output (file, stderr, stdout, udp, syslog, 
OutputDebugString...), una policy di abilitazione (livello di log 
configurabile). A sua volta la policy di output ha policy per la 
gestione del timestamping, dell'EOL, di prefixing...
A mio parere la libreria seppur piuttosto efficiente e flessibile e` un 
incubo da configuratre e soprattutto da mantenere perche` e` illeggibile 
da chiunque non sia super esperto di C++.
Nonostante stimi Alexandrescu e il collega che l'ha scritta sia un 
ottimo programmatore ritengo che sia un oggetto troppo complicato per 
quello che deve fare.
Configurare un oggetto di questo tipo richiede l'istanziazione di un 
oggetto specializzato con i giusti template, il che richiede la 
conoscenza degli oggetti sottostanti, conoscenza che e` molto + 
difficile da gestire rispetto a due o tre metodi con un paio di 
parametri che ti abilitano o meno il locking, che ti fanno stabilire il 
formato e che tipo di logging vuoi usare...
Senza parlare di quanto appesantisce la compilazione e la dimensione 
degli eseguibili un logger templatizzato :)
--
Bye,
  Gabry

per partire da qualcosa di essenziale, agile ed efficente si può
vedere questo
http://www.ddj.com/cpp/201804215?pgno=1

 degli eseguibili un logger templatizzato :)
Usare un adattatore?
(Suggerimento banale, ma naturale)

   Gabry

 
http://www.ddj.com/cpp/201804215?pgno=1
scusa mi sento un impedito, ma come cavolo si fa a scaricare roba da
quel sito? :)
cio
antonio


wrote:

non mi pare si possa scaricare nulla
sono solo piccoli esempi di codice
marco

 marco
"In this article, I present a simple—but highly useful—logging
framework that is typesafe, threadsafe (at line-level), efficient,
portable, fine-grained, compact, and flexible. The complete source
code, which works with Visual C++ 7.1, g++ 3.3.5, and CC 5.3 on Sun
and other platforms, is available at 
www.ddj.com/code/
."
ho capito male?
antonio



si, hai ragione
ftp://66.77.27.238/sourcecode/ddj/2007/0710.zip
contiene un file logcpp.zip che a sua volta contiene:
main.cpp
log.h
log1.h



grezie mille :)
antonio

> Credo che cercare una buona libreria in rete sia un'ottima idea.
Non è un po reinventare la ruota ? usare syslog ?
ciao
Pier Paolo


Esistono problemi di portabilità. Sotto windows al massimo c'è il
"visualizzatore eventi", e non m sembra saggio usarlo per metterci dei
log.

 vada in crash?
Di Linux ti hanno già spiegato; sotto windows il meccanismo è simile.
Il realtà quelle che pensavo io era ad un processo monitor che
controlla
processo worker. Quando questo worker va in crash il S.O avverte
questo monitor che prima fa il dump del processo, poi si attacca al
server di log, e gli spedisce il dump.
Il server di log lo dovrebbe mettere nella stessa cartella dei
log dell'applicativo controllato.
Moltiplica tutto per 100 processi che girano in contemporanea su vari
PC
(in realtà sono meno della metà, ma vorrei fare il gradasso)
Se ci pensi avere tutta la storia di ogni processo, e per quei due
che
vanno in crash avere il dump direttamente nella cartella dei log
sarebbe
una grande comodità.
Piuttosto non so bene se qualcosa di simile è fattibile su Linux, ma
sono convinto di si.

 che mi pare tu abbia già guardato.
Dopo i primi 5 secondi l'ho bocciata. Poi ci guarderò meglio e non 
superficialmente come ho fatto adesso, ma osservando gli esempi 
partiamo già male. A parte l'onnipresente uso di macro che non mi 
sfagiola il problema lo vedo già qui:
std::string hello = "hello", world = "world";
LAPP_ << hello << ", " << world;
In un ambiente multi thread come minimo si mischiano le scritture. Quel 
codice viene tradotto in tre chiamate di questo tipo:
LAPP_ << hello ;
LAPP_ << ", " ;
LAPP_ << world;
e questo non è bello. Non puoi metterci un lock a livello di intero 
messaggio. Nel mio codice del mio log la chiamata è simile a questa:
log.Write(livello, hello, ", " , world);
in modo che dentro la write la prima istruzione in pseudo codice è come 
se così:
template< typename T1, typename T2, typename T3>
inline void QuackLog::Write(int livello, const T1& t1, const T2& t2, 
const T3& t3)
{
  lock();
  //bla bla
  unlock();


 messaggio.
una soluzione che usi l'operate di ridirezione e sia thread-safe è
descritta qui
http://www.ddj.com/cpp/201804215?pgno=1
sulla base dell'articolo, una mia piccola implementazione è
disponibile qui:
http://depaolim.googlepages.com/logging

 
http://depaolim.googlepages.com/logging
Occhio che localtime e` thread safe solo su windows (in sistemi posix 
devi usare localtime_r), inoltre la scrittura su file non e` thread 
safe, quindi ti converrebbe aggiungere un mutex legato all'oggetto Stream.
Sinceramente sono anche dubbioso sull'implementazione threadsafe 
dell'operatore << di molti compilatori C++...
Per esempio ad occhio nel GCC funziona bene solo se si compila con 
-pthread, se si linka con -lpthread non da alcun errore ma produce 
risultati errati, ecco un programma di test (la classe thread non la 
posto, ma fa quello che fa ogni classe thread, crea il thread con 
pthread_create() su start e in questo caso avvia worker_thread), sarei 
curioso di vedere come si comporta il visual studio.
#include <iostream>
#include <thread.h>
class Pippo : public Thread
{
         int val_;
     public:
         void Value(int v) { val_ = v; }
         void worker_thread() {
             for (int i = 0; i < 10; i++) {
                 std::cerr << i << ')' << val_ << val_ << val_ << val_ 
<< val_ << 'e' << std::endl;
                 sleep(1);
             }
         }
};
int main()
{
     Pippo pippi[10];
     for (int i = 0; i < 10; ++i) {
         pippi[i].Value(i);
         pippi[i].start();
     }
     sleep(100);
}
Compilando con: g++ -o test test.cpp thread.cpp -lpthread
gabry@nevada:/tmp$ ./test
0)0)77777e
0)66666e
0)90)22222e
0)44444e
00000e
0)11111e
9999e
0)0)55555e
80)33333e
8888e
1)77777e
1)66666e
1)22222e
1)99999e
1)00000e
1)11)88888e
1)55555e
1)33333e
1111e
[...]
Compilando con: g++ -o test test.cpp thread.cpp -pthread
gabry@nevada:/tmp$ ./test
0)00000e
0)11111e
0)33333e
0)44444e
0)55555e
0)77777e
0)99999e
0)66666e
0)88888e
0)22222e
1)00000e
1)11111e
1)44444e
1)33333e
1)55555e
1)99999e
1)66666e
1)77777e
1)22222e
1)88888e
2)00000e
2)11111e
2)44444e
2)33333e
2)55555e
2)99999e
2)66666e
[...]
Bye,
  Gabry

 dell'operatore << di molti compilatori C++...
infatti non è richiesto che l'operatore << sia thread-safe
l'operatore viene usato su un oggetto automatico (di tipo Log) e solo
alla fine riversato sul vero e proprio file di log
ciao,
Marco

 sono convinto di si.
ciao

o no?
No, anche perché non c'è un meccanismo standard per "lockare" i
thread.

 thread.
parlando di VC8 sembra invece che il tutto sia thred-safe...
C:\Program Files\Microsoft Visual Studio 8\VC\crt\src\fprintf.c
        _lock_str(stream);
        __try {
        _VALIDATE_STREAM_ANSI_SETRET(stream, EINVAL, retval, -1);
                if(retval==0)
                {
                        buffing = _stbuf(stream);
                        retval =
_output_l(stream,format,NULL,arglist);
                        _ftbuf(buffing, stream);
                }
        }
        __finally {
            _unlock_str(stream);
        }
Notare che _lock_str è una define che rimappa su _lock_file
(documentato qui: 
http://msdn.microsoft.com/en-us/library/8w5bsb4f(VS.80).aspx
)
che dovrebbe implementare appunto quello che ci serve
...d'altra parte mi chiedo che senso avrebbe il CRT multithread se non
garantisse almeno un accesso in regione critica alle singole funzioni
Fino ad ora anche io avevo sempre usato i semafori prima di accedere
allo stream dei log e uno dei motivi per cui mi era piaciuta la
soluzione proposta dall'articolo era il poter evitare i miei semafori
e contare su quelli che esistono comunque già a livello sottostante
per la cronaca gli altri motivi per cui mi è piaciuto l'approccio
dell'articolo sono:
Primo:
una macro pulita che rende le chiamate alle funzione di log molto
efficenti:
a costo minimo (comporta solo un confronto fra due interi) qualora si
disattivi a run-time il log oltre un certo livello e a costo nullo
qualora si disattivi a compile time il log oltre un certo livello
Secondo:
la possibilità di usare l'operatore di ridirezione al posto di una
chiamata a funzione
(approccio, a mio parere, molto più flessibile)
Marco

parlando di VC8 sembra invece che il tutto sia thred-safe...
Meglio cosě. Io comunque parlavo del fatto che non c'č un meccanismo
standard, per cui a priori non puoi dare nulla per scontato.

 libere e libero ne � l'insegnamento

 chiamata a funzione
Quello lo potresti ottenere anche così (codice che SICURAMENTE non 
compila, lo scrivo di getto):
template<typename T>
class Q()
{
public:
  std::string Str() const;
  Q& operator <<(T t)
  {
     //funzione di conversione
     return *this;
  }
};
class Log
{
public:
  void Write( Q quack_stream )
  {
    std::string s = quack_stream.Str();
    //scrittura della stringa da qualche parte
  }
};
int main(..)
{
  Log log;
  //settaggi vari del log
  log.Write( Q() << "Pippo " << 'è' << 1 << " cane" );


 La libreria che ho in mente è proprio logging di python.
Lo sto guardando adesso per altri motivi. Ha quasi tutto ciò che 
vorrei. La documentazione non è fenomenale, ma il codice è molto 
commentato. Devo studiarla per vedere se ha delle magagne per il mio 
uso. Di primo acchito mi piace molto.
Per ora il la voglio in C++!! :-)
In realtà ho anche un problema contingente. Scegliere quale supporto di 
runtime per la "multipiattaformità" (scusa il terribile neologismo). 
Libreria scritta da me (soluzione che voglio abbandonare), boost 
(soluzione caldeggiata internamente), apache (che vorrei guardare per 
principio), altro?
Ora avere un libreria di log che usa un suo strato multipiattaforma mi 
sembra andare a cercarsi dei guai.
In più, a cercarsi le rogne, potrei avere il problema dell'encoding. 
L'encoding del file di log può essere deciso dall'utilizzatore? I 
messaggi vanno "tradotti"? Tieni conto che già oggi ne tengo conto 
visto che l'encoding della console sotto windows è uno, e l'encoding di 
default dei file è un'altro.
Ho le idee ancora confuse su quanta complessità mettere nel logger. 
Anche se per ora sono (molto) dubbioso sul log di boost, mi sembra di 
capire che con log4cpp e log4cxx non me la caverò in 5 minuti per avere 
una panoramica generale.


 default dei file è un'altro.
Certo avere a che fare con gli encoding e' spesso un incubo ma in
questo caso non lo vedo un problema catastrofico.


 questo caso non lo vedo un problema catastrofico.
Che io sappia esistono due sole librerie "decenti": ICU (enorme), 
iconv. Ci sarebbe anche quella di windows, ma non è portabile 
(ovviamente), oltre che essere progettata da un demente. La prima ICU 
per molti versi è ipercompleta, per me sarebbe anche l'ideale anche 
molti altri motivi ma è anche complessa. La seconda è semplice da usare 
ed è già tradotta sotto windows da apache, anche se onestamente un 
porting l'avevo fatto anche io.
Poi ne esisteranno altre, ma non le conosco.
In un ambiente cluster multipiattaforma, e potrebbe essere il mio caso, 
avere un file di log codificato utf-8 proveniente da una macchina linux 
e un altro in windows-1252 proevniente da una macchina windows potrebbe 
essere una rogna. O magari no, non mi sono ancora chiari quali sono i 
compromessi accettabili. Pensare fin dall'inizio a questa possibilità 
potrebbe essere più saggio che pensarci dopo. Poi ovviamente c'è la 
fregatura che se di default il log trascodifica un messaggio, magari 
alcuni (tutti?) i messaggi di errore non devono essere trascodificati. 
Anche qui non ho le idee chiare. Lavoro abitualmente con stringhe 
dall'encoding multiplo, ma per ora, con le stringhe che non adottano 
l'encoding di default del S.O., me la cavo scrivendo dei dump in cui ad 
una stringa corrisponde un file.
Probabilmente questo non è più accettabile. Penso ad al bocchettone di 
un "mio" programma che accetta come input un XML. Questo ora potrebbe 
essere codificato ora con un chartset, e poi con un altro. Nel file di 
log che ci scrivo? Mi viene da dire che scrivere il binario è la cosa 
migliore da fare (quel che faccio adesso n.d.p.), anche se questo rende 
difficilmente leggibile il file (che sarebbe con un charset multiplo).


 }
il problema è che in questo modo tutto il conto sulle stringhe
(costruzione, concatenazione, etc. etc.) viene fatto anche se non poi
non logghi in quanto il livello è inferiore al minimo.
Anche la stessa chiamata log.Write viene eseguita comunque
Viceversa una riga di codice scritta così:
  LOG(Log::TRACE) << "Pippo " << 'è' << 1 << " cane";
oltre ad ottenere l'effetto sopra (nessuna chiamata ne calcolo se non
serve), permette ad un client che vuole semplicemente loggare, di
poter essere ignaro di: istanza dell'oggetto Log, metodo Write,
oggetto Q
Marco

 libere e libero ne � l'insegnamento

 riesca a convincere quelli di Apache ad usare la tua versione
Io realtà voglio solo convinverMi ad usare il "run-time" di Apache, non 
viceversa. Oppure boost, oppure quello che sarà.
Poi ho il problema di dotnet in cui non abbiamo una libreria di log 
decente. Python, per ora, lo uso sempre in sistemi "integrati" con un 
"padre" scritto in C++, e per comodità uso il mio logger scritto in 
C++. Anche se mi rendo benissimo conto che non è "potente" come quello 
nativo in python.
Considero anche io saggio, come dici tu, di usare una libreria come una 
scatola nera. Però come dice un mio collega, ci vogliono 8 ore per 
compilare boost su Itanium. Non vorrei arrivare al paradosso che per 
fare un hello word ci vogliano 24 di compilazione, con megabyte di 
codice linkato al programma, per soddisfare le esigenze delle varie 
librerie.
-- 
Articolo 33 della Costituzione italiana: L'arte e la scienza sono 
libere e libero ne è l'insegnamento

 Poi ho il problema di dotnet in cui non abbiamo una libreria di log
http://logging.apache.org/
c++
java
.net
php


 non logghi in quanto il livello è inferiore al minimo.
Non ci avevo pensato. Cavolo adesso devo inventare qualcosa che non va 
nel tuo codice per non esagerare con le brutte figure :-)
Muble, muble. Proviamo questa: la fregatura della tua versione che hai 
un temporaneo in cui devi memorizzare le cose. Nel momento prima della 
eventuale scrittura quindi la dimensione occupata è il doppio. E' un 
pessimo italiano quindi procedo all'esempio:
Se devi loggare 100 Mb di testo; l'istruzione
LOG(Log::TRACE) << StringaDa100MB;
arriva a consumare 200 MB, 100 per la stringa e 100 per il dato 
temporaneo.
La soluzione migliore penso sia:
class Nulla{};
template<typename T1,typename T2=Nulla, typename T3=Nulla, ...>
class LogPapero
{
 ...
public :
  void Write(int livello, const T1& dato1, const T2& dato3, .., const 
Tn& daton);
};
In questo caso non ci sono temporanei. Tra l'altro io non credo di 
avere mai usato più di 4 parametri per una scritta di log in tutta la 
mia vita programmatoria.
Soluzione che stavo adottando per la nuova versione del mio logger, ma 
poi mi sono fermato, e ho deciso che esa più saggio vedere cosa c'era 
in giro. Da cui questo mio thread.


 php
Fantastico! A parte php che non usiamo in ditta, e python che manca, il 
resto mi serve proprio tutto. Sarà il primo logger c++ che cercherò di 
studiare un minimo decentemente.
Se interessa, cosa su cui non metterei di sucuro una mano sul fuoco,  
riporterò qui le mie impressioni.


 mia vita programmatoria.
ma poi questi dati come li scrivi su log?
nella scrittura devi essere atomico (altrimenti gli n dati sono
intercalati da altri dati loggati da altri) e ragionevolmente
efficente
Petru Marginean (l'autore dell'articolo su cui mi sono basato) propone
di concatenare anticipatamente e trasparentemente (ossia in modo
trasparente al client della class Log) i dati in ram e poi fare un
unica operazione di scrittura (atomica grazie a fprintf e flush thread-
safe)
... daltra parte spero che nessuno logghi 100 MB al colpo ;-)
Marco

 ... daltra parte spero che nessuno logghi 100 MB al colpo ;-)
Non lavori con dotnet. Un nostro programma appenna meno che scemo è un 
attimo che abbia un impronta in memoria di 100 Mb. Il profiler gratuito 
di Microsoft per dotnet (in realtà un ottimo analizzatore di memoria) 
scrive log da GB. Accidentaccio.
Davide


 scritture.
ok vedi che hai di nuovo una regione critica gestita da te (con in più
n scritture su file)?
nel mio esempio non c'è nessuna regione critica: si sfruttano quelle
date "in bundle" con il CRT multithread
mah... per concludere:
grazie di tutte i tuoi commenti: mi hanno aiutato, tra l'altro, ad
essere più consapevole di vincoli che sono disposto ad accettare e
libertà che voglio mantenere
continuo a ritenere l'approccio di Marginean elegante ed essenziale:
non ha ovviamente la pretesa di sostituire un intera libreria di
logging tipo apache, ma tenendo conto che il pezzo di codice che ho
scritto ha meno di 200 righe (comprese chiamate di esempio) e risolve
tutti i problemi più tipici... non mi sembra malaccio
ultimo appunto...
qui in passato abbiamo usato una libreria di logging "completa" (credo
log4cpp, non vorrei sbagliare) beh... a un certo punto l'abbiamo
gettata dalla finestra: mantenere la libreria di logging era un
ulteriore grattacapo in caso di porting (es. versione di Visual Studio
6-7-8, 32/64 bit etc.) per non parlare delle dipendenze che si portava
dietro.
Quando l'abbiamo eliminata per tornare al caro vecchio file di log
gestito da noi, abbiamo dovuto riscorrere il codice per sostituire le
chiamate di log e le chiamate che configuravano il log (Writers,
Formatters e amenicoli vari)
conclusione:
non voglio più sporcare il mio codice con chiamate di log complicate,
più semplici sono più sono garantito nel tempo
non voglio più linkare librerie ciclopiche e passibili di obsolescenza
e se per caso cambiassi idea sul secondo punto (perchè magari voglio
il log su database, come dicevi tu) voglio che le parti di codice che
loggano non si rendano conto se dietro c'è un banale file o il tutto
viene crittato ed inviato al presidente degli stati uniti (... che
presumibilmente lo classifica come spam :-)
Ciao,
Marco