spdlog/include/spdlog/sinks/file_sinks.h

234 lines
7.6 KiB
C
Raw Normal View History

2014-11-01 03:20:54 +02:00
/*************************************************************************/
/* spdlog - an extremely fast and easy to use c++11 logging library. */
/* Copyright (c) 2014 Gabi Melman. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2014-03-22 14:11:17 +02:00
2014-11-01 03:20:54 +02:00
#pragma once
#include <mutex>
2014-11-01 03:20:54 +02:00
#include "base_sink.h"
#include "../details/null_mutex.h"
2014-10-26 01:29:50 +02:00
#include "../details/file_helper.h"
2014-11-29 17:10:17 +02:00
#include "../details/format.h"
2015-07-13 19:43:22 +06:00
#include "../details/os.h"
2014-10-31 01:13:27 +02:00
namespace spdlog
2014-03-22 14:11:17 +02:00
{
namespace sinks
{
/*
* Trivial file sink with single file as target
2014-03-22 14:11:17 +02:00
*/
template<class Mutex>
class simple_file_sink : public base_sink < Mutex >
2014-03-22 14:11:17 +02:00
{
public:
2014-12-21 02:47:04 +02:00
explicit simple_file_sink(const std::string &filename,
bool force_flush = false) :
_file_helper(force_flush)
2014-12-21 02:47:04 +02:00
{
_file_helper.open(filename);
}
void flush() override
{
_file_helper.flush();
}
2014-03-22 14:11:17 +02:00
protected:
2014-12-21 02:47:04 +02:00
void _sink_it(const details::log_msg& msg) override
{
_file_helper.write(msg);
}
2014-03-22 14:11:17 +02:00
private:
2014-12-21 02:47:04 +02:00
details::file_helper _file_helper;
2014-03-22 14:11:17 +02:00
};
typedef simple_file_sink<std::mutex> simple_file_sink_mt;
typedef simple_file_sink<details::null_mutex> simple_file_sink_st;
2014-03-22 14:11:17 +02:00
/*
* Rotating file sink based on size
*/
template<class Mutex>
class rotating_file_sink : public base_sink < Mutex >
2014-03-22 14:11:17 +02:00
{
public:
2015-07-13 19:43:22 +06:00
rotating_file_sink(const tstring &base_filename, const tstring &extension,
2014-12-21 02:47:04 +02:00
std::size_t max_size, std::size_t max_files,
bool force_flush = false) :
2014-12-21 02:47:04 +02:00
_base_filename(base_filename),
_extension(extension),
_max_size(max_size),
_max_files(max_files),
_current_size(0),
_file_helper(force_flush)
2014-12-21 02:47:04 +02:00
{
_file_helper.open(calc_filename(_base_filename, 0, _extension));
}
2014-03-22 14:11:17 +02:00
2015-05-09 16:03:43 +03:00
void flush() override
{
2015-05-08 22:57:52 +02:00
_file_helper.flush();
}
2014-03-22 14:11:17 +02:00
protected:
2014-12-21 02:47:04 +02:00
void _sink_it(const details::log_msg& msg) override
{
_current_size += msg.formatted.size();
if (_current_size > _max_size)
2014-12-21 02:47:04 +02:00
{
_rotate();
_current_size = msg.formatted.size();
}
_file_helper.write(msg);
}
2014-03-22 14:11:17 +02:00
private:
2015-07-13 19:43:22 +06:00
static tstring calc_filename(const tstring& filename, std::size_t index, const tstring& extension)
2014-12-21 02:47:04 +02:00
{
2015-07-13 19:43:22 +06:00
fmt::TMemoryWriter w;
2014-12-21 02:47:04 +02:00
if (index)
w.write(S("{}.{}.{}"), filename, index, extension);
2014-12-21 02:47:04 +02:00
else
w.write(S("{}.{}"), filename, extension);
2014-12-21 02:47:04 +02:00
return w.str();
}
// Rotate files:
// log.txt -> log.1.txt
// log.1.txt -> log2.txt
// log.2.txt -> log3.txt
// log.3.txt -> delete
void _rotate()
{
_file_helper.close();
for (auto i = _max_files; i > 0; --i)
{
2015-07-13 19:43:22 +06:00
tstring src = calc_filename(_base_filename, i - 1, _extension);
tstring target = calc_filename(_base_filename, i, _extension);
2014-12-21 02:47:04 +02:00
if (details::file_helper::file_exists(target))
{
2015-07-13 19:43:22 +06:00
if (details::os::remove(target.c_str()) != 0)
2014-12-21 02:47:04 +02:00
{
2015-07-13 19:43:22 +06:00
throw spdlog_ex("rotating_file_sink: failed removing");
2014-12-21 02:47:04 +02:00
}
}
2015-07-13 19:43:22 +06:00
if (details::file_helper::file_exists(src) && details::os::rename(src.c_str(), target.c_str()))
2014-12-21 02:47:04 +02:00
{
2015-07-13 19:43:22 +06:00
throw spdlog_ex("rotating_file_sink: failed renaming");
2014-12-21 02:47:04 +02:00
}
}
_file_helper.reopen(true);
}
2015-07-13 19:43:22 +06:00
tstring _base_filename,
_extension;
std::size_t _max_size,
_max_files,
_current_size;
2014-12-21 02:47:04 +02:00
details::file_helper _file_helper;
2014-03-22 14:11:17 +02:00
};
typedef rotating_file_sink<std::mutex> rotating_file_sink_mt;
typedef rotating_file_sink<details::null_mutex>rotating_file_sink_st;
2014-03-22 14:11:17 +02:00
/*
* Rotating file sink based on date. rotates at midnight
2014-03-22 14:11:17 +02:00
*/
template<class Mutex>
class daily_file_sink :public base_sink < Mutex >
2014-03-22 14:11:17 +02:00
{
public:
//create daily file sink which rotates on given time
daily_file_sink(
2015-07-13 19:43:22 +06:00
const tstring& base_filename,
const tstring& extension,
int rotation_hour,
int rotation_minute,
bool force_flush = false) : _base_filename(base_filename),
2014-12-21 02:47:04 +02:00
_extension(extension),
_rotation_h(rotation_hour),
_rotation_m(rotation_minute),
_file_helper(force_flush)
2014-12-21 02:47:04 +02:00
{
if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59)
throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor");
_rotation_tp = _next_rotation_tp();
2014-12-21 02:47:04 +02:00
_file_helper.open(calc_filename(_base_filename, _extension));
}
2014-03-22 14:11:17 +02:00
2015-05-09 16:03:43 +03:00
void flush() override
{
2015-05-08 22:57:52 +02:00
_file_helper.flush();
}
2014-03-22 14:11:17 +02:00
protected:
2014-12-21 02:47:04 +02:00
void _sink_it(const details::log_msg& msg) override
{
if (std::chrono::system_clock::now() >= _rotation_tp)
2014-12-21 02:47:04 +02:00
{
_file_helper.open(calc_filename(_base_filename, _extension));
_rotation_tp = _next_rotation_tp();
2014-12-21 02:47:04 +02:00
}
_file_helper.write(msg);
}
2014-03-22 14:11:17 +02:00
private:
std::chrono::system_clock::time_point _next_rotation_tp()
2014-12-21 02:47:04 +02:00
{
using namespace std::chrono;
auto now = system_clock::now();
time_t tnow = std::chrono::system_clock::to_time_t(now);
tm date = spdlog::details::os::localtime(tnow);
date.tm_hour = _rotation_h;
date.tm_min = _rotation_m;
date.tm_sec = 0;
auto rotation_time = std::chrono::system_clock::from_time_t(std::mktime(&date));
if (rotation_time > now)
return rotation_time;
else
return system_clock::time_point(rotation_time + hours(24));
2014-12-21 02:47:04 +02:00
}
//Create filename for the form basename.YYYY-MM-DD.extension
2015-07-13 19:43:22 +06:00
static tstring calc_filename(const tstring& basename, const tstring& extension)
2014-12-21 02:47:04 +02:00
{
std::tm tm = spdlog::details::os::localtime();
2015-07-13 19:43:22 +06:00
fmt::TMemoryWriter w;
w.write(S("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.{}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, extension);
2014-12-21 02:47:04 +02:00
return w.str();
}
2015-07-13 19:43:22 +06:00
tstring _base_filename;
tstring _extension;
int _rotation_h;
int _rotation_m;
std::chrono::system_clock::time_point _rotation_tp;
2014-12-21 02:47:04 +02:00
details::file_helper _file_helper;
2014-03-22 14:11:17 +02:00
};
typedef daily_file_sink<std::mutex> daily_file_sink_mt;
typedef daily_file_sink<details::null_mutex> daily_file_sink_st;
2014-03-22 14:11:17 +02:00
}
}