Agora  1.2.0
Agora project
hourly_file_sink.h
Go to the documentation of this file.
1 // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
2 // Distributed under the MIT License (http://opensource.org/licenses/MIT)
3 
4 #pragma once
5 
6 #include <spdlog/common.h>
9 #include <spdlog/fmt/fmt.h>
10 #include <spdlog/sinks/base_sink.h>
11 #include <spdlog/details/os.h>
14 
15 #include <chrono>
16 #include <cstdio>
17 #include <ctime>
18 #include <mutex>
19 #include <string>
20 
21 namespace spdlog {
22 namespace sinks {
23 
24 /*
25  * Generator of Hourly log file names in format basename.YYYY-MM-DD-HH.ext
26  */
28 {
29  // Create filename for the form basename.YYYY-MM-DD-H
30  static filename_t calc_filename(const filename_t &filename, const tm &now_tm)
31  {
32  filename_t basename, ext;
33  std::tie(basename, ext) = details::file_helper::split_by_extension(filename);
34  return fmt_lib::format(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1,
35  now_tm.tm_mday, now_tm.tm_hour, ext);
36  }
37 };
38 
39 /*
40  * Rotating file sink based on time.
41  * If truncate != false , the created file will be truncated.
42  * If max_files > 0, retain only the last max_files and delete previous.
43  */
44 template<typename Mutex, typename FileNameCalc = hourly_filename_calculator>
45 class hourly_file_sink final : public base_sink<Mutex>
46 {
47 public:
48  // create hourly file sink which rotates on given time
50  filename_t base_filename, bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {})
51  : base_filename_(std::move(base_filename))
52  , file_helper_{event_handlers}
53  , truncate_(truncate)
54  , max_files_(max_files)
55  , filenames_q_()
56  {
57  auto now = log_clock::now();
58  auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now));
61 
62  if (max_files_ > 0)
63  {
65  }
66  }
67 
69  {
70  std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
71  return file_helper_.filename();
72  }
73 
74 protected:
75  void sink_it_(const details::log_msg &msg) override
76  {
77  auto time = msg.time;
78  bool should_rotate = time >= rotation_tp_;
79  if (should_rotate)
80  {
81  auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time));
84  }
85  memory_buf_t formatted;
86  base_sink<Mutex>::formatter_->format(msg, formatted);
87  file_helper_.write(formatted);
88 
89  // Do the cleaning only at the end because it might throw on failure.
90  if (should_rotate && max_files_ > 0)
91  {
92  delete_old_();
93  }
94  }
95 
96  void flush_() override
97  {
99  }
100 
101 private:
103  {
105 
107  std::vector<filename_t> filenames;
108  auto now = log_clock::now();
109  while (filenames.size() < max_files_)
110  {
111  auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now));
112  if (!path_exists(filename))
113  {
114  break;
115  }
116  filenames.emplace_back(filename);
117  now -= std::chrono::hours(1);
118  }
119  for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter)
120  {
121  filenames_q_.push_back(std::move(*iter));
122  }
123  }
124 
125  tm now_tm(log_clock::time_point tp)
126  {
127  time_t tnow = log_clock::to_time_t(tp);
128  return spdlog::details::os::localtime(tnow);
129  }
130 
131  log_clock::time_point next_rotation_tp_()
132  {
133  auto now = log_clock::now();
134  tm date = now_tm(now);
135  date.tm_min = 0;
136  date.tm_sec = 0;
137  auto rotation_time = log_clock::from_time_t(std::mktime(&date));
138  if (rotation_time > now)
139  {
140  return rotation_time;
141  }
142  return {rotation_time + std::chrono::hours(1)};
143  }
144 
145  // Delete the file N rotations ago.
146  // Throw spdlog_ex on failure to delete the old file.
147  void delete_old_()
148  {
151 
152  filename_t current_file = file_helper_.filename();
153  if (filenames_q_.full())
154  {
155  auto old_filename = std::move(filenames_q_.front());
157  bool ok = remove_if_exists(old_filename) == 0;
158  if (!ok)
159  {
160  filenames_q_.push_back(std::move(current_file));
161  SPDLOG_THROW(spdlog_ex("Failed removing hourly file " + filename_to_str(old_filename), errno));
162  }
163  }
164  filenames_q_.push_back(std::move(current_file));
165  }
166 
168  log_clock::time_point rotation_tp_;
170  bool truncate_;
171  uint16_t max_files_;
173 };
174 
177 
178 } // namespace sinks
179 
180 //
181 // factory functions
182 //
183 template<typename Factory = spdlog::synchronous_factory>
184 inline std::shared_ptr<logger> hourly_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false,
185  uint16_t max_files = 0, const file_event_handlers &event_handlers = {})
186 {
187  return Factory::template create<sinks::hourly_file_sink_mt>(logger_name, filename, truncate, max_files, event_handlers);
188 }
189 
190 template<typename Factory = spdlog::synchronous_factory>
191 inline std::shared_ptr<logger> hourly_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false,
192  uint16_t max_files = 0, const file_event_handlers &event_handlers = {})
193 {
194  return Factory::template create<sinks::hourly_file_sink_st>(logger_name, filename, truncate, max_files, event_handlers);
195 }
196 } // namespace spdlog
circular_q.h
file_helper.h
spdlog::hourly_logger_st
std::shared_ptr< logger > hourly_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate=false, uint16_t max_files=0, const file_event_handlers &event_handlers={})
Definition: hourly_file_sink.h:191
spdlog::sinks::hourly_file_sink::init_filenames_q_
void init_filenames_q_()
Definition: hourly_file_sink.h:102
spdlog::file_event_handlers
Definition: common.h:308
spdlog::details::file_helper::open
void open(const filename_t &fname, bool truncate=false)
Definition: file_helper-inl.h:32
spdlog::sinks::hourly_file_sink::next_rotation_tp_
log_clock::time_point next_rotation_tp_()
Definition: hourly_file_sink.h:131
spdlog::sinks::hourly_file_sink::truncate_
bool truncate_
Definition: hourly_file_sink.h:170
base_sink.h
spdlog::details::file_helper::split_by_extension
static std::tuple< filename_t, filename_t > split_by_extension(const filename_t &fname)
Definition: file_helper-inl.h:149
spdlog::details::circular_q::full
bool full() const
Definition: circular_q.h:109
spdlog::details::os::path_exists
SPDLOG_INLINE bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT
Definition: os-inl.h:187
spdlog::sinks::hourly_file_sink::filename
filename_t filename()
Definition: hourly_file_sink.h:68
spdlog::details::file_helper
Definition: file_helper.h:16
synchronous_factory.h
spdlog::details::circular_q::pop_front
void pop_front()
Definition: circular_q.h:99
spdlog::details::os::now
SPDLOG_INLINE spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT
Definition: os-inl.h:71
spdlog::sinks::hourly_file_sink::flush_
void flush_() override
Definition: hourly_file_sink.h:96
spdlog::details::os::remove_if_exists
SPDLOG_INLINE int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT
Definition: os-inl.h:172
spdlog::sinks::hourly_filename_calculator
Definition: hourly_file_sink.h:27
spdlog::sinks::hourly_file_sink::now_tm
tm now_tm(log_clock::time_point tp)
Definition: hourly_file_sink.h:125
spdlog::sinks::hourly_file_sink::rotation_tp_
log_clock::time_point rotation_tp_
Definition: hourly_file_sink.h:168
spdlog::sinks::hourly_file_sink::delete_old_
void delete_old_()
Definition: hourly_file_sink.h:147
filename
filename
Definition: parse_all_dl.m:14
spdlog::sinks::hourly_file_sink::filenames_q_
details::circular_q< filename_t > filenames_q_
Definition: hourly_file_sink.h:172
null_mutex.h
spdlog::sinks::hourly_file_sink::max_files_
uint16_t max_files_
Definition: hourly_file_sink.h:171
fmt::v8::basic_memory_buffer
Definition: format.h:677
spdlog::hourly_logger_mt
std::shared_ptr< logger > hourly_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate=false, uint16_t max_files=0, const file_event_handlers &event_handlers={})
Definition: hourly_file_sink.h:184
spdlog
Definition: async.h:25
spdlog::sinks::hourly_file_sink::file_helper_
details::file_helper file_helper_
Definition: hourly_file_sink.h:169
spdlog::sinks::base_sink
Definition: base_sink.h:19
spdlog::details::file_helper::filename
const filename_t & filename() const
Definition: file_helper-inl.h:131
spdlog::details::os::filename_to_str
SPDLOG_INLINE std::string filename_to_str(const filename_t &filename)
Definition: os-inl.h:398
spdlog::details::os::localtime
SPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
Definition: os-inl.h:84
os.h
spdlog::sinks::hourly_file_sink::sink_it_
void sink_it_(const details::log_msg &msg) override
Definition: hourly_file_sink.h:75
spdlog::sinks::hourly_file_sink::hourly_file_sink
hourly_file_sink(filename_t base_filename, bool truncate=false, uint16_t max_files=0, const file_event_handlers &event_handlers={})
Definition: hourly_file_sink.h:49
spdlog::sinks::hourly_filename_calculator::calc_filename
static filename_t calc_filename(const filename_t &filename, const tm &now_tm)
Definition: hourly_file_sink.h:30
spdlog::sinks::hourly_file_sink::base_filename_
filename_t base_filename_
Definition: hourly_file_sink.h:167
spdlog::spdlog_ex
Definition: common.h:276
spdlog::details::file_helper::write
void write(const memory_buf_t &buf)
Definition: file_helper-inl.h:112
SPDLOG_THROW
#define SPDLOG_THROW(ex)
Definition: common.h:103
SPDLOG_FILENAME_T
#define SPDLOG_FILENAME_T(s)
Definition: common.h:123
spdlog::details::file_helper::flush
void flush()
Definition: file_helper-inl.h:85
common.h
spdlog::details::log_msg
Definition: log_msg.h:11
spdlog::filename_t
std::string filename_t
Definition: common.h:122
spdlog::details::circular_q::front
const T & front() const
Definition: circular_q.h:66
fmt.h
spdlog::details::circular_q< filename_t >
spdlog::details::log_msg::time
log_clock::time_point time
Definition: log_msg.h:22
spdlog::details::circular_q::push_back
void push_back(T &&item)
Definition: circular_q.h:49
spdlog::sinks::hourly_file_sink
Definition: hourly_file_sink.h:45
utils::format
std::string format(const T &value)
Definition: utils.h:15