6 #ifndef SL_LOG_FILE_SINK_HPP
7 #define SL_LOG_FILE_SINK_HPP
78 template <Record TRecord>
117 Super{ m_FileStream }
131 if (m_FileStream.is_open())
164 std::scoped_lock lock{ m_RotationRuleMx };
165 m_RotationRule = rule;
174 return load(m_RotationRule, m_RotationRuleMx);
183 if (m_FileStream.is_open())
196 std::scoped_lock lock{ m_CleanupRuleMx };
197 m_CleanupRule = rule;
206 return load(m_CleanupRule, m_CleanupRuleMx);
215 template <FileStateHandler THandler>
218 std::scoped_lock lock{ m_OpeningHandlerMx };
219 m_OpeningHandler = std::forward<THandler>(handler);
227 std::scoped_lock lock{ m_OpeningHandlerMx };
228 m_OpeningHandler =
nullptr;
237 template <FileStateHandler THandler>
240 std::scoped_lock lock{ m_ClosingHandlerMx };
241 m_ClosingHandler = std::forward<THandler>(handler);
249 std::scoped_lock lock{ m_ClosingHandlerMx };
250 m_ClosingHandler =
nullptr;
260 std::scoped_lock lock{ m_FilePathNameMx };
262 create_directories(m_Directory);
272 std::scoped_lock lock{ m_FilePathNameMx };
292 throw SinkException{
"FileNamePattern must contain any directory information. Use directory property instead." };
295 std::scoped_lock lock{ m_FilePathNameMx };
306 std::scoped_lock lock{ m_FilePathNameMx };
313 mutable std::mutex m_FilePathNameMx;
315 std::filesystem::path m_Directory;
317 std::ofstream m_FileStream;
318 std::optional<std::filesystem::path> m_CurrentFilePath;
321 std::atomic<std::chrono::steady_clock::time_point> m_FileOpeningTime;
322 mutable std::mutex m_RotationRuleMx;
323 RotationRule m_RotationRule;
326 mutable std::mutex m_CleanupRuleMx;
327 CleanupRule m_CleanupRule;
330 std::mutex m_OpeningHandlerMx;
332 std::mutex m_ClosingHandlerMx;
339 std::scoped_lock lock{ m_FilePathNameMx };
340 return m_Directory / m_FileNamePattern.
next();
343 m_FileStream.open(filePath);
344 if (!m_FileStream.is_open())
346 throw SinkException{
"FileSink: Attempted opening file \"" + filePath.string() +
"\" but failed." };
349 m_CurrentFilePath = std::move(filePath);
350 m_FileOpeningTime = std::chrono::steady_clock::now();
352 if (std::scoped_lock lock{ m_OpeningHandlerMx }; m_OpeningHandler)
360 assert(m_FileStream.is_open() &&
"FileStream must be open.");
361 assert(m_CurrentFilePath && !std::empty(*m_CurrentFilePath));
363 if (std::scoped_lock lock{ m_ClosingHandlerMx }; m_ClosingHandler)
368 m_FileStream.close();
369 removeFilesIfNecessary();
370 m_CurrentFilePath.reset();
371 m_FileOpeningTime.store({});
374 void removeFilesIfNecessary()
377 auto directoryItr = std::filesystem::directory_iterator(m_CurrentFilePath->parent_path());
379 std::vector<std::filesystem::directory_entry> files;
380 for (
const auto& entry : directoryItr)
382 if (is_regular_file(entry) && entry.path().extension() == m_CurrentFilePath->extension() &&
383 !equivalent(entry.path(), *m_CurrentFilePath))
385 files.emplace_back(entry);
389 std::ranges::sort(files, std::greater(), [](
const auto& file) {
return last_write_time(file); });
390 fulfillFileCountCleanup(files);
391 fulfillDirectorySizeCleanup(files);
394 template <
class T,
class TMutex>
395 static T load(
const T&
object, TMutex& mutex)
397 std::scoped_lock lock{ mutex };
401 void fulfillFileCountCleanup(std::vector<std::filesystem::directory_entry>& files)
const
403 auto cleanupRule = load(m_CleanupRule, m_CleanupRuleMx);
409 auto& file = files.back();
415 void fulfillDirectorySizeCleanup(std::vector<std::filesystem::directory_entry>& files)
const
417 auto cleanupRule = load(m_CleanupRule, m_CleanupRuleMx);
421 auto size = std::accumulate(
425 [](
auto value,
const auto& file) {
return value + file.file_size(); }
429 auto& file = files.back();
430 size -= file_size(file);
437 bool shallRotate()
const
439 assert(m_FileStream.is_open() && m_CurrentFilePath && !std::empty(*m_CurrentFilePath));
441 auto rotationRule = load(m_RotationRule, m_RotationRuleMx);
447 void beforeMessageWrite(
const Record_t& record, std::string_view message)
override
449 if (!m_FileStream.is_open())
453 else if (shallRotate())
std::function< bool(const Record_t &)> Filter_t
Definition: BasicSink.hpp:59
std::function< std::string(const Record_t &)> Formatter_t
Definition: BasicSink.hpp:58
Class for logging into files.
Definition: FileSink.hpp:81
void setOpeningHandler(THandler &&handler) noexcept
Applies a new handler for opening files.
Definition: FileSink.hpp:216
FileSink(FileSink &&)=delete
Deleted move constructor.
void setRotationRule(RotationRule rule) noexcept
Applies a new RotationRule configuration.
Definition: FileSink.hpp:162
void setDirectory(std::filesystem::path directory)
Sets the directory in which the log files will be created.
Definition: FileSink.hpp:258
FileSink(std::string fileNamePattern, std::filesystem::path directory=std::filesystem::current_path())
Constructor.
Definition: FileSink.hpp:116
~FileSink() noexcept
Destructor.
Definition: FileSink.hpp:127
CleanupRule cleanupRule() const noexcept
Returns a copy of the current CleanupRule configuration.
Definition: FileSink.hpp:204
void removeOpeningHandler() noexcept
Removes the active opening handler.
Definition: FileSink.hpp:225
std::remove_cvref_t< TRecord > Record_t
Used Record type.
Definition: ISink.hpp:34
FileSink & operator=(const FileSink &)=delete
Deleted copy assign operator.
void removeClosingHandler() noexcept
Removes the active closing handler.
Definition: FileSink.hpp:247
FileSink(const FileSink &)=delete
Deleted copy constructor.
void setCleanupRule(CleanupRule rule) noexcept
Applies a new CleanupRule configuration.
Definition: FileSink.hpp:194
void setFileNamePattern(std::string fileNamePattern)
Sets the file name pattern for generated log files.
Definition: FileSink.hpp:283
std::string fileNamePattern() const noexcept
Getter of the used file name pattern string.
Definition: FileSink.hpp:304
std::filesystem::path directory() const noexcept
Getter of the directory member.
Definition: FileSink.hpp:270
void setClosingHandler(THandler &&handler) noexcept
Applies a new handler for closing files.
Definition: FileSink.hpp:238
RotationRule rotationRule() const noexcept
Returns a copy of the current RotationRule configuration.
Definition: FileSink.hpp:172
void rotate()
Rotates the current file.
Definition: FileSink.hpp:181
Sink interface class.
Definition: ISink.hpp:29
An std::ostream orientated Sink class which extends BasicSink.
Definition: OStreamSink.hpp:35
std::unique_ptr< detail::AbstractFlushPolicyWrapper< Record_t > > FlushPolicy_t
Definition: OStreamSink.hpp:42
void writeToStream(TData &&data)
Writes directly to the internal stream.
Definition: OStreamSink.hpp:129
std::remove_cvref_t< TRecord > Record_t
Used Record type.
Definition: ISink.hpp:34
Definition: ISink.hpp:183
Helper class for generating patterned strings.
Definition: StringPattern.hpp:120
void setPatternString(std::string patternString)
Sets the pattern string.
Definition: StringPattern.hpp:172
std::string_view patternString() const noexcept
Getter of the used pattern string.
Definition: StringPattern.hpp:163
std::string next()
Creates a new string.
Definition: StringPattern.hpp:142
concept FileStateHandler
Concept for invokable file state handler objects.
Definition: FileSink.hpp:31
Definition: BasicSink.hpp:22
Type for configuring FileSink cleanup rules.
Definition: FileSink.hpp:103
std::optional< std::size_t > fileCount
Definition: FileSink.hpp:105
std::optional< std::size_t > directorySize
Definition: FileSink.hpp:104
Type for configuring FileSink rotation rules.
Definition: FileSink.hpp:94
std::optional< std::chrono::seconds > duration
Definition: FileSink.hpp:96
std::optional< std::size_t > fileSize
Definition: FileSink.hpp:95