Allow basic_file_sink to open a file in text mode

Added an optional `bool` parameter to the explicit `basic_file_sink`
constructor, allowing to open the file in in text mode, instead of in binary
mode.

Enables automatic conversion of '\n' characters _inside_ a message string to a
platform specific eol representation. (`\r\n` on Windows.)
pull/2636/head
Niels Dekker 3 years ago
parent 927cc29444
commit 8bc619bda9

@ -29,13 +29,13 @@ SPDLOG_INLINE file_helper::~file_helper()
close();
}
SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate)
SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate, bool text_mode)
{
close();
filename_ = fname;
auto *mode = SPDLOG_FILENAME_T("ab");
auto *trunc_mode = SPDLOG_FILENAME_T("wb");
auto *mode = text_mode ? SPDLOG_FILENAME_T("a") : SPDLOG_FILENAME_T("ab");
auto *trunc_mode = text_mode ? SPDLOG_FILENAME_T("w") : SPDLOG_FILENAME_T("wb");
if (event_handlers_.before_open)
{
@ -47,8 +47,8 @@ SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate)
os::create_dir(os::dir_name(fname));
if (truncate)
{
// Truncate by opening-and-closing a tmp file in "wb" mode, always
// opening the actual log-we-write-to in "ab" mode, since that
// Truncate by opening-and-closing a tmp file in trunc mode, always
// opening the actual log-we-write-to in append mode, since that
// interacts more politely with eternal processes that might
// rotate/truncate the file underneath us.
std::FILE *tmp;

@ -23,7 +23,7 @@ public:
file_helper &operator=(const file_helper &) = delete;
~file_helper();
void open(const filename_t &fname, bool truncate = false);
void open(const filename_t &fname, bool truncate = false, bool text_mode = false);
void reopen(bool truncate);
void flush();
void sync();

@ -142,7 +142,7 @@ SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename
# endif
#else // unix
# if defined(SPDLOG_PREVENT_CHILD_FD)
const int mode_flag = mode == SPDLOG_FILENAME_T("ab") ? O_APPEND : O_TRUNC;
const int mode_flag = (mode.find('a') == filename_t::npos) ? O_TRUNC : O_APPEND;
const int fd = ::open((filename.c_str()), O_CREAT | O_WRONLY | O_CLOEXEC | mode_flag, mode_t(0644));
if (fd == -1)
{

@ -53,7 +53,16 @@ void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_formatter(std::unique_pt
template<typename Mutex>
void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_pattern_(const std::string &pattern)
{
const auto current_pattern_formatter = dynamic_cast<spdlog::pattern_formatter *>(formatter_.get());
if (current_pattern_formatter)
{
current_pattern_formatter->set_pattern(pattern);
}
else
{
set_formatter_(details::make_unique<spdlog::pattern_formatter>(pattern));
}
}
template<typename Mutex>

@ -9,15 +9,18 @@
#include <spdlog/common.h>
#include <spdlog/details/os.h>
#include <spdlog/pattern_formatter.h>
namespace spdlog {
namespace sinks {
template<typename Mutex>
SPDLOG_INLINE basic_file_sink<Mutex>::basic_file_sink(const filename_t &filename, bool truncate, const file_event_handlers &event_handlers)
: file_helper_{event_handlers}
SPDLOG_INLINE basic_file_sink<Mutex>::basic_file_sink(
const filename_t &filename, bool truncate, const file_event_handlers &event_handlers, bool text_mode)
: base_sink<Mutex>{details::make_unique<pattern_formatter>(pattern_time_type::local, text_mode ? "\n" : details::os::default_eol)}
, file_helper_{event_handlers}
{
file_helper_.open(filename, truncate);
file_helper_.open(filename, truncate, text_mode);
}
template<typename Mutex>

@ -20,7 +20,8 @@ template<typename Mutex>
class basic_file_sink final : public base_sink<Mutex>
{
public:
explicit basic_file_sink(const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {});
explicit basic_file_sink(
const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}, bool text_mode = false);
const filename_t &filename() const;
protected:

@ -23,6 +23,28 @@ TEST_CASE("simple_file_logger", "[simple_logger]]")
REQUIRE(file_contents(SIMPLE_LOG) == spdlog::fmt_lib::format("Test message 1{}Test message 2{}", default_eol, default_eol));
}
TEST_CASE("text_file_logger", "[text_file_logger]]")
{
spdlog::filename_t filename = SPDLOG_FILENAME_T(SIMPLE_LOG);
for (const bool text_mode : {false, true})
{
prepare_logdir();
auto sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, false, spdlog::file_event_handlers{}, text_mode);
sink->set_pattern("%v");
spdlog::logger logger("logger", sink);
logger.info("Test line {}\nTest line {}", 1, 2);
logger.flush();
require_message_count(SIMPLE_LOG, 2);
using spdlog::details::os::default_eol;
REQUIRE(file_contents(SIMPLE_LOG) ==
spdlog::fmt_lib::format("Test line 1{}Test line 2{}", text_mode ? default_eol : "\n", default_eol));
}
}
TEST_CASE("flush_on", "[flush_on]]")
{
prepare_logdir();

Loading…
Cancel
Save