Newsgroup: it.comp.lang.c++
Titolo: File log

Ho un programma diviso in diversi moduli che naturalmente lavora 
chiamando funzioni e dichiarando oggetti definiti/e in posti diversi. 
Sia per motivi di debug, che per fornire una rappresentazione del 
progresso dell'elaborazione, ho posto all'interno delle funzioni 
svariati messaggi a video (tramite cout) con l'indicazione 
dell'operazione in corso e il valore di alcune variabili in quel momento.
Tutto ok, tutto banale.
Ora mi domando: e se invece di mandarli a video questi messaggi volessi 
scriverli tutti su un unico file di log, come dovrei fare? Dovrei 
definire un oggetto ofstream globale e statico nel file main e poi 
dichiararlo come extern negli altri moduli?
-- 
www.project-ring.com

Il Vampiro Casimiro wrote:

una cosa più simpatica, imho, sarebbe piuttosto quella di definire delle 
funzioni e usare quelle: gli oggetti globali è sempre buona regola 
evitarli quando si può (e di solito si può sempre).
-- 
MSN: sirpsycho_78 -at- hotmail dot com

Il Vampiro Casimiro ha scritto:

Potresti definire una classe (es.: Logger)che implementa il design 
pattern Singleton, esisterebbe così una sola istanza in tutto il ciclo 
di vita del tuo programma a cui riferirsi per loggare.
Bye,
Giulio

 di vita del tuo programma a cui riferirsi per loggare.
Non avevo mai sentito parlare del design pattern singleton, grazie per 
la segnalazione. Mi sa che la faccio più semplice con una funzione che 
ha come parametro uno stringstream e scrive su un file in append, ma mi 
informo anche sulla tua soluzione.
Al momento ho trovato questo...
http://gethelp.devx.com/techtips/cpp_pro/10min/10min0200.asp
-- 
www.project-ring.com


Qui il singleton (e anche altri Design Pattern) sono descritti 
abbastanza bene, anche se implementati in C# (che è comprensibile) :
http://www.dofactory.com/Patterns/PatternSingleton.aspx
Utilizzare una classe per il logging è più OO rispetto ad una funzione, 
con la possibilità di nasconderne l'implementazione.
Mi viene in mente una classe astratta,con diverse specializzazioni tipo:
* logging a video
* su file
* via mail
Dipende se ti serve per qualcosa di concreto o solo per divertimento.
bye,
Giulio

 con la possibilità di nasconderne l'implementazione.
