2014-02-28 21 views
6

Kann ich das LineID-Attribut dafür verwenden? Ich hoffe, ich Spüle verwenden könnte :: set_formatter diese vonWie wird die Zeilennummer des Coders in Boost Log 2.0 protokolliert?

in jedem Log-Anweisung
__LINE__ 

und

__FILE__ 

anstelle zu tun.

+1

Das sollte so offensichtlich sein, aber es ist nicht so. Ich habe mir schon eine ganze Weile den Kopf darüber geschlagen. Hast du Glück gehabt, seit du deine Frage gestellt hast? Wenn du es herausgefunden hast, beantworte deine eigene Frage und hilf einem Kerl! – ixe013

Antwort

7

ich damit zu kämpfen, bis ich this snippet

#define LFC1_LOG_TRACE(logger) \ 
BOOST_LOG_SEV(logger, trivial::trace) << "(" << __FILE__ << ", " << __LINE__ << ") " 

Arbeiten wie ein Charme

+0

Ich versuchte Namensumfang, es funktioniert aber komplexer. Siehe meinen Code in meinem Post. http://blog.csdn.net/csfreebird/article/details/20213349#t9 Ich habe den gleichen Gedanken wie Sie, nur meine eigenen Makros definieren und verwenden __FILE__, __LINE__ –

+0

Ja, nach dem Posten ging ich diese Route auch. Hat sich etwas ergeben, das etwas anders ist als du, da ich das named_scope als Teil meines Formatierungsprogramms verwende. Es kann dann verschachtelte Bereichsaufrufe erzeugen. – Chris

5

Das LineID Attribut gefunden ist eine laufende Nummer, die für jede Protokollmeldung erhöht wird. Sie können das also nicht benutzen.

Sie können Attribute verwenden, um die Zeilennummern usw. zu protokollieren. Dies ermöglicht Ihnen eine flexible Formatierung mit dem Formatzeichenfolge, während die Verwendung von Chris 'Antwort Ihr Format ist behoben.

Register globale Attribute in Ihrer Protokollierung Initialisierungsfunktion:

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>("")); 

Festlegen dieser Attribute in Ihrem Logging-Makro:

#define logInfo(methodname, message) do {       \ 
    LOG_LOCATION;              \ 
    BOOST_LOG_SEV(_log, boost::log::trivial::severity_level::info) << message; \ 
    } while (false) 

#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__); 

Nicht gerade schön, aber es funktioniert und es war ein langer Weg für mich . Es ist schade, dass Boost dieses Feature nicht standardmäßig anbietet.

Das do {...} while (false) soll das Makro semantisch neutral machen.

1

Eine weitere Möglichkeit besteht darin, jedem Protokolldatensatz nach der Erstellung Zeilen- und Dateiattribute hinzuzufügen. Dies ist in neueren Versionen möglich. Später hinzugefügte Attribute nehmen nicht an der Filterung teil.

Unter der Annahme, severity_logger mit variabler Logger identifiziert:

boost::log::record rec = logger.open_record(boost::log::keywords::severity = <some severity value>); 
if (rec) 
{ 
    rec.attribute_values().insert(boost::log::attribute_name("Line"), 
     boost::log::attributes::constant<unsigned int>(__LINE__).get_value()); 
    ... other stuff appended to record ... 
} 

Die oben wäre natürlich, erhalten in bequeme Makro gewickelt.

Später können Sie dieses Attribut mit benutzerdefinierten Formatierer für die Spüle zeigen:

sink->set_formatter(...other stuff... << expr::attr<unsigned int>("Line") << ...other stuff...); 

Im Gegensatz zu früheren Antwort, dieser Ansatz benutzerdefinierten Code erfordert und nicht off-the-shelf-Boost Logging-Makros verwenden.

0

Für die Nachwelt - ich habe diese Menge von Makros für sehr einfache Protokollierung Bedürfnisse, die mir gut gedient hat - für einfache Protokollierung benötigt. Aber sie illustrieren, wie man das im Allgemeinen macht, und das Konzept funktioniert leicht mit Boost. Sie sind für eine Datei lokal (die in mehreren Prozessen ausgeführt wird, manchmal in mehreren Threads in mehreren Prozessen). Sie sind für relative Einfachheit gemacht, nicht für Geschwindigkeit. Sie sind sicher, um Aussagen zu machen, um den anderen nicht zu stehlen.Zu Beginn einer Funktion, bei der ein anmelden will, nennt man

GLogFunc("function name"); 

Dann kann man dies tun, eine komplette Linie zu protokollieren:

GLogL("this is a log entry with a string: " << some_string); 

Sie sind als so -

#define GLogFunc(x)  std::stringstream logstr; \ 
         std::string logfunc; \ 
         logfunc = x 

#define GLog(x)   do { logstr << x; } while(0) 

#define GLogComplete do { \ 
          _log << "[PID:" << _my_process << " L:" << __LINE__ << "] ((" << logfunc << ")) " << logstr.str() << endl; \ 
          logstr.str(""); \ 
          _log.flush(); \ 
         } while(0) 

