How to log to file AND debugger at once?
-
Hi there,
I know that I can install mal own message handler to write debug output in a file. But that disables the debug output in QtCreator completely.
How can I write my debug messages to the debugger again?
fprintf(stderr, ...) doesnt work.regards,
Tobias -
@Tobias-Fensch
My recollection: QtMessageHandler qInstallMessageHandler(QtMessageHandler handler)Installs a Qt message handler which has been defined previously. Returns a pointer to the previous message handler.
I think you need to remember that previous message handler returned when you install and call that explicitly at the beginning or end of your own added code, to get the original behaviour too. Try it out.
-
@Tobias-Fensch If you write your custom handler in a way that it logs both to file and console you get the desired output. I for example use a custom qt message handler to redirect logging to spdlog library which displays both on console and writes asynchronously to file
-
@Tobias-Fensch
My recollection: QtMessageHandler qInstallMessageHandler(QtMessageHandler handler)Installs a Qt message handler which has been defined previously. Returns a pointer to the previous message handler.
I think you need to remember that previous message handler returned when you install and call that explicitly at the beginning or end of your own added code, to get the original behaviour too. Try it out.
-
@Tobias-Fensch
I use the following code for logging to console and file:#include <fmt/format.h> #include <qlogging.h> #include <QDebug> #include <spdlog/spdlog.h> #include "spdlog/async.h" #include <spdlog/sinks/stdout_color_sinks.h> #include <spdlog/sinks/rotating_file_sink.h> #include <QStandardPaths> #include <QFile> #include "logging.h" static void init_spdlog() { constexpr int FILE_SIZE = 1 * 1024 * 1024; // 1 Megabyte constexpr int NUM_KEPT_LOGS = 2; spdlog::init_thread_pool(8192, 1); auto stdout_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); const QString fileName{"app.log"}; auto logFileLocation = QStandardPaths::locate(QStandardPaths::StandardLocation::DocumentsLocation, "", QStandardPaths::LocateDirectory); if (logFileLocation.isEmpty()) { qFatal("Unable to find standard directory"); } logFileLocation += fileName; auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(logFileLocation.toStdString(), FILE_SIZE, NUM_KEPT_LOGS); std::vector<spdlog::sink_ptr> sinks{stdout_sink, rotating_sink}; auto logger = std::make_shared<spdlog::async_logger>("loggername", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block); spdlog::set_default_logger(logger); spdlog::set_pattern("[%H:%M:%S.%f] [%^%=10l%$] [thread %t] %v"); spdlog::flush_every(std::chrono::seconds(3)); spdlog::set_level(spdlog::level::debug); // Set global log level to debug } static void qt_message_handler(QtMsgType type, [[maybe_unused]] const QMessageLogContext &context, const QString &msg) { const QByteArray localMsg = msg.toLocal8Bit(); #ifdef NDEBUG const auto out_msg = fmt::format("\t{}", localMsg.constData()); #else const char *function = context.function ? context.function : ""; const auto out_msg = fmt::format("\t{} [LINE:{}, {}]", localMsg.constData(), context.line, function); #endif switch (type) { case QtDebugMsg: spdlog::debug(out_msg); break; case QtInfoMsg: spdlog::info(out_msg); break; case QtWarningMsg: spdlog::warn(out_msg); break; case QtCriticalMsg: spdlog::error(out_msg); break; case QtFatalMsg: spdlog::critical(out_msg); spdlog::shutdown(); break; } } void init_logging() { init_spdlog(); qInstallMessageHandler(qt_message_handler); }
-
Hi,
Your issue is in fact simple: your handler only writes to your logger hence no message seen anymore on the standard output/error channels.