API
logMap.cpp
Go to the documentation of this file.
1 /** \file logMap.cpp
2  * \brief Declares and defines the logMap class and related classes.
3  * \author Jared R. Males (jaredmales@gmail.com)
4  *
5  * \ingroup logger_files
6  *
7  */
8 
9 #include "logMap.hpp"
10 
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14 
15 using namespace flatlogs;
16 
17 namespace MagAOX
18 {
19 namespace logger
20 {
21 
22 int logInMemory::loadFile( logFileName const& lfn)
23 {
24  int fd = open(lfn.fullName().c_str(), O_RDONLY );
25 
26  off_t fsz = mx::ioutils::fileSize(fd);
27 
28  std::vector<char> memory(fsz);
29 
30  ssize_t nrd = read(fd, memory.data(), memory.size());
31 
32  close(fd);
33 
34  if(nrd != fsz)
35  {
36  std::cerr << __FILE__ << " " << __LINE__ << " logInMemory::loadFile(" << lfn.fullName() << ") did not read all bytes\n";
37  return -1;
38  }
39 
40  flatlogs::timespecX startTime = logHeader::timespec(memory.data());
41 
42  size_t st=0;
43  size_t ed = logHeader::totalSize(memory.data());
44  st = ed;
45 
46  while(st < memory.size())
47  {
48  ed = logHeader::totalSize(memory.data()+st);
49  st = st + ed;
50  }
51 
52  if(st != memory.size())
53  {
54  std::cerr << __FILE__ << " " << __LINE__ << " Possibly corrupt logfile.\n";
55  return -1;
56  }
57 
58  st -= ed;
59 
60  flatlogs::timespecX endTime = logHeader::timespec(memory.data()+st);
61 
62  if(m_memory.size() == 0)
63  {
64  m_memory.swap(memory);
65  m_startTime = startTime;
66  m_endTime = endTime;
67 
68  std::string timestamp;
69  timespec ts{ endTime.time_s, endTime.time_ns};
70  mx::sys::timeStamp(timestamp, ts);
71 
72  #ifdef DEBUG
73  std::cerr << __FILE__ << " " << __LINE__ << " loading: " << lfn.fullName() << " " << timestamp << "\n";
74  #endif
75 
76  return 0;
77  }
78 
79  if(startTime < m_startTime)
80  {
81 
82  if(endTime >= m_startTime)
83  {
84  std::cerr << __FILE__ << " " << __LINE__ << " overlapping log files!\n";
85  return -1;
86  }
87 
88  m_memory.insert(m_memory.begin(), memory.begin(), memory.end());
89  m_startTime = startTime;
90  std::cerr << __FILE__ << " " << __LINE__ << " added before!\n";
91  return 0;
92  }
93 
94  if(startTime > m_endTime)
95  {
96  #ifdef DEBUG
97  std::cerr << __FILE__ << " " << __LINE__ << " gonna append\n";
98  #endif
99 
100  m_memory.insert(m_memory.end(), memory.begin(), memory.end());
101  m_endTime = endTime;
102 
103  #ifdef DEBUG
104  std::cerr << __FILE__ << " " << __LINE__ << " added after!\n";
105  #endif
106 
107  return 0;
108  }
109 
110  std::cerr << __FILE__ << " " << __LINE__ << " Need to implement insert in the middle!\n";
111  std::cerr << m_startTime.time_s << " " << m_startTime.time_ns << "\n";
112  std::cerr << startTime.time_s << " " << startTime.time_ns << "\n";
113 
114  return -1;
115 }
116 
117 int logMap::loadAppToFileMap( const std::string & dir,
118  const std::string & ext
119  )
120 {
121  std::vector<std::string> flist = mx::ioutils::getFileNames(dir, "", "", ext);
122 
123  for(size_t n=0;n<flist.size(); ++n)
124  {
125  //std::cerr << "loading: " << flist[n] << "\n";
126 
127  logFileName lfn(flist[n]);
128 
129  m_appToFileMap[lfn.appName()].insert(lfn);
130  }
131 
132  return 0;
133 }
134 
135 int logMap::getPriorLog( char * &logBefore,
136  const std::string & appName,
137  const flatlogs::eventCodeT & ev,
138  const flatlogs::timespecX & ts,
139  char * hint
140  )
141 {
143 
144  #ifdef DEBUG
145  std::cerr << __FILE__ << " " << __LINE__ << "\n";
146  #endif
147 
148  if(m_appToFileMap[appName].size() == 0)
149  {
150  std::cerr << __FILE__ << " " << __LINE__ << " getPriorLog empty map\n";
151  return -1;
152  }
153 
154  #ifdef DEBUG
155  std::cerr << __FILE__ << " " << __LINE__ << "\n";
156  #endif
157 
158  logInMemory & lim = m_appToBufferMap[appName];
159 
161  et.time_s += 30;
162  if(lim.m_startTime > ts || et < ts)
163  {
164  #ifdef DEBUG
165  std::cerr << __FILE__ << " " << __LINE__ << "\n";
166  #endif
167 
168  if(loadFiles(appName, ts) < 0)
169  {
170  std::cerr << __FILE__ << " " << __LINE__ << " error returned from loadfiles\n";
171  return -1;
172  }
173  }
174 
175  char* buffer, *priorBuffer;
176 
177  if(hint)
178  {
179  if(logHeader::timespec(hint) <= ts) buffer = hint;
180  else buffer = lim.m_memory.data();
181  }
182 
183  else buffer = lim.m_memory.data();
184 
185  priorBuffer = buffer;
186  evL = logHeader::eventCode(buffer);
187 
188  while(evL != ev)
189  {
190  priorBuffer = buffer;
191  buffer += logHeader::totalSize(buffer);
192  if(buffer >=lim.m_memory.data() + lim.m_memory.size()) break;
193  evL = logHeader::eventCode(buffer);
194  }
195 
196  if(evL != ev)
197  {
198  std::cerr << __FILE__ << " " << __LINE__ << " Event code not found.\n";
199  return -1;
200  }
201 
202  if( logHeader::timespec(buffer) < ts )
203  {
204  while( logHeader::timespec(buffer) < ts ) //Loop until buffer is after the timestamp we want
205  {
206  if(buffer >lim.m_memory.data() +lim.m_memory.size())
207  {
208  std::cerr << __FILE__ << " " << __LINE__ << " attempt to read too mach data, possible log corruption.\n";
209  return -1;
210  }
211 
212  if(buffer ==lim.m_memory.data() +lim.m_memory.size())
213  {
214  std::cerr << __FILE__ << " " << __LINE__ << " did not find following log for " << appName << " -- need to load more data.\n";
215  //Proper action here is to load the next file if possible...
216  return 1;
217  }
218 
219  priorBuffer = buffer;
220 
221  buffer += logHeader::totalSize(buffer);
222 
223  evL = logHeader::eventCode(buffer);
224 
225  while(evL != ev) //Find the next log with the event code we want.
226  {
227  if(buffer >lim.m_memory.data() + lim.m_memory.size())
228  {
229  std::cerr << __FILE__ << " " << __LINE__ << " attempt to read too mach data, possible log corruption.\n";
230  return -1;
231  }
232 
233  if(buffer ==lim.m_memory.data() + lim.m_memory.size())
234  {
235  std::cerr << __FILE__ << " " << __LINE__ << " did not find following log for " << appName << " -- need to load more data.\n";
236  //Proper action here is to load the next file if possible...
237  return 1;
238  }
239 
240  buffer += logHeader::totalSize(buffer);
241  evL = logHeader::eventCode(buffer);
242  }
243  }
244 
245  }
246 
247  logBefore = priorBuffer;
248 
249  return 0;
250 }//getPriorLog
251 
252 int logMap::getNextLog( char * &logAfter,
253  char * logCurrent,
254  const std::string & appName
255  )
256 {
257  flatlogs::eventCodeT ev, evL;
258 
259  logInMemory & lim = m_appToBufferMap[appName];
260 
261  char* buffer;
262 
263  ev = logHeader::eventCode(logCurrent);
264 
265  buffer = logCurrent;
266 
267  buffer += logHeader::totalSize(buffer);
268  if(buffer >= lim.m_memory.data() + lim.m_memory.size())
269  {
270  std::cerr << __FILE__ << " " << __LINE__ << " Reached end of data for " << appName << " -- need to load more data\n";
271  //propoer action is to load the next file if possible.
272  return 1;
273  }
274 
275  evL = logHeader::eventCode(buffer);
276 
277  while(evL != ev)
278  {
279  buffer += logHeader::totalSize(buffer);
280  if(buffer >= lim.m_memory.data() + lim.m_memory.size())
281  {
282  std::cerr << __FILE__ << " " << __LINE__ << " Reached end of data for " << appName << "-- need to load more data\n";
283  //propoer action is to load the next file if possible.
284  return 1;
285  }
286  evL = logHeader::eventCode(buffer);
287  }
288 
289  if(evL != ev)
290  {
291  std::cerr << "Event code not found.\n";
292  return -1;
293  }
294 
295  logAfter = buffer;
296 
297  return 0;
298 }
299 
300 int logMap::loadFiles( const std::string & appName,
301  const flatlogs::timespecX & startTime
302  )
303 {
304  if(m_appToFileMap[appName].size() == 0)
305  {
306  std::cerr << "*************************************\n\n";
307  std::cerr << "No files for " << appName << "\n";
308  std::cerr << "*************************************\n\n";
309  return -1;
310  }
311 
312  #ifdef DEBUG
313  std::cerr << __FILE__ << " " << __LINE__ << "\n";
314  #endif
315 
316  //First check if already loaded files cover this time
317  if(m_appToBufferMap[appName].m_memory.size() > 0)
318  {
319  if( m_appToBufferMap[appName].m_startTime <= startTime && m_appToBufferMap[appName].m_endTime >= startTime)
320  {
321  std::cerr << "good!\n";
322  return 0;
323  }
324 
325  #ifdef DEBUG
326  std::cerr << __FILE__ << " " << __LINE__ << "\n";
327  #endif
328 
329  if( m_appToBufferMap[appName].m_startTime > startTime ) // Files don't go back far enough
330  {
331  #ifdef DEBUG
332  std::cerr << __FILE__ << " " << __LINE__ << "\n";
333  #endif
334 
335  auto last = m_appToFileMap[appName].begin();
336  while( last->timestamp() < m_appToBufferMap[appName].m_startTime)
337  {
338  ++last;
339  if(last == m_appToFileMap[appName].end()) break;
340  }
341  //Now last is the last file to open in the for loop sense.
342  auto first = last;
343 
344  while( first->timestamp() > startTime)
345  {
346  --first;
347  if(first == m_appToFileMap[appName].begin()) break;
348  }
349 
350  //Now open each of these files, in reverse
351  std::cerr << "open earlier files!\n";
352  --last;
353  --first;
354  for(auto it=last; it != first; --it)
355  {
356  m_appToBufferMap[appName].loadFile(*it);
357  }
358 
359  return 0;
360  }
361  else
362  {
363  auto first = m_appToFileMap[appName].end();
364  --first;
365 
366  while( first->timestamp() > m_appToBufferMap[appName].m_endTime)
367  {
368  --first;
369  if(first == m_appToFileMap[appName].begin()) break;
370  }
371  ++first;
372  auto last = first;
373  while( last->timestamp() < startTime)
374  {
375  ++last;
376  if(last == m_appToFileMap[appName].end()) break;
377  }
378 
379  //Now open each of these files
380  std::cerr << "open later file for " << appName << "!\n";
381  for(auto it=first; it != last; ++it)
382  {
383  m_appToBufferMap[appName].loadFile(*it);
384  }
385  return 0;
386  }
387 
388  }
389 
390  #ifdef DEBUG
391  std::cerr << __FILE__ << " " << __LINE__ << "\n";
392  #endif
393 
394  auto before = m_appToFileMap[appName].begin();
395 
396  for(; before != m_appToFileMap[appName].end(); ++before)
397  {
398  if( !(before->timestamp() < startTime) )
399  {
400  break;
401  }
402  }
403 
404  #ifdef debug
405  std::cerr << __FILE__ << " " << __LINE__ << "\n";
406  #endif
407 
408  if(before == m_appToFileMap[appName].begin())
409  {
410  std::cerr << "No files in range for " << appName << "\n";
411  }
412  --before;
413 
414  #ifdef DEBUG
415  std::cerr << __FILE__ << " " << __LINE__ << "\n";
416  #endif
417 
418  m_appToBufferMap.emplace(std::pair<std::string, logInMemory>(appName, logInMemory()));
419 
420  #ifdef DEBUG
421  std::cerr << __FILE__ << " " << __LINE__ << "\n";
422  #endif
423 
424  m_appToBufferMap[appName].loadFile(*before);
425  if(++before != m_appToFileMap[appName].end())
426  {
427  m_appToBufferMap[appName].loadFile(*before);
428  }
429 
430  #ifdef DEBUG
431  std::cerr << __FILE__ << " " << __LINE__ << "\n";
432  #endif
433 
434  return 0;
435 }
436 
437 } //namespace logger
438 } //namespace MagAOX
Organize and analyze the name of a log or telemetry file.
Definition: logFileName.hpp:29
int fullName(const std::string &fullName)
Sets the full name.
Definition: logFileName.cpp:26
std::string appName() const
Get the current value of m_appName.
Definition: logFileName.cpp:49
uint16_t eventCodeT
The type of an event code (16-bit unsigned int).
Definition: logDefs.hpp:40
static int eventCode(bufferPtrT &logBuffer, const eventCodeT &ec)
Set the event code of a log entry.
Definition: logHeader.hpp:412
static size_t totalSize(bufferPtrT &logBuffer)
Get the total size of the log entry, including the message buffer.
Definition: logHeader.hpp:602
static int timespec(bufferPtrT &logBuffer, const timespecX &ts)
Set the timespec of a log entry.
Definition: logHeader.hpp:435
Declares and defines the logMap class and related classes.
std::ostream & cerr()
Definition: dm.hpp:24
Structure to hold a log file in memory, tracking when a new file needs to be opened.
Definition: logMap.hpp:32
flatlogs::timespecX m_startTime
Definition: logMap.hpp:35
std::vector< char > m_memory
The buffer holding the log.
Definition: logMap.hpp:33
flatlogs::timespecX m_endTime
Definition: logMap.hpp:36
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