I have a fairly basic singleton logger class that wraps around spdlog, and that I intend to use throughout my code via the macros defined to log to files. The problem I am having is that I cannot get it to log to files. If I use the spdlog::stdout_color_mt
it outputs to stdout as expected. But if I try either spdlog::basic_logger_mt
or spdlog::basic_logger_mt<spdlog::async_factory>
the log file is created, but is empty. If I call logger_->flush()
after each use, all I get is the first line "Log start: ... " I also assume you shouldn't have to flush manually after every use.
The interesting thing is that if I test the logger with the sample usage below it all works except for the "log end" in the Logger class destructor. But when I use the exact same header in my project, the log file is empty.
My question is: is there something obvious I am missing?
Here is the logger class:
#pragma once
#include <string>
#include <chrono>
#include <iostream>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/async.h"
#define LOG_TRACE(format, ...) spdlog::trace(format, ##__VA_ARGS__)
#define LOG_DEBUG(format, ...) spdlog::debug(format, ##__VA_ARGS__)
#define LOG_INFO(format, ...) spdlog::info(format, ##__VA_ARGS__)
#define LOG_WARN(format, ...) spdlog::warn(format, ##__VA_ARGS__)
#define LOG_ERROR(format, ...) spdlog::error(format, ##__VA_ARGS__)
#define LOG_CRITICAL(format, ...) spdlog::critical(format, ##__VA_ARGS__)
class Logger
{
public:
~Logger()
{
if (initialised_)
{
spdlog::info("Log end");
spdlog::shutdown();
}
}
static Logger& Instance()
{
static Logger instance;
return instance;
}
void Initialise(const std::string& filename, spdlog::level::level_enum level)
{
if (initialised_) return;
try
{
// logger_ = spdlog::stdout_color_mt("log");
auto logger = spdlog::basic_logger_mt("log", filename);
// spdlog::init_thread_pool(8192, 1);
// logger_ = spdlog::basic_logger_mt<spdlog::async_factory>("log", filename);
// logger_ = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "async_log.txt");
spdlog::set_default_logger(logger);
logger->set_pattern("[%H:%M:%S.%F] [%l] %v");
logger->set_level(level);
auto start = std::chrono::system_clock::now();
std::time_t starttime = std::chrono::system_clock::to_time_t(start);
spdlog::info("Log start: {}", std::ctime(&starttime));
initialised_ = true;
}
catch (spdlog::spdlog_ex& e)
{
std::cout << "log init failed: " << e.what() << std::endl;
}
}
Logger(const Logger&) = delete;
void operator=(const Logger&) = delete;
private:
Logger() {}
private:
bool initialised_ {false};
};
And basic usage:
class LogUser
{
public:
LogUser() { LOG_INFO("another class using logger"); }
void LogUsername() { LOG_INFO("username"); }
};
void AnotherFunc()
{
LOG_WARN("logging from another function");
}
int main(int argc, char** argv)
{
Logger::Instance().Initialise("log.txt", spdlog::level::info);
LOG_INFO("logging something");
LogUser user;
AnotherFunc();
user.LogUsername();
return 0;
}
Summary of what I have tried:
spdlog::stdout_color_mt
in basic example above: worksspdlog::basic_logger_mt
in basic example above: worksspdlog::stdout_color_mt
in project: worksspdlog::basic_logger_mt
in project: Doesn't work
Caveat for cases that work: "Log end" in the ~Logger()
doesn't work.