JeVois  1.21
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
Loading...
Searching...
No Matches
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>
21#include <jevois/Util/Async.H>
22#include <mutex>
23#include <iostream>
24#include <fstream>
25#include <stdexcept>
26
27namespace jevois
28{
29 int logLevel = LOG_INFO;
30 int traceLevel = 0;
31}
32
33namespace
34{
35 template <int Level> char const * levelStr();
36 template <> char const * levelStr<LOG_DEBUG>() { return "DBG"; }
37 template <> char const * levelStr<LOG_INFO>() { return "INF"; }
38 template <> char const * levelStr<LOG_ERR>() { return "ERR"; }
39 template <> char const * levelStr<LOG_CRIT>() { return "FTL"; }
40}
41
42// ##############################################################################################################
43template <>
44jevois::Log<LOG_ALERT>::Log(char const * /*fullFileName*/, char const * /*functionName*/, std::string * outstr) :
45 itsOutStr(outstr)
46{
47 // No prefix added here, will just throw the user message
48}
49
50// ##############################################################################################################
51// Explicit instantiations:
52namespace jevois
53{
54 template class Log<LOG_DEBUG>;
55 template class Log<LOG_INFO>;
56 template class Log<LOG_ERR>;
57 template class Log<LOG_CRIT>;
58 template class Log<LOG_ALERT>;
59}
60
61// ##############################################################################################################
62#ifdef JEVOIS_USE_SYNC_LOG
63namespace jevois
64{
65 // Mutex used to avoid clashing synchronous outputs from multiple threads
66 std::mutex logOutputMutex;
67}
68
69void jevois::logSetEngine(Engine * e)
70{ LERROR("Cannot set Engine for logs when JeVois has been compiled with -D JEVOIS_USE_SYNC_LOG -- IGNORED"); }
71void jevois::logEnd()
72{ LINFO("Terminating Log service"); }
73
74#else // JEVOIS_USE_SYNC_LOG
75#include <future>
78#include <jevois/Core/Engine.H>
79
80namespace
81{
82 class LogCore : public jevois::Singleton<LogCore>
83 {
84 public:
85 LogCore() : itsBuffer(10000), itsRunning(true)
86#ifdef JEVOIS_LOG_TO_FILE
87 , itsStream("jevois.log")
88#endif
89 , itsEngine(nullptr)
90 {
91 itsRunFuture = jevois::async_little(std::bind(&LogCore::run, this));
92 }
93
94 virtual ~LogCore()
95 {
96 // Tell run() thread to quit:
97 itsRunning = false;
98
99 // Push a message so we unblock our run() thread in case the buffer was empty:
100 itsBuffer.push("Terminating Log service");
101
102 // Wait for the run() thread to complete:
103 JEVOIS_WAIT_GET_FUTURE(itsRunFuture);
104 }
105
106 void run()
107 {
108 while (itsRunning)
109 {
110 std::string msg = itsBuffer.pop();
111#ifdef JEVOIS_LOG_TO_FILE
112 itsStream << msg << std::endl;
113#else
114#ifdef JEVOIS_PLATFORM
115 // When using the serial port debug on platform and screen connected to it, screen gets confused if we do not
116 // send a CR here, since some other messages do send CR (and screen might get confused as to which line end to
117 // use). So send a CR too:
118 std::cerr << msg << '\r' << std::endl;
119#else
120 std::cerr << msg << std::endl;
121#endif
122#endif
123 if (itsEngine) itsEngine->sendSerial(msg, true);
124 }
125 }
126
127 void abort()
128 {
129 itsRunning = false;
130 // One more message to make sure our run() thread will not be stuck on pop():
131 LINFO("Terminating log facility.");
132 }
133
135 volatile bool itsRunning;
136 std::future<void> itsRunFuture;
137#ifdef JEVOIS_LOG_TO_FILE
138 std::ofstream itsStream;
139#endif
140 jevois::Engine * itsEngine;
141 };
142}
143
144void jevois::logSetEngine(Engine * e) { LogCore::instance().itsEngine = e; }
145void jevois::logEnd() { LogCore::instance().abort(); jevois::logSetEngine(nullptr); }
146#endif // JEVOIS_USE_SYNC_LOG
147
148// ##############################################################################################################
149template <int Level>
150jevois::Log<Level>::Log(char const * fullFileName, char const * functionName, std::string * outstr) :
151 itsOutStr(outstr)
152{
153 // Strip out the file path and extension from the full file name
154 std::string const fn(fullFileName);
155 size_t const lastSlashPos = fn.rfind('/');
156 size_t const lastDotPos = fn.rfind('.');
157 std::string const partialFileName = fn.substr(lastSlashPos+1, lastDotPos-lastSlashPos-1);
158
159 // Print out a pretty prefix to the log message
160 itsLogStream << levelStr<Level>() << ' ' << partialFileName << "::" << functionName << ": ";
161}
162
163// ##############################################################################################################
164#ifdef JEVOIS_USE_SYNC_LOG
165
166template <int Level>
168{
169 std::lock_guard<std::mutex> guard(jevois::logOutputMutex);
170 std::string const msg = itsLogStream.str();
171 std::cerr << msg << std::endl;
172 if (itsOutStr) *itsOutStr = msg;
173}
174
175#else // JEVOIS_USE_SYNC_LOG
176
177template <int Level>
179{
180 std::string const msg = itsLogStream.str();
181 LogCore::instance().itsBuffer.push(msg);
182 if (itsOutStr) *itsOutStr = msg;
183}
184#endif // JEVOIS_USE_SYNC_LOG
185
186// ##############################################################################################################
187template <int Level>
188jevois::Log<Level> & jevois::Log<Level>::operator<<(uint8_t const & out_item)
189{
190 itsLogStream << static_cast<int>(out_item);
191 return * this;
192}
193
194// ##############################################################################################################
195template <int Level>
196jevois::Log<Level> & jevois::Log<Level>::operator<<(int8_t const & out_item)
197{
198 itsLogStream << static_cast<int>(out_item);
199 return * this;
200}
201
202// ##############################################################################################################
203void jevois::warnAndRethrowException(std::string const & prefix)
204{
205 std::string pfx;
206 if (prefix.empty() == false) pfx = prefix + ": ";
207
208 // great trick to get back the type of an exception caught via a catch(...), just rethrow it and catch again:
209 try { throw; }
210
211 catch (std::exception const & e)
212 {
213 LERROR(pfx << "Passing through std::exception:");
214 std::vector<std::string> lines = jevois::split(e.what(), "\\n");
215 for (std::string const & li : lines) LERROR(li);
216 throw;
217 }
218
219 catch (boost::python::error_already_set & e)
220 {
221 LERROR(pfx << "Received exception from the Python interpreter:");
222 std::string str = jevois::getPythonExceptionString(e);
223 std::vector<std::string> lines = jevois::split(str, "\\n");
224 for (std::string const & li : lines) LERROR(li);
225 throw;
226 }
227
228 catch (...)
229 {
230 LERROR(pfx << "Passing through unknown exception");
231 throw;
232 }
233}
234
235// ##############################################################################################################
236std::string jevois::warnAndIgnoreException(std::string const & prefix)
237{
238 std::string pfx;
239 if (prefix.empty() == false) pfx = prefix + ": ";
240
241 std::vector<std::string> retvec;
242
243 // great trick to get back the type of an exception caught via a catch(...), just rethrow it and catch again:
244 try { throw; }
245
246 catch (std::exception const & e)
247 {
248 retvec.emplace_back(pfx + "Caught std::exception:");
249 std::vector<std::string> lines = jevois::split(e.what(), "\\n");
250 for (std::string const & li : lines) retvec.emplace_back(li);
251 }
252
253 catch (boost::python::error_already_set & e)
254 {
255 retvec.emplace_back(pfx + "Caught exception from the Python interpreter:");
256 std::string str = jevois::getPythonExceptionString(e);
257 std::vector<std::string> lines = jevois::split(str, "\\n");
258 for (std::string const & li : lines) retvec.emplace_back(li);
259 }
260
261 catch (...)
262 {
263 retvec.emplace_back(pfx + "Caught unknown exception");
264 }
265
266 // Write out the message:
267 std::string ret;
268 for (std::string & m : retvec) { LERROR(m); ret += m + "\n"; }
269
270 return ret;
271}
272
273// ##############################################################################################################
274void jevois::warnAndRethrowParamCallbackException[[noreturn]](std::string const & descriptor,
275 std::string const & strval)
276{
277 LERROR("Parameter " << descriptor << ": Provided value [" << strval << "] rejected by callback:");
278
279 // great trick to get back the type of an exception caught via a catch(...), just rethrow it and catch again:
280 try { throw; }
281
282 catch (std::exception const & e)
283 {
284 throw std::runtime_error(e.what());
285 }
286
287 catch (boost::python::error_already_set & e)
288 {
289 LERROR("Python exception:");
290 throw std::runtime_error(jevois::getPythonExceptionString(e));
291 }
292
293 catch (...)
294 {
295 throw std::runtime_error("Caught unknown exception");
296 }
297}
298
299// ##############################################################################################################
300void jevois::drawErrorImage(std::string const & errmsg, jevois::RawImage & videoerrimg)
301{
302 if (videoerrimg.valid() == false) { LERROR("Cannot draw in empty image -- IGNORED"); return; }
303
304 int ypos = 40; int fw = 6, fh = 10; jevois::rawimage::Font font = jevois::rawimage::Font6x10;
305 unsigned int white = jevois::whiteColor(videoerrimg.fmt);
306
307 // Clear image:
308 videoerrimg.clear();
309
310 // Draw a sad face:
311 jevois::rawimage::drawDisk(videoerrimg, 10, 8, 4, white);
312 jevois::rawimage::drawDisk(videoerrimg, 25, 8, 4, white);
313 jevois::rawimage::drawLine(videoerrimg, 8, 20, 27, 23, 2, white);
314
315 // Initial message:
316 jevois::rawimage::writeText(videoerrimg, "Oooops...", 45, 3, white, jevois::rawimage::Font14x26);
317
318 // Prepare font size for error log:
319 if (videoerrimg.width <= 352 || videoerrimg.height <= 240)
320 { font = jevois::rawimage::Font6x10; fw = 6; fh = 10; }
321 else if (videoerrimg.width <= 640 || videoerrimg.height <= 480)
322 { font = jevois::rawimage::Font7x13; fw = 7; fh = 13; }
323 else { font = jevois::rawimage::Font10x20; fw = 10; fh = 20; }
324
325 // Write out the message:
326 std::vector<std::string> lines = jevois::split(errmsg, "\\n");
327 for (std::string & m : lines)
328 {
329 // Do some simple linewrap:
330 unsigned int nchar = (videoerrimg.width - 6) / fw; // yes this will be a huge number if width < 6
331 while (m.size() > nchar)
332 {
333 jevois::rawimage::writeText(videoerrimg, m.substr(0, nchar), 3, ypos, white, font);
334 ypos += fh + 2;
335 m = m.substr(nchar, m.npos);
336 }
337 // Print out the last chunk (or the whole thing if it was short):
338 jevois::rawimage::writeText(videoerrimg, m, 3, ypos, white, font);
339 ypos += fh + 2;
340 }
341}
342
343// ##############################################################################################################
344// ##############################################################################################################
345jevois::timed_lock_guard::timed_lock_guard(std::timed_mutex & mtx, char const * file, char const * func) :
346 itsMutex(mtx)
347{
348 if (itsMutex.try_lock_for(std::chrono::seconds(5)) == false)
349 {
350 jevois::Log<LOG_CRIT>(file, func) << "Timeout trying to acquire lock";
351 throw std::runtime_error("FATAL DEADLOCK ERROR");
352 }
353}
354
355// ##############################################################################################################
356jevois::timed_lock_guard::~timed_lock_guard()
357{ itsMutex.unlock(); }
#define JEVOIS_WAIT_GET_FUTURE(f)
Wait for a future to become ready for 5 seconds, get(), warn and ignore exception,...
Definition Log.H:336
Thread-safe synchronized producer/consumer queue.
JeVois processing engine - gets images from camera sensor, processes them, and sends results over USB...
Definition Engine.H:414
Logger class.
Definition Log.H:56
Log< Level > & operator<<(T const &out_item)
Overloaded stream input operator for any type that has operator<< defined for ostream.
Definition Log.H:67
~Log()
Close the Log, outputting the aggregated message.
Definition Log.C:178
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:150
A raw image as coming from a V4L2 Camera and/or being sent out to a USB Gadget.
Definition RawImage.H:111
unsigned int fmt
Pixel format as a V4L2_PIX_FMT_XXX.
Definition RawImage.H:147
unsigned int width
Image width in pixels.
Definition RawImage.H:145
unsigned int height
Image height in pixels.
Definition RawImage.H:146
void clear()
Clear the pixels to all black.
Definition RawImage.C:50
bool valid() const
Check whether the image has a valid pixel buffer.
Definition RawImage.C:46
A generic singleton class to enforce a single instance of an object.
Definition Singleton.H:92
int logLevel
Current log level.
Definition Log.C:29
int traceLevel
Current trace level.
Definition Log.C:30
void logSetEngine(Engine *e)
Set an Engine so that all log messages will be forwarded to its serial ports.
Definition Log.C:144
std::string warnAndIgnoreException(std::string const &prefix="")
Convenience function to catch an exception, issue some LERROR (depending on type),...
Definition Log.C:236
void warnAndRethrowParamCallbackException(std::string const &descriptor, std::string const &strval)
Convenience function for parameter callback exceptions.
Definition Log.C:274
void warnAndRethrowException(std::string const &prefix="")
Convenience function to catch an exception, issue some LERROR (depending on type),...
Definition Log.C:203
#define LERROR(msg)
Convenience macro for users to print out console or syslog messages, ERROR level.
Definition Log.H:211
#define LINFO(msg)
Convenience macro for users to print out console or syslog messages, INFO level.
Definition Log.H:194
std::string getPythonExceptionString(boost::python::error_already_set &)
Python exception translation to string so we can print the traceback to our serlog stream.
void writeText(RawImage &img, std::string const &txt, int x, int y, unsigned int col, Font font=Font6x10)
Write some text in an image.
void drawDisk(RawImage &img, int x, int y, unsigned int rad, unsigned int col)
Draw a disk in a YUYV image.
Font
Available fonts for writeText()
void drawLine(RawImage &img, int x1, int y1, int x2, int y2, unsigned int thick, unsigned int col)
Draw a line in a YUYV image.
unsigned int whiteColor(unsigned int fcc)
Return a value that corresponds to white for the given video format.
Definition Utils.C:197
std::vector< std::string > split(std::string const &input, std::string const &regex="\\s+")
Split string into vector of tokens using a regex to specify what to split on; default regex splits by...
Definition Utils.C:270
std::future< std::invoke_result_t< std::decay_t< Function >, std::decay_t< Args >... > > async_little(Function &&f, Args &&... args)
Async execution using a thread pool.
Main namespace for all JeVois classes and functions.
Definition Concepts.dox:2
void drawErrorImage(std::string const &errmsg, RawImage &videoerrimg)
Display an error message into a RawImage.
Definition Log.C:300
void logEnd()
Terminate log service.
Definition Log.C:145