2016-07-28 12 views
0

Ich versuche, einen benutzerdefinierten Formatierer mit Boost.Log zu verwenden. Die Art, wie ich weiß, wie dies zu tun ist, um die set_formatter Methode einer Senke nennen ihm die Adresse einer lokalen Funktion geben, wo die Signatur der lokalen Funktion sein muss:Wie Boost.Log Formatierungsausdrücke in benutzerdefinierten Formatierungsfunktion verwenden

void my_formatter(boost::log::record_view const& rec, boost::log::formatting_ostream& strm) 

In my_formatter ich die Boost-verwenden kann .Log Extraktion API, um die Attributwerte, die ich brauche. Sobald ich die Werte bekomme, kann ich sie an die strm ausgeben. Ich möchte dies tun, damit ich einige benutzerdefinierte Attribute, die im Datensatz gespeichert sind, leicht formatieren kann. Aber für andere, konventionellere Boost.Log-Attribute möchte ich weiterhin die einfachen Formatierungsausdrücke verwenden, die als Schlüsselwortargumente für die set_formatter-Methode dokumentiert sind. Gibt es eine Möglichkeit, die Schlüsselwortausdrücke auch in der benutzerdefinierten Funktion my_formatter zu verwenden?

Zum Beispiel:

void my_formatter(boost::log::record_view const& rec, boost::log::formatting_ostream& strm) 
{ 
    // here I can get the timestamp attribute and format its ticks value to the stream 
    boost::log::value_ref<boost::posix_time::ptime> tstamp_ref = 
     boost::log::extract<boost::posix_time::ptime>("TimeStamp", rec); 
    const boost::posix_time::ptime& timestamp = tstamp_ref.get(); 

    strm << timestamp.time_of_day().ticks(); 
} 

Dann ein Waschbecken gegeben, kann ich anrufen

sink->set_formatter(&my_formatter) 

Aber Boost.Log gibt mir einen eleganten (fast magischen) Ausdruck, die ich verwenden kann die Formatierer einzustellen :

boost::log::formatter formatter = 
    expr::stream 
    << expr::format_date_time<boost::posix_time::ptime>(
     "TimeStamp", "%Y/%m/%d, %H:%M:%S.%f, "); 

sink->set_formatter(formatter) 

Meine Frage ist: gibt es eine Möglichkeit, den Formatierer Ausdruck in meiner Gewohnheit zu verwenden my_formatter Funktion?

Danke!

Antwort

1

Sie könnten Ihre benutzerdefinierten Teile des Formatierungsprogramms in den mit Boost.Log erstellten Formatierungsausdruck einfügen, anstatt umgekehrt. This Antwort beschreibt eine Möglichkeit, das zu erreichen, indem Sie phoenix::bind verwenden.

+0

Danke! Das ist eine lange Antwort, also muss ich es ein wenig studieren, aber das scheint auch ein guter Ansatz zu sein. Können Sie die Leistungseinbußen bei der Verwendung der Formatierungsausdrücke etwas genauer erläutern? Sie erwähnen in den Dokumenten, dass die Formatierungsausdrücke im Code schneller ausgeführt werden als solche, die aus einer Konfigurationsdatei erstellt wurden. Meine Beobachtung ist, dass mein Nicht-Ausdruck-Formatierer schneller ist als der Ausdruck-basierte. (Zugegeben, in meinem Ad-hoc-Benchmark ist die einzige Arbeit, die getan wird, Logging, also bin ich hyperkritisch in Bezug auf die Verlangsamung, aber manchmal ist Leistung wirklich wichtig.) – Phil

+0

Man müsste den Code und die generierte Assembly untersuchen der Grund der Leistungsregression. Die Formatierungsausdrücke (die sowieso 'expr :: stream 'enthalten) sind effizienter als die analysierten Formatierer, da der Compiler mehr Möglichkeiten zur Optimierung hat. Insbesondere kann es inline aggressiver arbeiten. Ein von Hand geschriebener Formatierer kann den Formatierungsausdruck möglicherweise übertreffen, da er spezieller sein kann. Es ist normalerweise eine flache Funktion, so dass es nicht darauf ankommt, so viel zu inlinern, während der Compiler die Template-Ausdrücke aus irgendeinem Grund nicht optimieren kann. –

+0

Wenn Ihr Formatierer Datum/Uhrzeit einbezieht, sollten Sie sicherstellen, dass Sie 'expr :: format_date_time' und nicht den' Operator << 'von Boost.DateTime verwenden, da letzteres bekanntermaßen langsamer ist. –

0

Nach einigen Arbeiten fand ich einige Boost.Log Testcode, form_date_time.cpp, der zeigt, wie dies zu tun ist. Im Folgenden wird erläutert, wie Sie den Ausdruck Formatierer programmatisch in einer benutzerdefinierten Formatfunktion verwenden.

void my_formatter(boost::log::record_view const& rec, 
        boost::log::formatting_ostream& strm) 
{ 
    typedef boost::log::formatter formatter; 
    formatter f = expr::stream << expr::format_date_time<boost::posix_time::ptime>(
         "TimeStamp", "%Y/%m/%d, %H:%M:%S.%f, "); 
    f(rec, strm); 
} 

Während ich die Antwort gegeben habe, sollte man vorsichtig sein, es zu benutzen. In meinen Benchmark-Tests wird eine ordnungsgemäß implementierte benutzerdefinierte Formatiererfunktion den Ausdrucksformatierer übertreffen. Bei komplexen Ausdrücken, für die Sie keinen Code schreiben möchten (z. B. der spezialisierte Code Named scope formatter), können Sie mit diesem Ansatz jedoch einen Ausdrucksformatierer in einer benutzerdefinierten Formatiererfunktion nutzen.