12 Ekim 2017 Perşembe

log Macro'ları

Giriş
Macro kullanmaktan hiç hoşlanmıyorum ve maalesef log kütüphanesi bolca kullanıyor.

BOOST_LOG_ATTRIBUTE_KEYWORD
Yeni bir attribute eklemekden önce add_common_attributes() çağrılır. Bu çağrı ile
LineID,TimeStamp,ProcessID,ThreadID otomatik tanımlanır. Eğer add_common_attributes() çağrısı yapmak istemezsek bu keywordleri kodda tanımlamak için şöyle yaparız.
BOOST_LOG_ATTRIBUTE_KEYWORD(thread_id, "ThreadID",
  logging::attributes::current_thread_id::value_type)
BOOST_LOG_ATTRIBUTE_KEYWORD(process_id, "ProcessID",
  logging::attributes::current_process_id::value_type)
İlk parametre expression içinde kullanılacak değişkendir. İkinci parametre log çıktısındaki string, üçüncü parametre ise log çıktısındaki değeri üreten metoddur.

Örnek
Enum için şöyle yaparız.
enum class LogSeverity {
  trace, debug, info, warning, error, fatal
};
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", LogSeverity)
enum'u stringe çevirmek için şöyle yaparız.
std::ostream& operator<< (std::ostream& strm, LogSeverity level)
{
  static const std::array<std::string, 6> strings
  {
    std::string{"trace"},
    std::string{"debug"},
    std::string{"info"},
    std::string{"warn"},
    std::string{"error"},
    std::string{"fatal"}
  };

  strm << strings[static_cast< std::size_t >(level)];

  return strm;
}
Örnek
Şöyle yaparız.
BOOST_LOG_ATTRIBUTE_KEYWORD(timestamp, "TimeStamp", boost::posix_time::ptime)
BOOST_LOG_ATTRIBUTE_KEYWORD(log_thread_id, "ThreadID",
  attributes::current_thread_id::value_type)
Şöyle yaparız.
auto loggerSink = ...;

add_common_attributes();

loggerSink->locked_backend()->add_stream(stream);
loggerSink->locked_backend()->auto_flush(true);

loggerSink->set_filter(severity >= g_logLevel);

loggerSink->set_formatter( expressions::stream
  << "[" << expressions::format_date_time(timestamp, "%H:%M:%S.%f") << "] ["
  << std::setw(5) << std::left << severity << "] ["
  << log_thread_id << "] "
  << expressions::smessage
);
Örnek
Şöyle yaparız.
BOOST_LOG_ATTRIBUTE_KEYWORD(a_severity, "Severity", LogSeverity)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_channel, "Channel", std::string)

typedef sources::severity_channel_logger< LogSeverity, std::string > logger_type;

logger_type lg_a(keywords::channel = "A");
logger_type lg_b(keywords::channel = "B");

core::get()->set_filter
(
  (a_channel == "A" && a_severity >= LogSeverity::info) ||
  (a_channel == "B" && a_severity >= LogSeverity::warning)
);
veya şöyle yaparız.
auto min_severity = expressions::channel_severity_filter(a_channel, a_severity);
min_severity["A"] = LogSeverity::info;
min_severity["B"] = LogSeverity::warning;

core::get()->set_filter(min_severity);
Örnek
Şöyle yaparız. Tanımlanan yeni attribute logger'a da tanıtılıyor.
BOOST_LOG_ATTRIBUTE_KEYWORD(a_severity, "Severity", Log::Severity);
BOOST_LOG_ATTRIBUTE_KEYWORD(a_component, "Component", std::string);

class Foo
{
public:
  Foo(const std::string& component)
  {
    m_Logger.add_attribute(a_component.get_name(),
      boost::log::attributes::constant<tag::a_component::value_type>(component));
  }

  void bar()
  {
    BOOST_LOG_SEV(m_Logger, Log::INFO) << "Test";

  }

private:
  boost::log::sources::severity_logger_mt<Log::Severity> m_Logger;
};

BOOST_LOG_NAMED_SCOPE
Şöyle yaparız.
BOOST_LOG_NAMED_SCOPE("SomeModuleName")
BOOST_LOG_FUNCTION
Şöyle yaparız.
BOOST_LOG_FUNCTION()
BOOST_LOG_GLOBAL_LOGGER
Kendi global source nesnemizi tanımlamamızı sağlar. Açıklaması şöyle
it would be more convenient to have one or several global loggers in order to easily access them in every place when needed. In this regard std::cout is a good example of such a logger.
The library provides a way to declare global loggers that can be accessed pretty much like std::cout. In fact, this feature can be used with any logger, including user-defined ones. Having declared a global logger, one can be sure to have a thread-safe access to this logger instance from any place of the application code. The library also guarantees that a global logger instance will be unique even across module boundaries. This allows employing logging even in header-only components that may get compiled into different modules.
Örnek
Logging.h dosyasında şöyle yaparız.
typedef boost::log::sources::severity_logger_mt
  <boost::log::trivial::severity_level> logger_t;

