diff options
| author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2018-06-27 16:59:37 +0200 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2018-06-27 16:59:37 +0200 | 
| commit | 8111b77e95b083137faf888aeb5892073adf7ab4 (patch) | |
| tree | ed3896dfd2c2bbd9cc41f0bfcab1ee2a41c1cc77 /lib/spdlog/contrib/sinks/step_file_sink.h | |
| parent | e767091d649df311dd221e243ab2ce54776ae779 (diff) | |
New upstream version 2.0.0upstream/2.0.0
Diffstat (limited to 'lib/spdlog/contrib/sinks/step_file_sink.h')
| -rw-r--r-- | lib/spdlog/contrib/sinks/step_file_sink.h | 216 | 
1 files changed, 216 insertions, 0 deletions
diff --git a/lib/spdlog/contrib/sinks/step_file_sink.h b/lib/spdlog/contrib/sinks/step_file_sink.h new file mode 100644 index 0000000..85e24e9 --- /dev/null +++ b/lib/spdlog/contrib/sinks/step_file_sink.h @@ -0,0 +1,216 @@ +#pragma once + +#include "../../details/file_helper.h" +#include "../../details/null_mutex.h" +#include "../../fmt/fmt.h" +#include "../../sinks/base_sink.h" + +#include <algorithm> +#include <cerrno> +#include <chrono> +#include <cstdio> +#include <ctime> +#include <mutex> +#include <string> + +// Example for spdlog.h +// +// Create a file logger which creates new files with a specified time step and fixed file size: +// +// std::shared_ptr<logger> step_logger_mt(const std::string &logger_name, const filename_t &filename, unsigned seconds = 60, const +// filename_t &tmp_ext = ".tmp", unsigned max_file_size = std::numeric_limits<unsigned>::max(), bool delete_empty_files = true, const +// filename_t &file_header = ""); std::shared_ptr<logger> step_logger_st(const std::string &logger_name, const filename_t &filename, +// unsigned seconds = 60, const filename_t &tmp_ext = ".tmp", unsigned max_file_size = std::numeric_limits<unsigned>::max()); + +// Example for spdlog_impl.h +// Create a file logger that creates new files with a specified increment +// inline std::shared_ptr<spdlog::logger> spdlog::step_logger_mt( +//     const std::string &logger_name, const filename_t &filename_fmt, unsigned seconds, const filename_t &tmp_ext, unsigned max_file_size, +//     bool delete_empty_files, const filename_t &file_header) +// { +//     return create<spdlog::sinks::step_file_sink_mt>(logger_name, filename_fmt, seconds, tmp_ext, max_file_size, delete_empty_files, +//     file_header); +// } + +// inline std::shared_ptr<spdlog::logger> spdlog::step_logger_st( +//     const std::string &logger_name, const filename_t &filename_fmt, unsigned seconds, const filename_t &tmp_ext, unsigned max_file_size, +//     bool delete_empty_files, const filename_t &file_header) +// { +//     return create<spdlog::sinks::step_file_sink_st>(logger_name, filename_fmt, seconds, tmp_ext, max_file_size, delete_empty_files, +//     file_header); +// } + +namespace spdlog { +namespace sinks { + +/* + * Default generator of step log file names. + */ +struct default_step_file_name_calculator +{ +    // Create filename for the form filename_YYYY-MM-DD_hh-mm-ss.ext +    static std::tuple<filename_t, filename_t> calc_filename(const filename_t &filename, const filename_t &tmp_ext) +    { +        std::tm tm = spdlog::details::os::localtime(); +        filename_t basename, ext; +        std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename); +        std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w; +        w.write(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}-{:02d}{}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, +            tm.tm_hour, tm.tm_min, tm.tm_sec, tmp_ext); +        return std::make_tuple(w.str(), ext); +    } +}; + +/* + * Rotating file sink based on size and a specified time step + */ +template<class Mutex, class FileNameCalc = default_step_file_name_calculator> +class step_file_sink SPDLOG_FINAL : public base_sink<Mutex> +{ +public: +    step_file_sink(filename_t base_filename, unsigned step_seconds, filename_t tmp_ext, unsigned max_size, bool delete_empty_files, +        filename_t file_header) +        : _base_filename(std::move(base_filename)) +        , _tmp_ext(std::move(tmp_ext)) +        , _step_seconds(step_seconds) +        , _max_size(max_size) +        , _delete_empty_files(delete_empty_files) +    { +        if (step_seconds == 0) +        { +            throw spdlog_ex("step_file_sink: Invalid time step in ctor"); +        } + +        if (!file_header.empty()) +        { +            pattern_formatter formatter_for_file_header("%v"); +            _file_header.raw << file_header; +            formatter_for_file_header.format(_file_header); +        } + +        if (max_size <= _file_header.formatted.size()) +        { +            throw spdlog_ex("step_file_sink: Invalid max log size in ctor"); +        } + +        _tp = _next_tp(); +        std::tie(_current_filename, _ext) = FileNameCalc::calc_filename(_base_filename, _tmp_ext); + +        if (_tmp_ext == _ext) +        { +            throw spdlog_ex("step_file_sink: The temporary extension matches the specified in ctor"); +        } + +        _file_helper.open(_current_filename); +        _current_size = _file_helper.size(); // expensive. called only once + +        if (!_current_size) +        { +            _current_size += _file_header.formatted.size(); +            if (_current_size) +                _file_helper.write(_file_header); +        } +    } + +    ~step_file_sink() +    { +        try +        { +            close_current_file(); +        } +        catch (...) +        { +        } +    } + +protected: +    void _sink_it(const details::log_msg &msg) override +    { +        auto msg_size = msg.formatted.size(); + +        if (std::chrono::system_clock::now() >= _tp || _current_size + msg_size > _max_size) +        { +            filename_t new_filename; +            std::tie(new_filename, std::ignore) = FileNameCalc::calc_filename(_base_filename, _tmp_ext); + +            bool change_occured = !details::file_helper::file_exists(new_filename); +            if (change_occured) +            { +                close_current_file(); + +                _current_filename = std::move(new_filename); + +                _file_helper.open(_current_filename); +            } + +            _tp = _next_tp(); + +            if (change_occured) +            { +                _current_size = _file_header.formatted.size(); +                if (_current_size) +                    _file_helper.write(_file_header); +            } +        } + +        _current_size += msg_size; +        _file_helper.write(msg); +    } + +    void _flush() override +    { +        _file_helper.flush(); +    } + +private: +    std::chrono::system_clock::time_point _next_tp() +    { +        return std::chrono::system_clock::now() + _step_seconds; +    } + +    void close_current_file() +    { +        using details::os::filename_to_str; + +        // Delete empty files, if required +        if (_delete_empty_files && _current_size <= _file_header.formatted.size()) +        { +            if (details::os::remove(_current_filename) != 0) +            { +                throw spdlog_ex("step_file_sink: not remove " + filename_to_str(_current_filename), errno); +            } + +            return; +        } + +        filename_t target; +        std::tie(target, std::ignore) = details::file_helper::split_by_extenstion(_current_filename); +        target += _ext; + +        if (details::file_helper::file_exists(_current_filename) && details::os::rename(_current_filename, target) != 0) +        { +            throw spdlog_ex( +                "step_file_sink: failed renaming " + filename_to_str(_current_filename) + " to " + filename_to_str(target), errno); +        } +    } + +    const filename_t _base_filename; +    const filename_t _tmp_ext; +    const std::chrono::seconds _step_seconds; +    const unsigned _max_size; +    const bool _delete_empty_files; + +    std::chrono::system_clock::time_point _tp; +    filename_t _current_filename; +    filename_t _ext; +    unsigned _current_size; + +    details::file_helper _file_helper; +    details::log_msg _file_header; +}; + +using step_file_sink_mt = step_file_sink<std::mutex>; +using step_file_sink_st = step_file_sink<details::null_mutex>; + +} // namespace sinks +} // namespace spdlog  | 
