JeVois  1.0
JeVois Smart Embedded Machine Vision Toolkit
Log.C
Go to the documentation of this file.
1 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2016 by Laurent Itti, the University of Southern
4 // California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5 //
6 // This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7 // redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8 // Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10 // License for more details. You should have received a copy of the GNU General Public License along with this program;
11 // if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12 //
13 // Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14 // Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16 /*! \file */
17 
18 #include <jevois/Debug/Log.H>
19 #include <mutex>
20 #include <iostream>
21 #include <fstream>
22 #include <stdexcept>
23 
24 namespace jevois
25 {
26  int logLevel = LOG_INFO;
27  int traceLevel = 0;
28 }
29 
30 namespace
31 {
32  template <int Level> char const * levelStr();
33  template <> char const * levelStr<LOG_DEBUG>() { return "DBG"; }
34  template <> char const * levelStr<LOG_INFO>() { return "INF"; }
35  template <> char const * levelStr<LOG_ERR>() { return "ERR"; }
36  template <> char const * levelStr<LOG_CRIT>() { return "FTL"; }
37 }
38 
39 #ifdef JEVOIS_USE_SYNC_LOG
40 namespace jevois
41 {
42  // Mutex used to avoid clashing synchronous outputs from multiple threads
43  std::mutex logOutputMutex;
44 }
45 
46 void jevois::logSetEngine(Engine * e)
47 { LFATAL("Cannot set Engine for logs when JeVois has been compiled with -D JEVOIS_USE_SYNC_LOG"); }
48 
49 #else // JEVOIS_USE_SYNC_LOG
50 #include <future>
52 #include <jevois/Types/Singleton.H>
53 #include <jevois/Core/Engine.H>
54 
55 namespace
56 {
57  class LogCore : public jevois::Singleton<LogCore>
58  {
59  public:
60  LogCore() : itsBuffer(10000), itsRunning(true)
61 #ifdef JEVOIS_LOG_TO_FILE
62  , itsStream("jevois.log")
63 #endif
64  , itsEngine(nullptr)
65  {
66  itsRunFuture = std::async(std::launch::async, &LogCore::run, this);
67  }
68 
69  virtual ~LogCore()
70  {
71  // Tell run() thread to quit:
72  itsRunning = false;
73 
74  // Push a message so we unblock our run() thread in case the buffer was empty:
75  itsBuffer.push("Terminating Log activity");
76 
77  // Wait for the run() thread to complete:
78  if (itsRunFuture.valid()) try { itsRunFuture.get(); } catch (...) { jevois::warnAndIgnoreException(); }
79  }
80 
81  void run()
82  {
83  while (itsRunning)
84  {
85  std::string msg = itsBuffer.pop();
86 #ifdef JEVOIS_LOG_TO_FILE
87  itsStream << msg << std::endl;
88 #else
89 #ifdef JEVOIS_PLATFORM
90  // When using the serial port debug on platform and screen connected to it, screen gets confused if we do not
91  // send a CR here, since some other messages do send CR (and screen might get confused as to which line end to
92  // use). So send a CR too:
93  std::cerr << msg << '\r' << std::endl;
94 #else
95  std::cerr << msg << std::endl;
96 #endif
97 #endif
98  if (itsEngine) itsEngine->sendSerial(msg, true);
99  }
100  }
101 
103  volatile bool itsRunning;
104  std::future<void> itsRunFuture;
105 #ifdef JEVOIS_LOG_TO_FILE
106  std::ofstream itsStream;
107 #endif
108  jevois::Engine * itsEngine;
109  };
110 }
111 
112 void jevois::logSetEngine(Engine * e) { LogCore::instance().itsEngine = e; }
113 
114 #endif // JEVOIS_USE_SYNC_LOG
115 
116 // ##############################################################################################################
117 template <int Level>
118 jevois::Log<Level>::Log(char const * fullFileName, char const * functionName, std::string * outstr) :
119  itsOutStr(outstr)
120 {
121  // Strip out the file path and extension from the full file name
122  std::string const fn(fullFileName);
123  size_t const lastSlashPos = fn.rfind('/');
124  size_t const lastDotPos = fn.rfind('.');
125  std::string const partialFileName = fn.substr(lastSlashPos+1, lastDotPos-lastSlashPos-1);
126 
127  // Print out a pretty prefix to the log message
128  itsLogStream << levelStr<Level>() << ' ' << partialFileName << "::" << functionName << ": ";
129 }
130 
131 // ##############################################################################################################
132 #ifdef JEVOIS_USE_SYNC_LOG
133 
134 template <int Level>
136 {
137  std::lock_guard<std::mutex> guard(jevois::logOutputMutex);
138  std::string const msg = itsLogStream.str();
139  std::cerr << msg << std::endl;
140  if (itsOutStr) *itsOutStr = msg;
141 }
142 
143 #else // JEVOIS_USE_SYNC_LOG
144 
145 template <int Level>
147 {
148  std::string const msg = itsLogStream.str();
149  LogCore::instance().itsBuffer.push(msg);
150  if (itsOutStr) *itsOutStr = msg;
151 }
152 #endif // JEVOIS_USE_SYNC_LOG
153 
154 // ##############################################################################################################
155 template <int Level>
157 {
158  itsLogStream << static_cast<int>(out_item);
159  return * this;
160 }
161 
162 // ##############################################################################################################
163 template <int Level>
165 {
166  itsLogStream << static_cast<int>(out_item);
167  return * this;
168 }
169 
170 // ##############################################################################################################
171 // Explicit instantiations:
172 namespace jevois
173 {
174  template class Log<LOG_DEBUG>;
175  template class Log<LOG_INFO>;
176  template class Log<LOG_ERR>;
177  template class Log<LOG_CRIT>;
178 }
179 
180 // ##############################################################################################################
182 {
183  // great trick to get back the type of an exception caught via a catch(...), just rethrow it and catch again:
184  try { throw; }
185 
186  catch (std::exception const & e)
187  {
188  LERROR("Passing through std::exception: " << e.what());
189  throw;
190  }
191 
192  catch (...)
193  {
194  LERROR("Passing through unknown exception");
195  throw;
196  }
197 }
198 
199 // ##############################################################################################################
201 {
202  std::string ret;
203 
204  // great trick to get back the type of an exception caught via a catch(...), just rethrow it and catch again:
205  try { throw; }
206 
207  catch (std::exception const & e)
208  {
209  ret = "Ignoring std::exception [" + std::string(e.what()) + ']';
210  }
211 
212  catch (...)
213  {
214  ret = "Ignoring unknown exception";
215  }
216 
217  LERROR(ret);
218 
219  // Return the message except for the first 2 words:
220  size_t idx = ret.find(' '); idx = ret.find(' ', idx + 1);
221  return ret.substr(idx + 1);
222 }
223 
224 // ##############################################################################################################
225 // ##############################################################################################################
226 jevois::timed_lock_guard::timed_lock_guard(std::timed_mutex & mtx, char const * file, char const * func) :
227  itsMutex(mtx)
228 {
229  if (itsMutex.try_lock_for(std::chrono::seconds(1)) == false)
230  {
231  jevois::Log<LOG_CRIT>(file, func) << "Timeout trying to acquire lock";
232  throw std::runtime_error("FATAL DEADLOCK ERROR");
233  }
234 }
235 
236 // ##############################################################################################################
238 { itsMutex.unlock(); }
Thread-safe synchronized producer/consumer queue.
Definition: BoundedBuffer.H:37
std::string warnAndIgnoreException()
Convenience function to catch an exception, issue some LERROR (depending on type), and ignore it.
Definition: Log.C:200
Log< Level > & operator<<(T const &out_item)
Overloaded stream input operator for any type that has operator<< defined for ostream.
Definition: Log.H:66
#define LERROR(msg)
Convenience macro for users to print out console or syslog messages, ERROR level. ...
Definition: Log.H:186
void warnAndRethrowException()
Convenience function to catch an exception, issue some LERROR (depending on type), and rethrow it.
Definition: Log.C:181
void logSetEngine(Engine *e)
Set an Engine so that all log messages will be forwarded to its serial ports.
Definition: Log.C:112
int logLevel
Current log level.
Definition: Log.C:26
Logger class.
Definition: Log.H:54
~timed_lock_guard()
Destructor, unlocks the mutex.
Definition: Log.C:237
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level. ...
Definition: Log.H:205
int traceLevel
Current trace level.
Definition: Log.C:27
JeVois processing engine - gets images from camera sensor, processes them, and sends results over USB...
Definition: Engine.H:223
timed_lock_guard(std::timed_mutex &mtx, char const *file, char const *func)
Constructor, locks the mutex or throw if it cannot be locked before timeout.
Definition: Log.C:226
Log(char const *fullFileName, char const *functionName, std::string *outstr=nullptr)
Construct a new Log, adding a prefix to the log stream.
Definition: Log.C:118
A generic singleton class to enforce a single instance of an object.
Definition: Singleton.H:91
~Log()
Close the Log, outputting the aggregated message.
Definition: Log.C:146