//declares a global logger with a custom initialization
BOOST_LOG_GLOBAL_LOGGER(my_logger, logger_t)
Kendi logger'ımızın ismi my_logger. Bu nesneye tekrar erişmek mümkün. Açıklaması şöyle
Regardless of the macro you used to declare the logger, you can acquire the logger instance with the static get function of the logger tag
Şöyle yaparız.
src::severity_logger_mt< >& lg = my_logger::get();
Logging.h dosyasında kendi macrolarımızı tanımlarız. Şöyle yaparız.
#define INFO  BOOST_LOG_SEV(my_logger::get(), boost::log::trivial::info)
#define WARN  BOOST_LOG_SEV(my_logger::get(), boost::log::trivial::warning)
#define ERROR BOOST_LOG_SEV(my_logger::get(), boost::log::trivial::error)
Örnek
Şöyle yaparız.
// register a global logger
BOOST_LOG_GLOBAL_LOGGER(my_logger,
 boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level>)
BOOST_LOG_GLOBAL_LOGGER_INIT
BOOST_LOG_GLOBAL_LOGGER macrosunu header dosyasında. Bu macro cpp dosyasında. Eğer bu macroyu tanımlamazsak şuna benzer bir hata alırız.
error: undefined reference to `my_logger::construct_logger()'
Örneklerde neden macronun bir ve ikinci parametrelerinin kullanılmadığını anlamadım. Tüm örneklerde yeni bir logger yaratılıyor ve döndürülüyor.
Örnek
Logging.cpp dosyasında şöyle yaparız.
#include "Logging.h"

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

//Defines a global logger initialization routine
BOOST_LOG_GLOBAL_LOGGER_INIT(my_logger, logger_t)
{
  logger_t lg;

  logging::add_common_attributes();

  logging::add_file_log(
            boost::log::keywords::file_name = ...,
            boost::log::keywords::format = ...
    );

    logging::add_console_log(
            std::cout,
            boost::log::keywords::format = ...
    );

    logging::core::get()->set_filter
    (
        logging::trivial::severity >= logging::trivial::info
    );

    return lg;
}
Kendi logger'ımızı main.cpp dosyasında kullanmak için şöyle yaparız.
#include "Logging.h"

int main(int argc, char **argv)
{
  INFO << "Program started";

  return 0;
}
Örnek
Şöyle yaparız.
BOOST_LOG_GLOBAL_LOGGER_INIT(logger, src::severity_logger_mt) {
  src::severity_logger_mt<boost::log::trivial::severity_level> logger;

  // add attributes
  logger.add_attribute("LineID", attrs::counter<unsigned int>(1)); 
  logger.add_attribute("TimeStamp", attrs::local_clock());         

  return logger;
}
BOOST_LOG
Belirtilen logger'a yazmak için şöyle yaparız.
BOOST_LOG(lg) << ...;
BOOST_LOG_TRIVIAL
Boost trafından tanımlı olan global logger'a yazmak için şu satırı dahil ederiz. Global logger severity_logger_mt tipindendir.
#include <boost/log/trivial.hpp>
Şöyle yaparız.
BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
BOOST_LOG_TRIVIAL(debug) << "A debug severity message";
BOOST_LOG_TRIVIAL(info) << "An informational severity message";
BOOST_LOG_TRIVIAL(warning) << "A warning severity message";
BOOST_LOG_TRIVIAL(error) << "An error severity message";
BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message";
Bu macro ile logging::trivial::severity isimli bir attribute değer alır. Bu attribute değerini bir seviye ile karşılaştırmak istersek şöyle yaparız.
auto filt = logging::filter(logging::trivial::severity >= logging::trivial::info);
logging::core::get()->set_filter(filt);
Eğe kendi değişkenimiz ile karşılaştırmak istersek şöyle yaparız.
// track your own variable here
logging::trivial::severity_level my_log_level = logging::trivial::trace;

// with this filter
auto filt = logging::filter(logging::trivial::severity >= my_log_level);
logging::core::get()->set_filter(filt);
BOOST_LOG_SEV
Belirtilen logger'a severity + mesaj ile loglamak için şöyle yaparız.
enum SeverityLevel { trace, fatal };

boost::log::sources::severity_logger<SeverityLevel> lg;
BOOST_LOG_SEV(lg, trace) << "This is a trace message";
BOOST_LOG_SEV(lg, fatal) << "This is a fatal message";
Bu macro altta şunu kullanır.
BOOST_LOG_SEV(lg, Log::INFO) << "Test";

// Or, equivalently:
 BOOST_LOG_STREAM_WITH_PARAMS(lg, (boost::log::keywords::severity = Log::INFO)) << "Test";
Açıklaması şöyle
The parameters you pass to BOOST_LOG_STREAM_WITH_PARAMS are not attributes. These are named parameters that are received and used by logger features. Each such parameter has a meaning specific to a given feature that expects it. For example, the severity logger feature accepts the severity parameter, which it interprets as the severity level of the logging record. The BOOST_LOG_SEV macro handles the named parameter internally, so you don't have to use BOOST_LOG_STREAM_WITH_PARAMS for that.




Hiç yorum yok:

Yorum Gönder