4

ブースト ログ 2.0 を多用するアプリケーションがあります。std::setprecision(std::numeric_limits<double>::digits10 + 1)ここで、そのアプリケーションに、 、などのデフォルト フラグを設定したいと思いstd::scientificますstd::left。しかし、どうすればそれを行うことができますか?1 つのアプローチは、メイン関数の最初にロガーを作成し、ダミーのログ メッセージを作成することです。これにより、必要なフラグが永続的に設定されます。しかし、これを行うより良い方法はありませんか?

「OPは実際のコードを表示する必要があります」に返信して編集します。

L と呼ばれるグローバル ロギング シングルトンがあります。

class L{
public:
  enum severity_level
  {
      dddebug,
      ddebug,
      debug,
      control,
      iiinfo,
      iinfo,
      info,
      result,
      warning,
      error,
      critical
  };

  typedef boost::log::sources::severity_channel_logger<
      severity_level, // the type of the severity level
      std::string // the type of the channel name
  > logger_t;
  typedef boost::log::sinks::synchronous_sink< boost::log::sinks::text_ostream_backend > text_sink;
  boost::shared_ptr< text_sink > sink_;

  static L& get();
  static boost::shared_ptr<text_sink> sink();
  static double t0();
  static double tElapsed();
private:
  L();
  double t0_p;
  static std::string tElapsedFormat();

  L(const L&) = delete;
  void operator=(const L&) = delete;
};

ログ シンク、重大度レベルを提供し、MPI ノード間で同期されたタイムキーピングのために MPI メソッドを利用します。クラスメンバーの実装は次のとおりです。

#include "log.h"

#include <iomanip>
#include <limits>
#include <fstream>
#include <boost/log/attributes/function.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/smart_ptr/make_shared_object.hpp>
#include <boost/log/core.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sources/severity_channel_logger.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>


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

#include "mpiwrap.h"
#include <mpi.h>

BOOST_LOG_ATTRIBUTE_KEYWORD(t, "Time", std::string)
BOOST_LOG_ATTRIBUTE_KEYWORD(rank, "Rank", int)
BOOST_LOG_ATTRIBUTE_KEYWORD(channel, "Channel", std::string)
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", L::severity_level)

L::L():
  sink_(boost::make_shared< text_sink >()),
  t0_p(MPI_Wtime())
{

  sink_->locked_backend()->add_stream(
    boost::make_shared< std::ofstream >("log." + std::to_string(MpiWrap::getRank())));

  sink_->set_formatter
  (
    expr::stream
      << "< "
      << t << " "
      << "[p:" << rank << "] "
      << "[c:" << channel << "] "
      << "[s:" << severity << "] "
      << expr::smessage
  );

  logging::core::get()->add_sink(sink_);

  logging::core::get()->set_filter(

       (channel == "ChannelName1" && severity >= dddebug)
    || (channel == "ChannelName2" && severity >= info)
    || (channel == "ChannelName3" && severity >= result)

  );

  // Add attributes
  logging::core::get()->add_global_attribute("Time", attrs::make_function(&tElapsedFormat));
  logging::core::get()->add_global_attribute("Rank", attrs::constant<int>(MpiWrap::getRank()));
}

L& L::get(){
  static L instance;
  return instance;
}

boost::shared_ptr<L::text_sink> L::sink(){
  return get().sink_;
}

double L::t0(){
  return get().t0_p;
}

double L::tElapsed(){
  return MPI_Wtime() - t0();
}

std::string L::tElapsedFormat(){
  std::stringstream ss;
  const int prec = std::numeric_limits<double>::digits10;
  ss << std::setw(prec + 2 + 6) << std::left << std::setprecision(prec) << tElapsed();
  return ss.str();
}

std::ostream& operator<< (std::ostream& strm, L::severity_level level)
{
    static const char* strings[] =
    {
        "DBG3",
        "DBG2",
        "DBG1",
        "CTRL",
        "INF3",
        "INF2",
        "INF1",
        "RSLT",
        "WARN",
        "ERRR",
        "CRIT"
    };

    if (static_cast< std::size_t >(level) < sizeof(strings) / sizeof(*strings))
        strm << strings[level];
    else
        strm << static_cast< int >(level);

    return strm;
}

使用法について:私のクラスには通常、静的logger_t( typedef for boost::log::sources::severity_channel_logger<severity_level, std::string>)メンバーがあります

class A {
public:
    logger_t logger;
    //other stuff here
    void function_which_does_logging();
};

L::logger_t A::logger(boost::log::keywords::channel = "ClassA");

void A::function_which_does_logging(){
    //do non logging related stuff
    BOOST_LOG_SEV(logger, L::result) << "the error is: " << 0.1234567890;
    //do non logging related stuff
}

問題に対する私の現在の解決策は、ログステートメントをプログラムの先頭に置くことです

int main(){
    L::logger_t logger(boost::log::keywords::channel = "init");
    BOOST_LOG_SEV(logger, L::critical) << "setting up logger" << std::scientific << std::setprecision(std::numeric_limits<double>::digits10 + 1);

    //do stuff
}
4

2 に答える 2

5

@rhashimoto は、現在のソリューションが複数のスレッド/同時ロギング操作でどのように機能しないかについて良い点を指摘しています。BOOST_LOG_SEV次のように、ストリーム修飾子が含まれている独自のロギング マクロを定義して置き換えるのが最善の解決策だと思います。

#define LOG_SCIENTIFIC(logger, sev) (BOOST_LOG_SEV(logger, sev) << std::scientific)

BOOST_LOG_SEVこれは、数字を科学的にフォーマットするためのドロップイン代替として使用できます。ただし、コードを調べて、すべてのログ操作を新しいカスタム マクロに置き換えるのはおそらく面倒です。独自のマクロを定義する代わりに、希望どおりBOOST_LOG_SEVに動作するように再定義することもできます。boost/log/sources/severity_feature.hpp次のように定義BOOST_LOG_SEVします。

//! An equivalent to BOOST_LOG_STREAM_SEV(logger, lvl)
#define BOOST_LOG_SEV(logger, lvl) BOOST_LOG_STREAM_SEV(logger, lvl)

まだ公開ブースト API の一部であるためBOOST_LOG_STREAM_SEV、次のように安全に再定義できるはずですBOOST_LOG_SEV

#define BOOST_LOG_SEV(logger, lvl) (BOOST_LOG_STREAM_SEV(logger, lvl) << std::scientific)

ブーストログヘッダーを含めた後にこれが定義されている限り、それはあなたが望むことをするはずです. ただし、カスタム名のマクロを使用することをお勧めします。これにより、コードが何を行っているかが他の人に明確になります。

于 2014-04-28T01:57:18.870 に答える