2014-07-15 4 views
12

Sto utilizzando Boost (1.55.0) Registrazione nella mia applicazione C++. Sono stato in grado di generare log di questo formatoboost log per stampare il nome del file del codice sorgente e il numero di riga

[2014-Jul-15 10:47:26.137959]: <debug> A regular message 

voglio essere in grado di aggiungere il nome del file di origine e il numero di riga in cui viene generato il registro.

[2014-Jul-15 10:47:26.137959]: <debug> [filename:line_no] A regular message 

esempio:

[2014-Jul-15 10:47:26.137959]: <debug> [helloworld.cpp : 12] A regular message 

Source Code:

#include <boost/log/core.hpp> 
#include <boost/log/trivial.hpp> 
#include <boost/log/expressions.hpp> 
#include <boost/log/sinks/text_file_backend.hpp> 
#include <boost/log/utility/setup/file.hpp> 
#include <boost/log/utility/setup/common_attributes.hpp> 
#include <boost/log/sources/severity_logger.hpp> 
#include <boost/log/sources/record_ostream.hpp> 
#include <boost/log/expressions.hpp> 
#include <boost/log/support/date_time.hpp> 
#include <boost/log/attributes/attribute.hpp> 
#include <boost/log/attributes/attribute_cast.hpp> 
#include <boost/log/attributes/attribute_value.hpp> 
#include <boost/make_shared.hpp> 
#include <boost/property_tree/ptree.hpp> 

namespace logging = boost::log; 
namespace src = boost::log::sources; 
namespace sinks = boost::log::sinks; 
namespace keywords = boost::log::keywords; 

void init() 
{ 
    logging::add_file_log 
    (
     keywords::file_name = "sample_%N.log",          /*< file name pattern >*/ 
     keywords::rotation_size = 10*1024*1204,         /*< rotate files every 10 MiB... >*/ 
     keywords::time_based_rotation = sinks::file::rotation_at_time_point(0, 0, 0), /*< ...or at midnight >*/ 
     keywords::format = 
     (
      boost::log::expressions::stream 
       << boost::log::expressions::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d_%H:%M:%S.%f") 
       << ": <" << boost::log::trivial::severity << "> " 
       << boost::log::expressions::smessage 
     ) 
    ); 
} 

int main(int, char*[]) 
{ 
    init(); 
    logging::add_common_attributes(); 

    using namespace logging::trivial; 
    src::severity_logger<severity_level> lg; 

    BOOST_LOG_SEV(lg, debug) << "A regular message"; 
    return 0; 
} 
+0