#define GLogLine(x)  do { GLog(x); GLogComplete; } while(0) 
#define GLogL(x)  GLogLine(x) 
#define GLC    GLogComplete 

Man kann auch ein Protokoll über ein paar Zeilen aufbauen ...

GLog("I did this."); 
// later 
GLog("One result was " << some_number << " and then " << something_else); 
// finally 
GLog("And now I'm done!"); 
GLogComplete; 

Was auch immer Strom _log ist (ich es als eine Datei im Konstruktor der Klasse zu öffnen, die in diesem Fall als sicher gewährleistet ist) bekommt ouput wie folgt aus:

[PID:4848 L:348] ((SetTextBC)) ERROR: bad argument row:0 col:-64 

Und sie können bedingt ausgeschaltet und alle Leistung sein durch ein Symbol bei der Kompilierung Strafe negiert wie so:

#ifdef LOGGING_ENABLED 
... do the stuff above ... 
#else 

#define GLogFunc(x) 
#define GLog(x) 
#define GLogComplete 
#define GLogLine(x) 
#define GLogL(x) 

#endif 
3

die Lösung von Chris Arbeiten gezeigt, aber wenn Sie das Format anpassen oder festlegen, welche Informationen in jedem Waschbecken angezeigt wird, Sie änderbare konstante Attribute verwenden müssen:

logging::core::get()->add_global_attribute("File", attrs::mutable_constant<std::string>("")); 
    logging::core::get()->add_global_attribute("Line", attrs::mutable_constant<int>(0)); 

Dann machen Sie eine benutzerdefinierte Makros, die diese neuen Attribute enthält:

// 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_global_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); 
} 

Die nächste vollständige Quellcode zwei Waschbecken erstellen. Der erste verwendet Datei- und Linienattribute, der zweite nicht.

#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_global_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_global_attribute("File", attrs::mutable_constant<std::string>("")); 
    logging::core::get()->add_global_attribute("Line", attrs::mutable_constant<int>(0)); 

    // A file log with time, severity, filename, line and message 
    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 
    ) 
    ); 
    // A console log with only time and message 
    logging::add_console_log (
    std::clog, 
    keywords::format = (
    expr::stream 
     << expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d %H:%M:%S") 
     << " | " << 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; 
} 

Die Aussage CUSTOM_LOG(lg, debug) << "A regular message"; zwei Ausgänge erzeugt, mit diesem Format eine Protokolldatei zu schreiben ...

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

... und gibt an die Konsole dies:

2015-10-15 16:58:35 | A regular message 
+0

Es gab ein Programm Beendigungsproblem mit dem obigen Code in dem Programm, das Multi-Threads verwendet. Das Programm endete und der Unterbrechungspunkt befand sich in der Mitte der Boost-Protokollfunktionen in Visual Studio. Nachdem ich die obige Methode nicht mehr verwendete, war das Problem verschwunden. Vorsicht ist in Multi-Threads-Umgebung erforderlich. – Hill

0

Hier meine Lösung.

Setup-Code

auto formatter = 
    expr::format("[ %3% %1%:%2% :: %4%]") 
    % expr::attr<std::string>("File") 
    % expr::attr<uint32_t>("Line") 
    % expr::attr<boost::posix_time::ptime>("TimeStamp") 
    % expr::smessage 
    ; 

/* stdout sink*/ 
boost::shared_ptr<sinks::text_ostream_backend> backend = 
    boost::make_shared<sinks::text_ostream_backend>(); 
backend->add_stream(
    boost::shared_ptr<std::ostream>(&std::clog, NullDeleter())); 

// Enable auto-flushing after each log record written 
backend->auto_flush(true); 

// Wrap it into the frontend and register in the core. 
// The backend requires synchronization in the frontend. 
typedef sinks::synchronous_sink<sinks::text_ostream_backend> sink2_t; 
boost::shared_ptr<sink2_t> sink_text(new sink2_t(backend)); 

logging::add_common_attributes(); 

sink_text->set_formatter(formatter); 

Das Protokoll Verwendungscode (Kurzfassung):

rec.attribute_values().insert("File", attrs::make_attribute_value(std::string(__FILE__))); \ 

Vollversion:

#define LOG(s, message) { \ 
    src::severity_logger<severity_level> slg; \ 
    logging::record rec = slg.open_record(keywords::severity = s); \ 
    if (rec) \ 
    { \ 
    rec.attribute_values().insert("File", attrs::make_attribute_value(boost::filesystem::path(__FILE__).filename().string())); \ 
    rec.attribute_values().insert("Line", attrs::make_attribute_value(uint32_t(__LINE__))); \ 
    logging::record_ostream strm(rec); \ 
    strm << message; \ 
    strm.flush(); \ 
    slg.push_record(boost::move(rec)); \ 
    } \ 

} \

Wenn ich globales Attribut definieren (wie Leute beraten haben vor), das heißt

logging::core::get()->add_global_attribute("File", attrs::mutable_constant<std::string>("")); 

dann bekomme ich leer files/stiring.