tsLogger
A C++17 data logger for timeseries and snapshot data
Loading...
Searching...
No Matches
tsLogger.cpp
Go to the documentation of this file.
1#include <tsLogger.h>
2#include <iostream>
3#include <cstdio>
4#include <cstring>
5#include <ctime>
6#include <type_traits>
7#include <vector>
8#include <algorithm>
9
10// Template to handle undefined visitor types of variants
11template<class> inline constexpr bool always_false_v = false;
12
13int tsLogger::initLogger()
14{
15 // Allocate buffer memory dynamically
16 logBuffer = (char*) malloc(logBufferSize);
17 preamble.clear();
18 tsHeader.clear();
19 dataVector.clear();
20
21 // Open data file
22 if (fileType == _TSLOGGER_CSV) {
23 fopen_s(&(this->logFilePtr), fileName, "w+");
24 setvbuf(logFilePtr, logBuffer, _IOLBF, logBufferSize);
25 }
26 else {
27 fopen_s(&(this->logFilePtr), fileName, "wb+");
28 }
29
30 // Set internal parameters of the logger object
31 numHeaderLines = 0;
32 dataVecLen = dataVector.size();
33
34 canAddPreamble = true;
35 canAddDataHeader = true;
36 isLogggingStart = false;
37
38 return 0;
39}
40
42{
43 logUnixTime = time(NULL);
44 tm localTime;
45 localtime_s(&localTime, &logUnixTime);
46
47 snprintf(fileName, fileNameLength, "%s\\%s_%04d-%02d-%02d-%02d%02d%02d.csv",
48 defaultFilePath, /*File directory*/
49 defaultFileName, /*File name prefix*/
50 localTime.tm_year+1900, /*Current year*/
51 localTime.tm_mon+1, /*Current Month*/
52 localTime.tm_mday, /*Current Date*/
53 localTime.tm_hour, /*Current Hour of day (24-hour mode)*/
54 localTime.tm_min, /*Current Minute of day (24-hour mode)*/
55 localTime.tm_sec); /*Current Seconds*/
56 fileType = _TSLOGGER_CSV;
57 logBufferSize = defLogBufferSize;
58
59 initLogger();
60}
61
63{
64 logUnixTime = time(NULL);
65 tm localTime;
66 localtime_s(&localTime, &logUnixTime);
67
68 snprintf(fileName, fileNameLength, "%s\\%s_%04d-%02d-%02d-%02d%02d%02d.csv",
69 defaultFilePath, /*File directory*/
70 defaultFileName, /*File name prefix*/
71 localTime.tm_year+1990, /*Current year*/
72 localTime.tm_mon+1, /*Current Month*/
73 localTime.tm_mday, /*Current Date*/
74 localTime.tm_hour, /*Current Hour of day (24-hour mode)*/
75 localTime.tm_min, /*Current Minute of day (24-hour mode)*/
76 localTime.tm_sec); /*Current Seconds*/
77 fileType = logFileType;
78 logBufferSize = defLogBufferSize;
79
80 initLogger();
81}
82
83tsLogger::tsLogger(const char* logFileName)
84{
85 logUnixTime = time(NULL);
86 snprintf(fileName, fileNameLength, "%s", logFileName);
87 fileType = _TSLOGGER_CSV;
88 logBufferSize = defLogBufferSize;
89
90 initLogger();
91}
92
93tsLogger::tsLogger(const char* logFileName, tsLogFileType logFileType)
94{
95 logUnixTime = time(NULL);
96 snprintf(fileName, fileNameLength, "%s", logFileName);
97 fileType = logFileType;
98 logBufferSize = defLogBufferSize;
99
100 initLogger();
101}
102
103tsLogger::tsLogger(const char* logFileName, tsLogFileType logFileType, size_t logBufferMaxSize)
104{
105 logUnixTime = time(NULL);
106 snprintf(fileName, fileNameLength, "%s", logFileName);
107 fileType = logFileType;
108 logBufferSize = logBufferMaxSize;
109
110 initLogger();
111}
112
113void tsLogger::getFilePath(char* pathDestination, size_t pathDestinationLength)
114{
115 strcpy_s(pathDestination, pathDestinationLength, this->fileName);
116}
117
119{
120 return dataVecLen;
121}
122
123void tsLogger::appendToPreamble(std::string appendString)
124{
125 std::replace(appendString.begin(), appendString.end(), '\n', ' '); // replace all new line characters with spaces.
126 this->preamble.append(appendString);
127 this->preamble.push_back('\n');
128 this->numHeaderLines++;
129}
130
132{
133 // Can add preamble only if this is the first time you are adding it,
134 // and neither the dataHeader has been input nor the logging started.
135 if (canAddPreamble == true && this->canAddDataHeader == true && isLogggingStart == false) {
136 this->numHeaderLines++;
137 fprintf(this->logFilePtr, "%05d,%lld\n%s", this->numHeaderLines, (long long)this->logUnixTime, this->preamble.c_str());
138 canAddPreamble = false;
139 }
140}
141
143{
144 if (this->canAddDataHeader == true && isLogggingStart == false) {
145 if (this->canAddPreamble == false) {
146 fseek(this->logFilePtr, 0, SEEK_SET);
147 this->numHeaderLines++;
148 fprintf(this->logFilePtr, "%05d", this->numHeaderLines);
149 fseek(this->logFilePtr, 0, SEEK_END);
150 }
151 for (auto it = std::begin(this->dataVector); it != std::end(this->dataVector); /*increment is in loop*/) {
152 if (this->fileType == _TSLOGGER_CSV) {
153 fprintf(this->logFilePtr, "%s", it->dataName.c_str());
154 if (++it != this->dataVector.end()) {
155 fprintf(this->logFilePtr, ",");
156 }
157 else {
158 fprintf(this->logFilePtr, "\n");
159 }
160 }
161 }
162 this->canAddDataHeader = false;
163 }
164}
165
167{
168 if (isLogggingStart == false) {
169 isLogggingStart = true;
170 }
171}
172
174{
175 smartDataPtr dataPtr;
176 if (isLogggingStart != false) {
177 this->startLogger();
178 }
179 for (auto it = std::begin(this->dataVector); it != std::end(this->dataVector); /*increment is in loop*/) {
180 if (this->fileType == _TSLOGGER_CSV) {
181
182 // Handle variant types here
183 //--------------------------
184 dataPtr = std::visit([](auto&& arg) -> smartDataPtr {return arg;}, it->dataPtr);
185 std::visit([this](auto&& arg) {
186 using dataPtrType = std::decay_t<decltype(arg)>;
187
188 // data pointer is int*
189 if constexpr (std::is_same_v<dataPtrType, int*>)
190 fprintf(this->logFilePtr, "%d", *arg);
191 // data pointer is unsigned int*
192 else if constexpr (std::is_same_v<dataPtrType, unsigned int*>)
193 fprintf(this->logFilePtr, "%u", *arg);
194 // data pointer is long*
195 else if constexpr (std::is_same_v<dataPtrType, long*>)
196 fprintf(this->logFilePtr, "%ld", *arg);
197 // data pointer is unsigned long*
198 else if constexpr (std::is_same_v<dataPtrType, unsigned long*>)
199 fprintf(this->logFilePtr, "%lu", *arg);
200 // data pointer is long long*
201 else if constexpr (std::is_same_v<dataPtrType, long long*>)
202 fprintf(this->logFilePtr, "%lld", *arg);
203 // data pointer is unsigned long long*
204 else if constexpr (std::is_same_v<dataPtrType, unsigned long long*>)
205 fprintf(this->logFilePtr, "%llu", *arg);
206 // data pointer is float*
207 else if constexpr (std::is_same_v<dataPtrType, float*>)
208 fprintf(this->logFilePtr, "%f", *arg);
209 // data pointer is double*
210 else if constexpr (std::is_same_v<dataPtrType, double*>)
211 fprintf(this->logFilePtr, "%f", *arg);
212 // data pointer is char*
213 else if constexpr (std::is_same_v<dataPtrType, char*>)
214 fprintf(this->logFilePtr, "%c", *arg);
215 // data pointer is unsigned char*
216 else if constexpr (std::is_same_v<dataPtrType, unsigned char*>)
217 fprintf(this->logFilePtr, "%hhu", *arg);
218 // data pointer is bool*
219 else if constexpr (std::is_same_v<dataPtrType, bool*>)
220 fprintf(this->logFilePtr, "%d", *arg);
221 // handle unsupported variant visitor types of data pointer
222 else
223 static_assert(always_false_v<dataPtrType>, "tsLogger: FATAL ERROR: attempting to log unsupported data type!");
224 }, dataPtr);
225
226 if (++it != this->dataVector.end()) {
227 fprintf(this->logFilePtr, ",");
228 }
229 else {
230 fprintf(this->logFilePtr, "\n");
231 }
232 }
233 }
234}
235
237{
238 // Flush buffer and close file
239 fflush(logFilePtr);
240 fclose(logFilePtr);
241
242 // Free all dynamic memory allocated to logger object
243 free(logBuffer);
244 dataVector.clear();
245
246 numHeaderLines = 0;
247 dataVecLen = 0;
248 isLogggingStart = false;
249}
void appendToPreamble(std::string appendString)
Appends a line of text to the preamble block of the log file. Replaces new line characters with space...
Definition: tsLogger.cpp:123
void startLogger()
Starts the logger and locks out the ability to add preambles, headers and new data points.
Definition: tsLogger.cpp:166
void getFilePath(char *pathDestination, size_t pathDestinationLength)
Allows the user to read the file path of the log file.
Definition: tsLogger.cpp:113
size_t getNumDataPoints()
Returns the total number of data points being tracked for logging by the tsLogger class object.
Definition: tsLogger.cpp:118
void addDataHeader()
Add the data header (consisting of datapoint names separated by commas) to the header file....
Definition: tsLogger.cpp:142
void addPreamble()
Adds the preamble to the log file-can only be added once and only be called before the addDataHeader ...
Definition: tsLogger.cpp:131
void logData()
Logs the data points being tracked as a line in the log file.
Definition: tsLogger.cpp:173
tsLogger()
Default constructor of the tsLogger class. Uses default values to initialize all object properties.
Definition: tsLogger.cpp:41
constexpr bool always_false_v
Definition: tsLogger.cpp:11
@ _TSLOGGER_CSV
Definition: tsLogger.h:25
std::variant< int *, unsigned int *, long *, unsigned long *, long long *, unsigned long long *, float *, double *, char *, unsigned char *, bool * > smartDataPtr
This varriant datatype governs the supported data points that can be tracked.
Definition: tsLogger.h:37
#define defaultFileName
Definition: tsLogger.h:13
#define fileNameLength
Definition: tsLogger.h:15
enum _tsLogFileType tsLogFileType
The file-types supported by tsLogger. [BINARY support coming in the future].
#define defaultFilePath
Definition: tsLogger.h:12
#define defLogBufferSize
Definition: tsLogger.h:16