Come aggiungere la registrazione a una libreria in modo che possa integrarsi facilmente con il sistema di registrazione del programma utilizzando la libreria?

5

Sto scrivendo una libreria che ha molte informazioni che possono essere utili in un log nel programma che la usa, ma non conosco il modo migliore per esporla in modo tale che il programma usi la mia libreria può integrare i log della mia biblioteca con i propri registri in modo inequivocabile (se lo si desidera).

Scegliere una libreria di registrazione specifico per la mia biblioteca aggiunge alla lista delle dipendenze per usare la mia biblioteca e lega il programma principale di quella biblioteca - e se più librerie utilizzate dal programma principale ha fatto questo, ci potrebbero hanno ciascuno selezionato una libreria diversa.

Ho pensato di fare in modo che il programma registri un oggetto flusso C ++ con la libreria da usare. Sembra che sarebbe uno scopo relativamente generale, ma ho anche pensato che il programma principale avrebbe registrato una funzione di callback che sarebbe stata richiesta con i contenuti e i metadati quando i dati sono registrati. Un'altra opzione sarebbe semplicemente quella di archiviare i dati del registro nella libreria in una sorta di elenco per il programma principale da afferrare ogni volta che vuole trattare con quei dati, lasciando che il programma principale decida quando ha il tempo di trattare i dati.

Sto cercando suggerimenti e pro / contro di diversi approcci, così posso decidere cosa è meglio nella mia situazione.

Grazie.

    
posta xaxxon 08.06.2017 - 00:06
fonte

2 risposte

7

Puoi esporre più metodi per ricevere la registrazione dalla tua libreria e avvolgere tutti tranne uno degli adattatori su quello "reale" utilizzato nella libreria.

es. decidi di avere internamente una raccolta std::function<void(std::string)> che è ogni callback del logger. Fornisci:

void registerLogCallback(std::function<void(std::string)> callback); 
// Main logging implemention

e anche

registerLogStream(std::ostream stream) { 
    registerLogCallback([stream](std::string message){ stream << message; }); 
}

e anche

template<typename OutputIterator>
registerLogOutputIterator(OutputIterator iter) { 
    registerLogCallback([iter](std::string message){ *iter++ = message; }); 
}

e qualsiasi altra variante di tipi "recieve stringhe da qualche parte" a cui tieni di implementare gli adattatori.

    
risposta data 08.06.2017 - 00:28
fonte
4

Il modo più semplice per consentire a un'applicazione di essere in grado di sfruttare la funzionalità di registrazione è consentirgli di registrare una classe / funzione per ricevere il messaggio di registro. Quello che fanno con quel messaggio dipende interamente dall'applicazione.

Usando C / C ++, puoi usare quanto segue nella tua libreria:

typedef void (*LogMessageReceiver)(char const* message,
                                   void* user_data);

void registerLogMessageReceiver(LogMessageReceiver receiver,
                                void* user_data);

Un'applicazione può registrare una funzione chiamando registerLogMessageReceiver . con l'appropriato user_data . Nella sezione di registrazione del tuo codice base, devi assicurarti di chiamare quella funzione con il messaggio appropriato e il user_data registrato.

Se non ti devi preoccupare di C, puoi usare una classe come destinatario dei messaggi.

struct LogMessageReceiver
{
   virtual ~LogMessageReceiver() {}
   virtual void receive(std::string const& message) = 0;
};

e aggiungere una funzione nella libreria per consentire a un'applicazione di registrare un ricevitore di messaggi di registro.

void registerLogMessageReceiver(LogMessageReceiver* receiver);

Un'applicazione può registrare un LogMessageReceiver chiamando la funzione sopra. Dovrai prendere alcune decisioni politiche riguardanti la proprietà del LogMessageReceiver registrato. Se la libreria assume la proprietà del destinatario, deve delete il puntatore. Se la libreria non assume la proprietà del destinatario, l'applicazione deve occuparsi di delete nel ricevitore.

Utilizzando una classe come ricevitore dei messaggi di registro, il user_data bit deve essere omesso in registerLogMessageReceiver poiché il sottotipo di LogMessageReceiver è libero di contenere tutti i dati utili per il suo funzionamento. Non è necessario passare alcun dato utente aggiuntivo nella funzione receive .

Da lì, può diventare più complesso a seconda di quanto sia sofisticato il meccanismo di registrazione.

Ad esempio, potresti avere vari livelli di registrazione: Conciso, Normale, Dettagliato o LoggingLevel1, LoggingLevel2, ..., LoggingLevelN.

In tal caso, dovrai consentire all'applicazione di controllare il livello di registrazione che desiderano utilizzare.

Ci sono una serie infinita di scelte quando si decide di andare oltre il meccanismo di registrazione semplicistico. Non ha senso approfondire qui.

    
risposta data 08.06.2017 - 00:20
fonte

Leggi altre domande sui tag