ompl/util/src/Console.cpp
00001 /********************************************************************* 00002 * Software License Agreement (BSD License) 00003 * 00004 * Copyright (c) 2008, Willow Garage, Inc. 00005 * All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions 00009 * are met: 00010 * 00011 * * Redistributions of source code must retain the above copyright 00012 * notice, this list of conditions and the following disclaimer. 00013 * * Redistributions in binary form must reproduce the above 00014 * copyright notice, this list of conditions and the following 00015 * disclaimer in the documentation and/or other materials provided 00016 * with the distribution. 00017 * * Neither the name of the Willow Garage nor the names of its 00018 * contributors may be used to endorse or promote products derived 00019 * from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00022 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00023 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00024 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00025 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00026 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00027 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00028 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00029 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00030 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00031 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 * POSSIBILITY OF SUCH DAMAGE. 00033 *********************************************************************/ 00034 00035 /* Author: Ioan Sucan */ 00036 00037 #include "ompl/util/Console.h" 00038 #include <boost/thread/mutex.hpp> 00039 #include <iostream> 00040 #include <cstdio> 00041 #include <cstdarg> 00042 00044 00045 struct DefaultOutputHandler 00046 { 00047 DefaultOutputHandler() 00048 { 00049 output_handler_ = static_cast<ompl::msg::OutputHandler*>(&std_output_handler_); 00050 previous_output_handler_ = output_handler_; 00051 logLevel_ = ompl::msg::LOG_DEBUG; 00052 } 00053 00054 ompl::msg::OutputHandlerSTD std_output_handler_; 00055 ompl::msg::OutputHandler *output_handler_; 00056 ompl::msg::OutputHandler *previous_output_handler_; 00057 ompl::msg::LogLevel logLevel_; 00058 boost::mutex lock_; // it is likely the outputhandler does some I/O, so we serialize it 00059 }; 00060 00061 // we use this function because we want to handle static initialization correctly 00062 // however, the first run of this function is not thread safe, due to the use of a static 00063 // variable inside the function. For this reason, we ensure the first call happens during 00064 // static initialization using a proxy class 00065 static DefaultOutputHandler* getDOH() 00066 { 00067 static DefaultOutputHandler DOH; 00068 return &DOH; 00069 } 00070 00071 #define USE_DOH \ 00072 DefaultOutputHandler *doh = getDOH(); \ 00073 boost::mutex::scoped_lock slock(doh->lock_) 00074 00075 #define MAX_BUFFER_SIZE 1024 00076 00078 00079 void ompl::msg::noOutputHandler() 00080 { 00081 USE_DOH; 00082 doh->previous_output_handler_ = doh->output_handler_; 00083 doh->output_handler_ = NULL; 00084 } 00085 00086 void ompl::msg::restorePreviousOutputHandler() 00087 { 00088 USE_DOH; 00089 std::swap(doh->previous_output_handler_, doh->output_handler_); 00090 } 00091 00092 void ompl::msg::useOutputHandler(OutputHandler *oh) 00093 { 00094 USE_DOH; 00095 doh->previous_output_handler_ = doh->output_handler_; 00096 doh->output_handler_ = oh; 00097 } 00098 00099 ompl::msg::OutputHandler* ompl::msg::getOutputHandler() 00100 { 00101 return getDOH()->output_handler_; 00102 } 00103 00104 void ompl::msg::log(const char *file, int line, LogLevel level, const char *m, ...) 00105 { 00106 USE_DOH; 00107 if (doh->output_handler_ && level >= doh->logLevel_) 00108 { 00109 va_list __ap; 00110 va_start(__ap, m); 00111 char buf[MAX_BUFFER_SIZE]; 00112 vsnprintf(buf, sizeof(buf), m, __ap); 00113 va_end(__ap); 00114 buf[MAX_BUFFER_SIZE - 1] = '\0'; 00115 00116 doh->output_handler_->log(buf, level, file, line); 00117 } 00118 } 00119 00120 void ompl::msg::setLogLevel(LogLevel level) 00121 { 00122 USE_DOH; 00123 doh->logLevel_ = level; 00124 } 00125 00126 ompl::msg::LogLevel ompl::msg::getLogLevel() 00127 { 00128 USE_DOH; 00129 return doh->logLevel_; 00130 } 00131 00132 static const char *LogLevelString[4] = {"Debug: ", "Info: ", "Warning: ", "Error: "}; 00133 00134 void ompl::msg::OutputHandlerSTD::log(const std::string &text, LogLevel level, const char *filename, int line) 00135 { 00136 if (level >= LOG_WARN) 00137 { 00138 std::cerr << LogLevelString[level] << text << std::endl; 00139 std::cerr << " at line " << line << " in " << filename << std::endl; 00140 std::cerr.flush(); 00141 } 00142 else 00143 { 00144 std::cout << LogLevelString[level] << text << std::endl; 00145 std::cout.flush(); 00146 } 00147 } 00148 00149 ompl::msg::OutputHandlerFile::OutputHandlerFile(const char *filename) : OutputHandler() 00150 { 00151 file_ = fopen(filename, "a"); 00152 if (!file_) 00153 std::cerr << "Unable to open log file: '" << filename << "'" << std::endl; 00154 } 00155 00156 ompl::msg::OutputHandlerFile::~OutputHandlerFile() 00157 { 00158 if (file_) 00159 if (fclose(file_) != 0) 00160 std::cerr << "Error closing logfile" << std::endl; 00161 } 00162 00163 void ompl::msg::OutputHandlerFile::log(const std::string &text, LogLevel level, const char *filename, int line) 00164 { 00165 if (file_) 00166 { 00167 fprintf(file_, "%s%s\n", LogLevelString[level], text.c_str()); 00168 if(level >= LOG_WARN) 00169 fprintf(file_, " at line %d in %s\n", line, filename); 00170 fflush(file_); 00171 } 00172 }