-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLogging_file.h
126 lines (112 loc) · 3.88 KB
/
Logging_file.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#pragma once
#include "Logging_console.h"
#include <fstream>
#include <string>
#include <filesystem>
namespace logging {
class FileNameGenerator {
public:
static constexpr int FILE_NAME_LENGTH = 8;
FileNameGenerator(const std::filesystem::path& filePath);
std::string stem() const { return _fileNameStem; }
bool isNewDay(Logger& logger) const { return _fileDayNo != logger.log_date.dayNo; }
int dayNo() const { return _fileDayNo; }
std::string operator()(Logger& logger);
private:
std::string _fileNameStem;
std::filesystem::path _filePath;
unsigned char _fileDayNo = 0;
};
/// <summary>
/// Logs to file, and mirrors to the provided ostream - typcally clog
/// New Filenames are generated for each day
/// </summary>
template<typename MirrorBase = Console_Logger>
class File_Logger : public MirrorBase {
public:
File_Logger(const std::filesystem::path& filePath) : File_Logger{ filePath, L_null } {}
File_Logger(const std::filesystem::path& filePath, Flags initFlags, Streamable& mirrorStream = std::clog);
File_Logger(const std::filesystem::path& filePath, Flags initFlags, Logger& mirror_chain) : File_Logger{ filePath, initFlags } { _mirror = &mirror_chain; }
Streamable& stream() override;
void flush() override;
Logger* mirror_stream(Logger::ostreamPtr& mirrorStream) override;
bool open() override;
private:
Logger& logTime() override;
FileNameGenerator _fileNameGenerator;
Logger* _mirror = this;
std::ofstream _dataFile;
};
template<typename MirrorBase>
File_Logger<MirrorBase>::File_Logger(const std::filesystem::path& filePath, Flags initFlags, Streamable& mirrorStream)
: MirrorBase{ initFlags, mirrorStream }
, _fileNameGenerator{ filePath }
{
MirrorBase::stream() << "\nFile_Logger: " << _fileNameGenerator.stem() << std::endl;
}
template<typename MirrorBase>
Streamable& File_Logger<MirrorBase>::stream() {
if (MirrorBase::is_cout() || !open()) {
Logger::ostreamPtr streamPtr = &_dataFile;
mirror_stream(streamPtr);
return *streamPtr;
} else return _dataFile;
}
template<typename MirrorBase>
bool File_Logger<MirrorBase>::open() {
if (_fileNameGenerator.isNewDay(*this)) _dataFile.close();
if (!_dataFile.is_open()) {
_dataFile.open(_fileNameGenerator(*this), std::ios::app); // Append
}
return _dataFile.good();
}
template<typename MirrorBase>
Logger& File_Logger<MirrorBase>::logTime() {
auto streamPtr = &stream();
Logger* logger = mirror_stream(streamPtr);
while (streamPtr) {
*streamPtr << _fileNameGenerator.stem() << " ";
logger = logger->mirror_stream(streamPtr);
}
MirrorBase::logTime();
return *this;
}
template<typename MirrorBase>
void File_Logger<MirrorBase>::flush() {
auto streamPtr = &stream();
Logger* logger = mirror_stream(streamPtr);
while (streamPtr && logger != this) {
logger->flush();
logger = logger->mirror_stream(streamPtr);
}
MirrorBase::flush();
_dataFile.flush();
}
template<typename MirrorBase>
Logger* File_Logger<MirrorBase>::mirror_stream(Logger::ostreamPtr& mirrorStream) {
bool isChainedMirror = this != _mirror;
if (isChainedMirror) {
mirrorStream = &_mirror->stream();
return _mirror;
} else {
return MirrorBase::mirror_stream(mirrorStream);
}
}
inline
FileNameGenerator::FileNameGenerator(const std::filesystem::path& filePath) :
_filePath{ filePath }
{
_fileNameStem = _filePath.filename().string();
_fileNameStem.resize(FILE_NAME_LENGTH - 4);
if (!_filePath.has_extension()) _filePath += ".txt";
}
inline
std::string FileNameGenerator::operator()(Logger & logger) {
if (logger.log_date.dayNo == 0) logger.getTime();
_fileDayNo = logger.log_date.dayNo;
auto fileName = std::stringstream{};
fileName << _fileNameStem << std::setfill('0') << std::setw(2) << (int)logger.log_date.monthNo << std::setw(2) << (int)_fileDayNo;
_filePath.replace_filename(fileName.str()) += _filePath.extension();
return _filePath.string();
}
}