Console.cpp
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2008, Willow Garage, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 * * Neither the name of the Willow Garage nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34 
35 /* Author: Ioan Sucan */
36 
37 #include "ompl/util/Console.h"
38 #include <mutex>
39 #include <iostream>
40 #include <cstdio>
41 #include <cstdarg>
42 #ifdef _WIN32
43 #include <stdio.h>
44 #include <io.h>
45 #define isatty(x) _isatty(x)
46 #define fileno(x) _fileno(x)
47 #else
48 #include <unistd.h>
49 #endif
50 
51 #define ANSI_COLOR_RED "\x1b[31m"
52 #define ANSI_COLOR_GREEN "\x1b[32m"
53 #define ANSI_COLOR_YELLOW "\x1b[33m"
54 #define ANSI_COLOR_BLUE "\x1b[34m"
55 #define ANSI_COLOR_MAGENTA "\x1b[35m"
56 #define ANSI_COLOR_CYAN "\x1b[36m"
57 #define ANSI_COLOR_RESET "\x1b[0m"
58 
60 
61 struct DefaultOutputHandler
62 {
63  DefaultOutputHandler()
64  {
65  output_handler_ = static_cast<ompl::msg::OutputHandler *>(&std_output_handler_);
66  previous_output_handler_ = output_handler_;
67  logLevel_ = ompl::msg::LOG_DEBUG;
68  }
69 
70  ompl::msg::OutputHandlerSTD std_output_handler_;
71  ompl::msg::OutputHandler *output_handler_;
72  ompl::msg::OutputHandler *previous_output_handler_;
73  ompl::msg::LogLevel logLevel_;
74  std::mutex lock_; // it is likely the outputhandler does some I/O, so we serialize it
75 };
76 
77 // we use this function because we want to handle static initialization correctly
78 // however, the first run of this function is not thread safe, due to the use of a static
79 // variable inside the function. For this reason, we ensure the first call happens during
80 // static initialization using a proxy class
81 static DefaultOutputHandler *getDOH()
82 {
83  static DefaultOutputHandler DOH;
84  return &DOH;
85 }
86 
87 #define USE_DOH \
88  DefaultOutputHandler *doh = getDOH(); \
89  std::lock_guard<std::mutex> slock(doh->lock_)
90 
91 #define MAX_BUFFER_SIZE 1024
92 
94 
96 {
97  USE_DOH;
98  doh->previous_output_handler_ = doh->output_handler_;
99  doh->output_handler_ = nullptr;
100 }
101 
103 {
104  USE_DOH;
105  std::swap(doh->previous_output_handler_, doh->output_handler_);
106 }
107 
109 {
110  USE_DOH;
111  doh->previous_output_handler_ = doh->output_handler_;
112  doh->output_handler_ = oh;
113 }
114 
116 {
117  return getDOH()->output_handler_;
118 }
119 
120 void ompl::msg::log(const char *file, int line, LogLevel level, const char *m, ...)
121 {
122  USE_DOH;
123  if ((doh->output_handler_ != nullptr) && level >= doh->logLevel_)
124  {
125  va_list __ap;
126  va_start(__ap, m);
127  char buf[MAX_BUFFER_SIZE];
128  vsnprintf(buf, sizeof(buf), m, __ap);
129  va_end(__ap);
130  buf[MAX_BUFFER_SIZE - 1] = '\0';
131 
132  doh->output_handler_->log(buf, level, file, line);
133  }
134 }
135 
137 {
138  USE_DOH;
139  doh->logLevel_ = level;
140 }
141 
143 {
144  USE_DOH;
145  return doh->logLevel_;
146 }
147 
148 static const char *LogLevelString[6] = {"Dev2: ", "Dev1: ", "Debug: ", "Info: ", "Warning: ", "Error: "};
149 static const char *LogColorString[6] = {ANSI_COLOR_MAGENTA, ANSI_COLOR_GREEN, ANSI_COLOR_BLUE,
150  ANSI_COLOR_CYAN, ANSI_COLOR_YELLOW, ANSI_COLOR_RED};
151 
152 void ompl::msg::OutputHandlerSTD::log(const std::string &text, LogLevel level, const char *filename, int line)
153 {
154  if (level >= LOG_WARN)
155  {
156  bool isTTY(isatty(fileno(stderr)) != 0);
157  if (isTTY)
158  std::cerr << LogColorString[level + 2];
159  std::cerr << LogLevelString[level + 2] << text << std::endl;
160  std::cerr << " at line " << line << " in " << filename << std::endl;
161  if (isTTY)
162  std::cerr << ANSI_COLOR_RESET;
163  std::cerr.flush();
164  }
165  else
166  {
167  bool isTTY(isatty(fileno(stdout)) != 0);
168  if (isTTY)
169  std::cout << LogColorString[level + 2];
170  std::cout << LogLevelString[level + 2] << text << std::endl;
171  if (isTTY)
172  std::cout << ANSI_COLOR_RESET;
173  std::cout.flush();
174  }
175 }
176 
178 {
179  file_ = fopen(filename, "a");
180  if (file_ == nullptr)
181  std::cerr << "Unable to open log file: '" << filename << "'" << std::endl;
182 }
183 
184 ompl::msg::OutputHandlerFile::~OutputHandlerFile()
185 {
186  if (file_ != nullptr)
187  if (fclose(file_) != 0)
188  std::cerr << "Error closing logfile" << std::endl;
189 }
190 
191 void ompl::msg::OutputHandlerFile::log(const std::string &text, LogLevel level, const char *filename, int line)
192 {
193  if (file_ != nullptr)
194  {
195  fprintf(file_, "%s%s\n", LogLevelString[level + 2], text.c_str());
196  if (level >= LOG_WARN)
197  fprintf(file_, " at line %d in %s\n", line, filename);
198  fflush(file_);
199  }
200 }
void noOutputHandler()
This function instructs ompl that no messages should be outputted. Equivalent to useOutputHandler(nul...
Definition: Console.cpp:95
Generic class to handle output from a piece of code.
Definition: Console.h:102
void useOutputHandler(OutputHandler *oh)
Specify the instance of the OutputHandler to use. By default, this is OutputHandlerSTD.
Definition: Console.cpp:108
void log(const std::string &text, LogLevel level, const char *filename, int line) override
log a message to the output handler with the given text and logging level from a specific file and li...
Definition: Console.cpp:152
Default implementation of OutputHandler. This sends the information to the console.
Definition: Console.h:116
void log(const char *file, int line, LogLevel level, const char *m,...)
Root level logging function. This should not be invoked directly, but rather used via a logging macro...
Definition: Console.cpp:120
OutputHandlerFile(const char *filename)
The name of the file in which to save the message data.
Definition: Console.cpp:177
void setLogLevel(LogLevel level)
Set the minimum level of logging data to output. Messages with lower logging levels will not be recor...
Definition: Console.cpp:136
LogLevel
The set of priorities for message logging.
Definition: Console.h:84
void restorePreviousOutputHandler()
Restore the output handler that was previously in use (if any)
Definition: Console.cpp:102
void log(const std::string &text, LogLevel level, const char *filename, int line) override
log a message to the output handler with the given text and logging level from a specific file and li...
Definition: Console.cpp:191
LogLevel getLogLevel()
Retrieve the current level of logging data. Messages with lower logging levels will not be recorded.
Definition: Console.cpp:142
OutputHandler * getOutputHandler()
Get the instance of the OutputHandler currently used. This is nullptr in case there is no output hand...
Definition: Console.cpp:115