file_helper.h
Go to the documentation of this file.
1 //
2 // Copyright(c) 2015 Gabi Melman.
3 // Distributed under the MIT License (http://opensource.org/licenses/MIT)
4 //
5 
6 #pragma once
7 
8 // Helper class for file sinks.
9 // When failing to open a file, retry several times(5) with a delay interval(10 ms).
10 // Throw spdlog_ex exception on errors.
11 
12 #include "spdlog/details/log_msg.h"
13 #include "spdlog/details/os.h"
14 
15 #include <cerrno>
16 #include <chrono>
17 #include <cstdio>
18 #include <string>
19 #include <thread>
20 #include <tuple>
21 
22 namespace spdlog {
23 namespace details {
24 
26 {
27 
28 public:
29  const int open_tries = 5;
30  const int open_interval = 10;
31 
32  explicit file_helper() = default;
33 
34  file_helper(const file_helper &) = delete;
35  file_helper &operator=(const file_helper &) = delete;
36 
38  {
39  close();
40  }
41 
42  void open(const filename_t &fname, bool truncate = false)
43  {
44  close();
45  auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab");
46  _filename = fname;
47  for (int tries = 0; tries < open_tries; ++tries)
48  {
49  if (!os::fopen_s(&fd_, fname, mode))
50  {
51  return;
52  }
53 
54  details::os::sleep_for_millis(open_interval);
55  }
56 
57  throw spdlog_ex("Failed opening file " + os::filename_to_str(_filename) + " for writing", errno);
58  }
59 
60  void reopen(bool truncate)
61  {
62  if (_filename.empty())
63  {
64  throw spdlog_ex("Failed re opening file - was not opened before");
65  }
66  open(_filename, truncate);
67  }
68 
69  void flush()
70  {
71  std::fflush(fd_);
72  }
73 
74  void close()
75  {
76  if (fd_ != nullptr)
77  {
78  std::fclose(fd_);
79  fd_ = nullptr;
80  }
81  }
82 
83  void write(const fmt::memory_buffer &buf)
84  {
85  size_t msg_size = buf.size();
86  auto data = buf.data();
87  if (std::fwrite(data, 1, msg_size, fd_) != msg_size)
88  {
89  throw spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno);
90  }
91  }
92 
93  size_t size() const
94  {
95  if (fd_ == nullptr)
96  {
97  throw spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename));
98  }
99  return os::filesize(fd_);
100  }
101 
102  const filename_t &filename() const
103  {
104  return _filename;
105  }
106 
107  static bool file_exists(const filename_t &fname)
108  {
109  return os::file_exists(fname);
110  }
111 
112  //
113  // return file path and its extension:
114  //
115  // "mylog.txt" => ("mylog", ".txt")
116  // "mylog" => ("mylog", "")
117  // "mylog." => ("mylog.", "")
118  // "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
119  //
120  // the starting dot in filenames is ignored (hidden files):
121  //
122  // ".mylog" => (".mylog". "")
123  // "my_folder/.mylog" => ("my_folder/.mylog", "")
124  // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
125  static std::tuple<filename_t, filename_t> split_by_extension(const spdlog::filename_t &fname)
126  {
127  auto ext_index = fname.rfind('.');
128 
129  // no valid extension found - return whole path and empty string as
130  // extension
131  if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1)
132  {
133  return std::make_tuple(fname, spdlog::filename_t());
134  }
135 
136  // treat casese like "/etc/rc.d/somelogfile or "/abc/.hiddenfile"
137  auto folder_index = fname.rfind(details::os::folder_sep);
138  if (folder_index != filename_t::npos && folder_index >= ext_index - 1)
139  {
140  return std::make_tuple(fname, spdlog::filename_t());
141  }
142 
143  // finally - return a valid base and extension tuple
144  return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));
145  }
146 
147 private:
148  std::FILE *fd_{nullptr};
150 };
151 } // namespace details
152 } // namespace spdlog
bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT
Definition: os.h:188
basic_memory_buffer< char > memory_buffer
Definition: format.h:553
void open(const filename_t &fname, bool truncate=false)
Definition: file_helper.h:42
size_t filesize(FILE *f)
Definition: os.h:204
void reopen(bool truncate)
Definition: file_helper.h:60
int errno
Contains the last error code.
Definition: structcmd.h:53
basic_data data
Definition: format.h:764
Definition: async.h:27
static std::tuple< filename_t, filename_t > split_by_extension(const spdlog::filename_t &fname)
Definition: file_helper.h:125
void write(const fmt::memory_buffer &buf)
Definition: file_helper.h:83
bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)
Definition: os.h:148
std::string filename_t
Definition: common.h:202
const filename_t & filename() const
Definition: file_helper.h:102
file_helper & operator=(const file_helper &)=delete
static SPDLOG_CONSTEXPR const char folder_sep
Definition: os.h:126
static bool file_exists(const filename_t &fname)
Definition: file_helper.h:107
#define SPDLOG_FILENAME_T(s)
Definition: os.h:369
void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT
Definition: os.h:351
std::string filename_to_str(const filename_t &filename)
Definition: os.h:370