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
61struct 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
81static 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
120void 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
148static const char *LogLevelString[6] = {"Dev2: ", "Dev1: ", "Debug: ", "Info: ", "Warning: ", "Error: "};
149static const char *LogColorString[6] = {ANSI_COLOR_MAGENTA, ANSI_COLOR_GREEN, ANSI_COLOR_BLUE,
150 ANSI_COLOR_CYAN, ANSI_COLOR_YELLOW, ANSI_COLOR_RED};
151
152void 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
184ompl::msg::OutputHandlerFile::~OutputHandlerFile()
185{
186 if (file_ != nullptr)
187 if (fclose(file_) != 0)
188 std::cerr << "Error closing logfile" << std::endl;
189}
190
191void 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 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
OutputHandlerFile(const char *filename)
The name of the file in which to save the message data.
Definition: Console.cpp:177
Default implementation of OutputHandler. This sends the information to the console.
Definition: Console.h:117
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
Generic class to handle output from a piece of code.
Definition: Console.h:103
OutputHandler * getOutputHandler()
Get the instance of the OutputHandler currently used. This is nullptr in case there is no output hand...
Definition: Console.cpp:115
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
void useOutputHandler(OutputHandler *oh)
Specify the instance of the OutputHandler to use. By default, this is OutputHandlerSTD.
Definition: Console.cpp:108
void noOutputHandler()
This function instructs ompl that no messages should be outputted. Equivalent to useOutputHandler(nul...
Definition: Console.cpp:95
LogLevel
The set of priorities for message logging.
Definition: Console.h:85
LogLevel getLogLevel()
Retrieve the current level of logging data. Messages with lower logging levels will not be recorded.
Definition: Console.cpp:142
void restorePreviousOutputHandler()
Restore the output handler that was previously in use (if any)
Definition: Console.cpp:102
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