API
 
Loading...
Searching...
No Matches
logFileRaw.hpp
Go to the documentation of this file.
1/** \file logFileRaw.hpp
2 * \brief Manage a raw log file.
3 * \ingroup logger_files
4 */
5
6#ifndef logger_logFileRaw_hpp
7#define logger_logFileRaw_hpp
8
9#include <iostream>
10
11#include <mx/ioutils/fileUtils.hpp>
12#include <mx/ioutils/stringUtils.hpp>
13
14#include <flatlogs/flatlogs.hpp>
15
16#include "../file/fileTimes.hpp"
17
18namespace MagAOX
19{
20namespace logger
21{
22
23/// A class to manage raw binary log files
24/** Manages a binary file containing MagAO-X logs.
25 *
26 * The log entries are written as a binary stream of a configurable
27 * maximum size. If this size will be exceed by the next entry, then a new file is created.
28 *
29 * Filenames have a standard form of: `[path]/[name]/[name]_YYYYMMDDHHMMSSNNNNNNNNN.[ext]` where fields in [] are
30 * configurable.
31 *
32 * The timestamp in the file name is from the first entry of the file.
33 *
34 */
35template <class verboseT = XWC_DEFAULT_VERBOSITY>
37{
38
39 protected:
40 /** \name Configurable Parameters
41 *@{
42 */
43 std::string m_logPath{ "." }; ///< The base path for the log files.
44 std::string m_logName{ "xlog" }; ///< The base name for the log files.
45 std::string m_logExt{ MAGAOX_default_logExt }; ///< The extension for the log files.
46
47 size_t m_maxLogSize{ MAGAOX_default_max_logSize }; ///< The maximum file size in bytes. Default is 10 MB.
48 ///@}
49
50 /** \name Internal State
51 *@{
52 */
53
54 FILE *m_fout{ 0 }; ///< The file pointer
55
56 size_t m_currFileSize{ 0 }; ///< The current file size.
57
58 ///@}
59
60 public:
61 /// Default constructor
62 /** Currently does nothing.
63 */
65
66 /// Destructor
67 /** Closes the file if open
68 */
70
71 /// Set the path.
72 /**
73 *
74 * \returns 0 on success
75 * \returns -1 on error
76 */
77 mx::error_t logPath( const std::string &newPath /**< [in] the new value of _path */ );
78
79 /// Get the path.
80 /**
81 * \returns the current value of m_logPath.
82 */
83 std::string logPath();
84
85 /// Set the log name
86 /**
87 *
88 * \returns 0 on success
89 * \returns -1 on error
90 */
91 mx::error_t logName( const std::string &newName /**< [in] the new value of m_logName */ );
92
93 /// Get the name
94 /**
95 * \returns the current value of _name.
96 */
97 std::string logName();
98
99 /// Set the log extension
100 /**
101 *
102 * \returns 0 on success
103 * \returns -1 on error
104 */
105 mx::error_t logExt( const std::string &newExt /**< [in] the new value of m_logExt */ );
106
107 /// Get the log extension
108 /**
109 * \returns the current value of m_logExt.
110 */
111 std::string logExt();
112
113 /// Set the maximum file size
114 /**
115 *
116 * \returns 0 on success
117 * \returns -1 on error
118 */
119 mx::error_t maxLogSize( size_t newMaxFileSize /**< [in] the new value of _maxLogSize */ );
120
121 /// Get the maximum file size
122 /**
123 * \returns the current value of m_maxLogSize
124 */
125 size_t maxLogSize();
126
127 /// Write a log entry to the file
128 /** Checks if this write will exceed m_maxLogSize, and if so opens a new file.
129 * The new file will have the timestamp of this log entry.
130 *
131 * \returns 0 on success
132 * \returns -1 on error
133 */
134 mx::error_t writeLog( flatlogs::bufferPtrT &data /**< [in] the log entry to write to disk */ );
135
136 /// Flush the stream
137 /** Calls `fflush`. See issue #192
138 *
139 * \returns 0 on success
140 * \returns -1 on error
141 */
142 mx::error_t flush();
143
144 /// Close the file pointer
145 /** Sets \ref m_fout to nullptr after calling fclose regardless of error.
146 *
147 * \returns 0 on success
148 * \returns -1 on error
149 */
150 mx::error_t close();
151
152 protected:
153 /// Create a new file
154 /** Closes the current file if open. Then creates a new file with a name of the form
155 * [path]/[name]/YYYY_MM_DD/[name]_YYYYMMDDHHMMSSNNNNNNNNN.[ext]
156 *
157 *
158 * \returns 0 on success
159 * \returns -1 on error
160 */
161 mx::error_t createFile( flatlogs::timespecX &ts /**< [in] A MagAOX timespec, used to set the timestamp */ );
162};
163
164template <class verboseT>
168
169template <class verboseT>
171{
172 close();
173}
174
175template <class verboseT>
176mx::error_t logFileRaw<verboseT>::logPath( const std::string &newPath )
177{
178 try
179 {
180 m_logPath = newPath;
181 }
182 catch( const std::bad_alloc &e )
183 {
184 std::throw_with_nested( xwcException( "string assignment" ) );
185 }
186 catch( const std::exception &e )
187 {
188 return mx::error_report( mx::error_t::std_exception, std::string( "string assignment: " ) + e.what() );
189 }
190
191 return mx::error_t::noerror;
192}
193
194template <class verboseT>
196{
197 return m_logPath;
198}
199
200template <class verboseT>
201mx::error_t logFileRaw<verboseT>::logName( const std::string &newName )
202{
203 try
204 {
205 m_logName = newName;
206 }
207 catch( const std::bad_alloc &e )
208 {
209 std::throw_with_nested( xwcException( "string assignment" ) );
210 }
211 catch( const std::exception &e )
212 {
213 return mx::error_report( mx::error_t::std_exception, std::string( "string assignment: " ) + e.what() );
214 }
215
216 return mx::error_t::noerror;
217}
218
219template <class verboseT>
221{
222 return m_logName;
223}
224
225template <class verboseT>
226mx::error_t logFileRaw<verboseT>::logExt( const std::string &newExt )
227{
228 try
229 {
230 m_logExt = newExt;
231 }
232 catch( const std::bad_alloc &e )
233 {
234 std::throw_with_nested( xwcException( "string assignment" ) );
235 }
236 catch( const std::exception &e )
237 {
238 return mx::error_report( mx::error_t::std_exception, std::string( "string assignment: " ) + e.what() );
239 }
240
241 return mx::error_t::noerror;
242}
243
244template <class verboseT>
246{
247 return m_logExt;
248}
249
250template <class verboseT>
251mx::error_t logFileRaw<verboseT>::maxLogSize( size_t newMaxFileSize )
252{
253 try
254 {
255 m_maxLogSize = newMaxFileSize;
256 }
257 catch( const std::bad_alloc &e )
258 {
259 std::throw_with_nested( xwcException( "string assignment" ) );
260 }
261 catch( const std::exception &e )
262 {
263 return mx::error_report( mx::error_t::std_exception, std::string( "string assignment: " ) + e.what() );
264 }
265
266 return mx::error_t::noerror;
267}
268
269template <class verboseT>
271{
272 return m_maxLogSize;
273}
274
275template <class verboseT>
277{
278 size_t N = flatlogs::logHeader::totalSize( data );
279
280 // Check if we need a new file
281 if( m_currFileSize + N > m_maxLogSize || m_fout == 0 )
282 {
284
285 mx_error_check( createFile( ts ) );
286 }
287
288 size_t nwr = fwrite( data.get(), sizeof( char ), N, m_fout );
289
290 if( nwr != N * sizeof( char ) )
291 {
292 return mx::error_report<verboseT>( mx::errno2error_t( errno ), "Error from fwrite" );
293 }
294
295 m_currFileSize += N;
296
297 return mx::error_t::noerror;
298}
299
300template <class verboseT>
302{
303 ///\todo this probably should be fsync, with appropriate error handling (see fsyncgate) [issue #192]
304
305 if( m_fout )
306 {
307 if( fflush( m_fout ) != 0 )
308 {
309 return mx::error_report<verboseT>( mx::errno2error_t( errno ), "Error from fflush" );
310 }
311 }
312 return mx::error_t::noerror;
313}
314
315template <class verboseT>
317{
318 if( m_fout )
319 {
320 errno = 0;
321
322 if( fclose( m_fout ) != 0 )
323 {
324 m_fout = nullptr;
325
326 return mx::error_report<verboseT>( mx::errno2error_t( errno ), "Error from fflush" );
327 }
328
329 m_fout = nullptr;
330 }
331
332 return mx::error_t::noerror;
333}
334
335template <class verboseT>
337{
338 std::string fileName;
339 std::string relPath;
340
341 try
342 {
343 mx::error_t errc = file::fileTimeRelPath( fileName, relPath, m_logName, m_logExt, ts.time_s, ts.time_ns );
344
345 if( !!errc )
346 {
347 return mx::error_report<verboseT>( errc );
348 }
349 }
350 catch( ... )
351 {
352 std::throw_with_nested( mx::exception<verboseT>(mx::error_t::exception));
353 }
354
355 std::string fullPath = m_logPath + '/' + relPath + '/';
356
357 // Create directory
358 mx::error_t errc = mx::ioutils::createDirectories( fullPath );
359
360 if( !!errc )
361 {
362 return mx::error_report<verboseT>( errc, "creating directory" );
363 }
364
365 fullPath += fileName;
366
367 if( mx::ioutils::exists( fullPath, errc ) )
368 {
369 return mx::error_report<verboseT>( mx::error_t::eexist, "file " + fullPath + " exists" );
370 }
371
372 if( !!errc )
373 {
374 return mx::error_report<verboseT>( errc, "checking directory" );
375 }
376
377 // Close current file if it's open
378 errc = close();
379 if( errc != mx::error_t::noerror )
380 {
381 mx::error_report<verboseT>( errc, "Error from close, attempting to continue");
382 }
383
384 errno = 0;
385
386 m_fout = fopen( fullPath.c_str(), "wb" );
387
388 if( m_fout == 0 )
389 {
390 return mx::error_report<verboseT>( mx::errno2error_t( errno ), "Error from fopen on " + fullPath );
391 }
392
393 // Reset counters.
394 m_currFileSize = 0;
395
396 return mx::error_t::noerror;
397}
398
399extern template class logFileRaw<XWC_DEFAULT_VERBOSITY>;
400
401} // namespace logger
402} // namespace MagAOX
403
404#endif // logger_logFileRaw_hpp
A class to manage raw binary log files.
logFileRaw()
Default constructor.
size_t maxLogSize()
Get the maximum file size.
FILE * m_fout
The file pointer.
mx::error_t logExt(const std::string &newExt)
Set the log extension.
mx::error_t writeLog(flatlogs::bufferPtrT &data)
Write a log entry to the file.
std::string logName()
Get the name.
mx::error_t logPath(const std::string &newPath)
Set the path.
std::string logPath()
Get the path.
mx::error_t maxLogSize(size_t newMaxFileSize)
Set the maximum file size.
mx::error_t flush()
Flush the stream.
mx::error_t logName(const std::string &newName)
Set the log name.
std::string m_logName
The base name for the log files.
std::string m_logPath
The base path for the log files.
mx::error_t close()
Close the file pointer.
size_t m_maxLogSize
The maximum file size in bytes. Default is 10 MB.
mx::error_t createFile(flatlogs::timespecX &ts)
Create a new file.
std::string logExt()
Get the log extension.
std::string m_logExt
The extension for the log files.
size_t m_currFileSize
The current file size.
Augments an exception with the source file and line.
Flatlogs single include file.
#define MAGAOX_default_logExt
The extension for MagAO-X binary log files.
Definition defaults.hpp:22
#define MAGAOX_default_max_logSize
The default maximum log file size.
Definition defaults.hpp:40
static size_t totalSize(bufferPtrT &logBuffer)
Get the total size of the log entry, including the message buffer.
std::shared_ptr< char > bufferPtrT
The log entry buffer smart pointer.
Definition logHeader.hpp:58
static int timespec(bufferPtrT &logBuffer, const timespecX &ts)
Set the timespec of a log entry.
mx::error_t fileTimeRelPath(std::string &tstamp, std::string &relPath, time_t ts_sec, long ts_nsec)
Get the timestamp and the relative path based on a time.
Definition dm.hpp:28
A fixed-width timespec structure.
Definition timespecX.hpp:35
nanosecT time_ns
Nanoseconds.
Definition timespecX.hpp:37
secT time_s
Time since the Unix epoch.
Definition timespecX.hpp:36