a prescindere dal discorso specifico, "soluzione più OO" non significa 
automaticamente soluzione migliore. Nello specifico invece, i Singleton 
non mi hanno mai convinto: che cosa c'è di così vantaggioso nello scrivere
int fuu()
{
	Singleton s = Singleton::getInstance();
	s.sua_funzione();
}
rispetto a
int bar()
{
	oggetto_globale.sua_funzione();


         oggetto_globale.sua_funzione();
Ci sono dei vantaggi. Nel primo caso hai un controllo maggiore
sull'istanziazione dell'oggetto. 'Singleton' potrebbe essere in interfaccia
astratta, 'getInstance' potrebbe decidere che tipo concreto instanziare.
Oppure, 'getInstance' potrebbe comportarsi diversamente in un programma
multithread e restituire un'instanza diversa per ogni thread. Inoltre,
sempre nel primo caso, puoi intercettare eventuali eccezioni lanciate
nell'instanziazione.
In generale, io preferisco che tutti gli oggetti siano instanziati dopo
l'inizio del 'main'.
Max

 
Io la vedrei più così :
int fuu()
{
	Singleton s = Singleton::getInstance()->loggaQuesto(...);
}
Con getInstance() e loggaQuesto() definite inline per migliorare le 
performance (ma questo dipende da come e con cosa si compila), sempre 
che non si scelga la soluzione con classe astratta e loggaQuesto() 
virtual, che in effetti cambia (niente inlining e un livello di 
indirezione).
In ogni caso il Singleton è una soluzione che funziona, de gustibus ...
nel caso di una funzione di logging su file, chi conserva il reference 
al file ?
* lo si potrebbe dichiarare globale
	* visibile a tutti
	* necessiterebbe di un'inizializzatore e finalizzazione
	  pericoloso perché potrebbe esserne dimenticate le invocazioni
* lo si potrebbe dichiarare static interno alla funzione
	* ad ogni chiamata sarebbe da testarne l'inizializzazione e nel
	  caso invocarne l'inizializzazione ... e per finalizzarlo ?
Non voglio criticare a prescindere la soluzione, ma sono problemi che mi 
vengono in mente a pensarci, sono curioso di vederne una soluzione non OOP.
Grazie,
ciao,
Giulio

 vengono in mente a pensarci, sono curioso di vederne una soluzione non OOP.
<logging.cpp>
class Logger
{
public:
	Logger()	{ /* ctor */ }
	~Logger()	{ /* dtor */ }
	//	altre funzioni membro
};
static Logger logger;
logdata(int severity, const char * fmt, ...)
{
	// definizione
}
</logging.cpp>
<logging.h>
logdata(int severity, const char * fmt, ...);
</logging.h>


Nella soluzione proposta (anche se in effetti non dettagliata) 
all'inizio del thread, parlavi di preferire funzioni e di cercare di 
evitare gli oggetti globali, qui invece utilizzi un oggetto dichiarato 
globalmente per poi utilizzarlo all'interno della funzione di logging, 
di fatto lo stesso numero di chiamate a funzioni innestate di un 
Singleton, ma sicuramente è più leggibile.
Ciao,
Giulio


una precisazione: non è un oggetto globale, è globale localmente al 
modulo logger.cpp (è dichiarato static).


 l'inizio del 'main'.
ok.


 Dipende se ti serve per qualcosa di concreto o solo per divertimento.
In effetti mi basterebbe qualcosa di semplice (per quanto brutto) che mi 
aiuti anche come metodo di debug (uso dev-ccp sul cui sistema di debug 
non mi trovo bene) e, che, a programma ultimato, potrei anche decidere 
di togliere.
Per esempio avevo semplicemente pensato di dichiarare globalmente un 
oggetto...
ostringstream logfile;
quindi mettere in ogni header interessato un
extern ostringstream logfile;
e a quel punto buttare i miei messaggi nello stream con delle semplici:
logfile << "Lancio della funzione di region growing blah blah\n";
disseminate per le varie funzioni.
Alla fine del main potrei decidere se salvare lo stream su file, 
lanciarlo a video oppure che, so, cancellarlo.
Ora, so che la soluzione e' brutta, ma mi basterebbe appunto che 
funzionasse, invece il compilatore mi da' errori del tipo "multiple 
definition of 'logfile'". Dove sbaglio?
-- 
www.project-ring.com

 
a occhio, se fai come hai scritto sopra, dovrebbe essere giusto. Forse 
ti sei scordato un "extern" da qualche parte.


Fred Mammola e il Tempio di Sdenk Settemani Urrins ha scritto:

No, gli "extern" ci sono tutti, inoltre se fosse quello il problema 
l'errore dovrebbe essere del tipo "multiple declaration", se non sbaglio.
-- 
www.project-ring.com

 
sbagli: dichiarazioni multiple in c++ sono consentite, ed è esattamente 
quello che fai già tu scrivendo "extern tipo_oggetto oggetto;" in più di 
un file di intestazione.


Fred Mammola e il Tempio di Sdenk Settemani Urrins ha scritto:

Ah, si', giusto. Allora non mi spiego l'errore del compilatore una volta 
verificato di aver messo tutti gli extern del caso.
-- 
www.project-ring.com

 
non so, oltre a dirti "cerca bene" non mi viene in mente altro..


 definition of 'logfile'". Dove sbaglio?
Non e' che hai messo
  ostringstream logfile;
in un file header?
In tal caso chiunque includesse quel file definirebbe un logfile, da
cui l'errore.
Quell'oggetto va invece definito  in un solo file (.cc) mentre gli
altri devono limitarsi a dichiararlo come extern.
Fabio