Possibile duplicato di [Boost.Log: nome del file di supporto e il numero di linea] (http://stackoverflow.com/questions/31154429/boost-log-support-file-name-and-line-number) – Paladin

risposta

1

Definire

namespace attrs = boost::logging::attributes; 
namespace expr = boost::logging::expressions; 

Aggiungere

<< expr::format_named_scope("Scope", keywords::format = "[%f:%l]") 

al keywords::format = (...) in init.

Quindi aggiungere

logging::core::get()->add_global_attribute("Scope", attrs::named_scope()); 

dopo add_common_attributes() in main.

Quindi poco prima che la riga BOOST_LOG_SEV aggiunga BOOST_LOG_NAMED_SCOPE("whatever").

BOOST_LOG_NAMED_SCOPE("whatever") crea un "ambito" denominato "qualunque". L'ambito è implementato da una variabile non utilizzata che contiene il nome dell'ambito e il file e la linea in cui è stato definito l'ambito.

La riga format_named_scope specifica come deve essere formattato un ambito nella riga di registro. % f è il file,% l è la riga e% n è il nome dell'ambito.

Si noti che la linea di file che appare nel record di log è la linea in cui la macro BOOST_LOG_NAMED_SCOPE appare e non la linea del BOOST_LOG_SEV macro.

Non sono a conoscenza del metodo semplice per registrare il file e la linea senza utilizzare BOOST_LOG_NAMED_SCOPE.

+0

Proverò questi. grazie. –

4

Come sottolineato dall'utente2943014, l'utilizzo degli ambiti stampa il numero di riga in cui è stato aperto quell'ambito, non il numero di riga in cui è stato emesso un messaggio di registro utilizzando BOOST_LOG_SEV.

È possibile utilizzare gli attributi per registrare i numeri di riga ecc. Nella posizione in cui si è effettivamente effettuato il login.

Registrati attributi globali nella tua registrazione funzione di inizializzazione:

using namespace boost::log; 
core::get()->add_global_attribute("Line", attributes::mutable_constant<int>(5)); 
core::get()->add_global_attribute("File", attributes::mutable_constant<std::string>("")); 
core::get()->add_global_attribute("Function", attributes::mutable_constant<std::string>("")); 

impostazione di questi attributi nella macro di registrazione:

#define logInfo(methodname, message)       \ 
    LOG_LOCATION;            \ 
    BOOST_LOG_SEV(_log, boost::log::trivial::severity_level::trace) << message 

#define LOG_LOCATION       \ 
    boost::log::attribute_cast<boost::log::attributes::mutable_constant<int>>(boost::log::core::get()->get_global_attributes()["Line"]).set(__LINE__); \ 
    boost::log::attribute_cast<boost::log::attributes::mutable_constant<std::string>>(boost::log::core::get()->get_global_attributes()["File"]).set(__FILE__); \ 
    boost::log::attribute_cast<boost::log::attributes::mutable_constant<std::string>>(boost::log::core::get()->get_global_attributes()["Function"]).set(__func__); 

Non esattamente bello, ma funziona ed è stato un lungo cammino per me . È un vero peccato che non offra questa funzionalità fuori dagli schemi.

+0

Mi sembra carino. Proverò questa volta –

11

Come indicato da Horus, è possibile utilizzare gli attributi per registrare i numeri di file e di riga. Tuttavia è meglio evitare di usare Multi-istruzioni macro per evitare problemi con espressioni come questa:

if (something) 
    LOG_FILE_LINE(debug) << "It's true"; // Only the first statement is conditional! 

si può fare meglio la creazione di una macro che sfrutta il comportamento di fondo della libreria Boost Log. Ad esempio, BOOST_LOG_SEV è:

#define BOOST_LOG_SEV(logger, lvl) BOOST_LOG_STREAM_SEV(logger, lvl) 
#define BOOST_LOG_STREAM_SEV(logger, lvl)\ 
    BOOST_LOG_STREAM_WITH_PARAMS((logger), (::boost::log::keywords::severity = (lvl))) 

Utilizzando BOOST_LOG_STREAM_WITH_PARAMS è possibile impostare e ottenere più attributi, come questo:

Il codice sorgente completo è:

#include <boost/log/trivial.hpp> 
#include <boost/log/sources/severity_logger.hpp> 
#include <boost/log/utility/setup/file.hpp> 
#include <boost/log/utility/setup/console.hpp> 
#include <boost/log/expressions.hpp> 
#include <boost/log/utility/setup/common_attributes.hpp> 
#include <boost/log/attributes/mutable_constant.hpp> 
#include <boost/date_time/posix_time/posix_time_types.hpp> 
#include <boost/log/support/date_time.hpp> 
#include <boost/log/attributes/mutable_constant.hpp> 

namespace logging = boost::log; 
namespace attrs = boost::log::attributes; 
namespace expr  = boost::log::expressions; 
namespace src  = boost::log::sources; 
namespace keywords = boost::log::keywords; 

// New macro that includes severity, filename and line number 
#define CUSTOM_LOG(logger, sev) \ 
    BOOST_LOG_STREAM_WITH_PARAMS(\ 
     (logger), \ 
     (set_get_attrib("File", path_to_filename(__FILE__))) \ 
     (set_get_attrib("Line", __LINE__)) \ 
     (::boost::log::keywords::severity = (boost::log::trivial::sev)) \ 
    ) 

// Set attribute and return the new value 
template<typename ValueType> 
ValueType set_get_attrib(const char* name, ValueType value) { 
    auto attr = logging::attribute_cast<attrs::mutable_constant<ValueType>>(logging::core::get()->get_thread_attributes()[name]); 
    attr.set(value); 
    return attr.get(); 
} 

// Convert file path to only the filename 
std::string path_to_filename(std::string path) { 
    return path.substr(path.find_last_of("/\\")+1); 
} 

void init() { 
    // New attributes that hold filename and line number 
    logging::core::get()->add_thread_attribute("File", attrs::mutable_constant<std::string>("")); 
    logging::core::get()->add_thread_attribute("Line", attrs::mutable_constant<int>(0)); 

    logging::add_file_log (
    keywords::file_name = "sample.log", 
    keywords::format = (
    expr::stream 
     << expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d_%H:%M:%S.%f") 
     << ": <" << boost::log::trivial::severity << "> " 
     << '[' << expr::attr<std::string>("File") 
       << ':' << expr::attr<int>("Line") << "] " 
     << expr::smessage 
    ) 
    ); 
    logging::add_common_attributes(); 
} 

int main(int argc, char* argv[]) { 
    init(); 
    src::severity_logger<logging::trivial::severity_level> lg; 

    CUSTOM_LOG(lg, debug) << "A regular message"; 
    return 0; 
} 

Questo genera un registro come questo:

2015-10-15_15:25:12.743153: <debug> [main.cpp:61] A regular message 
+1

+1. Osservando come è implementato, dovrebbe funzionare più velocemente se si definisce il tipo di attributo come "mutable_constant " e lo si assegna con 'boost :: log :: string_literal (__ FILE __)' ecc. interrompere l'allocazione/copia delle stringhe su ciascuna riga del registro. – bobah

+0

Buon punto. Tuttavia, '__LINE__' è una costante intera e' __FILE__' è usato per ottenere una sottostringa in questo esempio. costrutti 'boost :: log :: string_literal' da una costante di array come' char value [N] '. –

+0

@ Nature.Li ha indicato che il codice non è thread-safe. Ho modificato gli attributi globali per gli attributi di thread nel codice, ma non l'ho testato con diversi thread. –