Boost Logging displays linux thread ids as all 0s
I'm trying to send log lines to a file in the latest boost 1.57 and for some reason on linux the thread IDs are always 0. I have a feeling it might be due to using native threads instead of boosting threads, but that doesn't explain why it works in Windows environment. Any help would be appreciated.
Here is my init code in the logger.cpp file.
EDIT : shown below. I have also included my Logger.h which shows the type of logger in use - effectively using the BOOST_LOG_CHANNEL_SEV macro to log into
nudge :: log sources :: severity_channel_logger_mt <boost :: log :: trivial :: severity_level>
#include <boost/log/core.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/attributes/scoped_attribute.hpp>
#include <boost/log/expressions/formatters/date_time.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/manipulators/add_value.hpp>
#include <boost/log/sources/severity_channel_logger.hpp>
. . .
namespace fs = boost::filesystem;
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;
namespace trivial = boost::log::trivial;
void
Logger::init(
const fs::path& rErrEvtPath,
const fs::path& rStatusPath)
{
// register common attributes - ThreadID, LineID, TimeStamp etc.
logging::add_common_attributes();
// Construct the sink for the "event_log" channel
typedef sinks::synchronous_sink<
sinks::text_ostream_backend> text_sink;
auto sink = boost::make_shared<text_sink>();
sink->locked_backend()->auto_flush(true);
sink->locked_backend()->add_stream(
boost::make_shared<std::ofstream>(rErrEvtPath.c_str()));
sink->set_formatter(
expr::format("%1% [%2%] tid[%3%] %4%")
% expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%H:%M:%S.%f")
% logging::trivial::severity
% expr::attr<attrs::current_thread_id::value_type>("ThreadID")
% expr::smessage);
sink->set_filter(expr::attr<std::string>("Channel") == "event");
logging::core::get()->add_sink(sink);
// Construct the sink for the "status_log" channel
sink = boost::make_shared<text_sink>();
sink->locked_backend()->auto_flush(true);
sink->locked_backend()->add_stream(
boost::make_shared<std::ofstream>(rStatusPath.c_str()));
sink->set_formatter(
expr::format("%1% [%2%] tid[%3%] %4%")
% expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%H:%M:%S.%f")
% logging::trivial::severity
% expr::attr<attrs::current_thread_id::value_type>("ThreadID")
% expr::smessage);
sink->set_filter(expr::attr<std::string>("Channel") == "status");
logging::core::get()->add_sink(sink);
}
The logs on windows display just fine.
15:42:35.205747 [info] tid[0x00000e14] module[NIC:192.168.1.1] SETCNTX IP_ADDR 192.168.1.1
15:42:35.207747 [info] tid[0x00000e14] module[NIC:192.168.1.1] SETCNTX RESP_ON
15:42:35.209747 [info] tid[0x00000e14] module[NIC:192.168.1.1] SETCNTX SET_FTP_TIMEOUT 10
15:42:35.212747 [info] tid[0x00000e14] module[NIC:192.168.1.1] FTPNOPROMPT [192.168.1.1] [timeout 10(s)]
15:42:35.552781 [info] tid[0x00000e14] module[NIC:192.168.1.1] SETCNTX RESP_OFF
15:42:35.553781 [info] tid[0x00000e14] module[NIC:192.168.1.1] FTPQUOTE "site attrib 0 DEOS"
however on linux (ppc) using the same boost 1.57.0 the logs look like this:
13:43:45.092206 [info] tid[0000000000] module[N/A] MLFCommand - command group(5) - end
13:43:45.092568 [info] tid[0000000000] module[N/A] SETCNTX IP_ADDR 192.168.1.23
13:43:45.097037 [info] tid[0000000000] module[N/A] SETCNTX RESP_ON
13:43:45.098691 [info] tid[0000000000] module[N/A] SETCNTX SET_FTP_TIMEOUT 10
13:43:45.100474 [info] tid[0000000000] module[N/A] FTPNOPROMPT [192.168.1.23] [timeout 10(s)]
13:43:49.191856 [warning] tid[0000000000] module[N/A] [>TIMEOUT<]
EDIT: for completeness - I am including logger.h
#ifndef _logger_h_
#define _logger_h_
// SYSTEM INCLUDES
#include <mutex>
#include <string>
#include <memory>
#include <boost/filesystem.hpp>
#if !defined(__GNUC__)
#pragma warning(push)
#pragma warning(disable: 4714 4100 4510 4503 4512 4610)
#endif
#include <boost/log/trivial.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/sources/severity_channel_logger.hpp>
#if !defined(__GNUC__)
#pragma warning(pop)
#endif
// APPLICATION INCLUDES
// DEFINES
#define LOG(logger, lvl) BOOST_LOG_CHANNEL_SEV(logger, "event", lvl)
#define LOG_TRACE(logger) BOOST_LOG_CHANNEL_SEV(logger, "event", trivial::trace)
#define LOG_DEBUG(logger) BOOST_LOG_CHANNEL_SEV(logger, "event", trivial::debug)
#define LOG_INFO(logger) BOOST_LOG_CHANNEL_SEV(logger, "event", trivial::info)
#define LOG_WARNING(logger) BOOST_LOG_CHANNEL_SEV(logger, "event", trivial::warning)
#define LOG_ERROR(logger) BOOST_LOG_CHANNEL_SEV(logger, "event", trivial::error)
#define LOG_FATAL(logger) BOOST_LOG_CHANNEL_SEV(logger, "event", trivial::fatal)
// MACROS
// EXTERNAL FUNCTIONS
extern bool gVerboseMode;
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS
class Logger
{
public:
using SEVChannelLoggerMT = boost::log::sources::severity_channel_logger_mt<
boost::log::trivial::severity_level>;
/**
* singleton pattern implementation
*
* @return singleton instance
*/
static Logger* getInstance();
// destructor
virtual ~Logger() = default;
/** define a log filter associated with a channel attribute */
enum class LogDest {
EventLog, StatusLog
};
/**
* log the message to a specified log<p>
*
* @param logDest [in] filter used to route the log message to
* the correct logging sink.
* @param rMessage [in] message to log
*/
void logMessage(
const LogDest logDest,
const boost::log::trivial::severity_level& severity,
const std::string& rMessage);
/**
* Returns logger associated with the specified log destination.<p>
*
* @param logDest [in] filter used to route the log message to
* the correct logging sink.
* @return logger of the appropriate type
*/
SEVChannelLoggerMT& getLoggerRef(const LogDest logDest);
/**
* Custom reusable formatter which we can attach to all sinks
* for a uniform formatting of log messages
*
* @param rec [in] record contain the log details
* @param strm [in,out] logging stream
*/
static void customFormatter(
boost::log::record_view const& rec,
boost::log::formatting_ostream& strm);
/**
* Initialize the logging framework.<p>
* Initializes the Boost logging framework by setting up the
* following log files<p>.
* Under the covers the Boost Logging framework initializes two
* distinct log files.
* <ul>
* <li>Error/Event log - this contains everything</li>
* <li>rStatusPath - high level log file which is also
* displayed on the iPad</li>
* </ul>
*
* @param rErrEvtPath
* [in] fully qualified path to
* DlfLogBuffer[num].txt log file. This log
* file will be created as necessary or
* reinitialized to empty (truncated) if it
* already exists.
* @param rStatusPath
* [in] fully qualified path to
* DlfStatusBuffer[num].txt log file. This log
* file will be created as necessary or
* reinitialized to empty (truncated) if it
* already exists.
*/
static void init(
const boost::filesystem::path& rErrEvtPath,
const boost::filesystem::path& rStatusPath);
private:
// severity channel loggers - one for the error event log
SEVChannelLoggerMT m_event_logger, m_status_logger;
/**
* Constructor - initialize each channel logger with a named
* channel attribute which will be used by filtering to route
* logging records to the appropriate sink.
*/
Logger();
// singleton and locking support
static std::mutex gMutexGuard;
static Logger* gpInstance;
};
#endif // _logger_h_
source to share
You can report it at the top (or debug it manually).
Update Issues were reported with the Boost Log developers and they fixed it (thanks @ johnco3)
Here's the same on Debian:
#define BOOST_LOG_DYN_LINK 1
#include <boost/filesystem.hpp>
#include <boost/log/attributes/scoped_attribute.hpp>
#include <boost/log/core.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/expressions/formatters/date_time.hpp>
#include <boost/log/sinks/sync_frontend.hpp>
#include <boost/log/sinks/text_ostream_backend.hpp>
#include <boost/log/sources/severity_channel_logger.hpp>
#include <boost/log/sources/channel_logger.hpp>
#include <boost/log/sources/global_logger_storage.hpp>
#include <boost/log/keywords/channel.hpp>
#include <boost/log/keywords/severity.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/manipulators/add_value.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <fstream>
#include <boost/log/sources/logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/sources/global_logger_storage.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
namespace fs = boost::filesystem;
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;
namespace trivial = boost::log::trivial;
struct Logger {
void init(const fs::path &rErrEvtPath, const fs::path &rStatusPath) {
// register common attributes - ThreadID, LineID, TimeStamp etc.
logging::add_common_attributes();
// Construct the sink for the "event_log" channel
typedef sinks::synchronous_sink<sinks::text_ostream_backend> text_sink;
auto sink = boost::make_shared<text_sink>();
sink->locked_backend()->auto_flush(true);
sink->locked_backend()->add_stream(boost::make_shared<std::ofstream>(rErrEvtPath.c_str()));
sink->set_formatter(expr::format("%1% [%2%] tid[%3%] %4%") %
expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%H:%M:%S.%f") %
logging::trivial::severity % expr::attr<attrs::current_thread_id::value_type>("ThreadID") %
expr::smessage);
sink->set_filter(expr::attr<std::string>("Channel") == "event");
logging::core::get()->add_sink(sink);
// Construct the sink for the "status_log" channel
sink = boost::make_shared<text_sink>();
sink->locked_backend()->auto_flush(true);
sink->locked_backend()->add_stream(boost::make_shared<std::ofstream>(rStatusPath.c_str()));
sink->set_formatter(expr::format("%1% [%2%] tid[%3%] %4%") %
expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%H:%M:%S.%f") %
logging::trivial::severity % expr::attr<attrs::current_thread_id::value_type>("ThreadID") %
expr::smessage);
sink->set_filter(expr::attr<std::string>("Channel") == "status");
logging::core::get()->add_sink(sink);
}
};
BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS(statuc_lg,
src::severity_channel_logger_mt< >, (keywords::severity = trivial::error)(keywords::channel = "status"))
BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS(event_lg,
src::severity_channel_logger_mt< >, (keywords::severity = trivial::error)(keywords::channel = "event"))
#include <boost/thread.hpp>
int main()
{
Logger l;
l.init("test.1", "test.2");
boost::thread_group tg;
tg.create_thread([]{
BOOST_LOG(statuc_lg::get()) << "this is a status update";
BOOST_LOG(event_lg::get()) << "this is an event"; });
tg.create_thread([]{
BOOST_LOG(statuc_lg::get()) << "this is a status update";
BOOST_LOG(event_lg::get()) << "this is an event"; });
tg.join_all();
}
Results:
==> test.1 <==
23:55:58.635779 [] tid[0x00007f26d9a65700] this is an event
23:55:58.635832 [] tid[0x00007f26d9264700] this is an event
==> test.2 <==
23:55:58.635367 [] tid[0x00007f26d9a65700] this is a status update
23:55:58.635540 [] tid[0x00007f26d9264700] this is a status update
source to share