Goby Underwater Autonomy Project
Series: 1.1, revision: 163, released on 2013-02-06 14:23:27 -0500
|
00001 // copyright 2009 t. schneider tes@mit.edu 00002 // 00003 // this file is part of flex-cout, a terminal display library 00004 // that extends the functionality of std::cout 00005 // 00006 // This program is free software: you can redistribute it and/or modify 00007 // it under the terms of the GNU General Public License as published by 00008 // the Free Software Foundation, either version 3 of the License, or 00009 // (at your option) any later version. 00010 // 00011 // This software is distributed in the hope that it will be useful, 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 // GNU General Public License for more details. 00015 // 00016 // You should have received a copy of the GNU General Public License 00017 // along with this software. If not, see <http://www.gnu.org/licenses/>. 00018 00019 #include <iostream> 00020 #include <sstream> 00021 #include <limits> 00022 #include <iomanip> 00023 00024 #include <boost/assign.hpp> 00025 #include <boost/foreach.hpp> 00026 #include <boost/bind.hpp> 00027 #include <boost/date_time.hpp> 00028 00029 //#ifdef HAS_NCURSES 00030 #include "flex_ncurses.h" 00031 //#endif 00032 00033 #include "flex_ostreambuf.h" 00034 #include "goby/util/sci.h" 00035 #include "goby/util/time.h" 00036 #include "goby/core/libcore/exception.h" 00037 #include "logger_manipulators.h" 00038 00039 00040 00041 boost::mutex curses_mutex; 00042 00043 boost::mutex goby::util::Logger::mutex; 00044 00045 goby::util::FlexOStreamBuf::FlexOStreamBuf(): buffer_(1), 00046 name_("no name"), 00047 die_flag_(false), 00048 warn_flag_(false), 00049 debug_flag_(false), 00050 #ifdef HAS_NCURSES 00051 curses_(0), 00052 #endif 00053 start_time_(goby_time()), 00054 is_quiet_(true), 00055 is_gui_(false) 00056 00057 { 00058 Group no_group("", "Ungrouped messages"); 00059 groups_[""] = no_group; 00060 } 00061 00062 goby::util::FlexOStreamBuf::~FlexOStreamBuf() 00063 { 00064 #ifdef HAS_NCURSES 00065 if(curses_) delete curses_; 00066 #endif 00067 } 00068 00069 void goby::util::FlexOStreamBuf::add_stream(Logger::Verbosity verbosity, std::ostream* os) 00070 { 00071 //check that this stream doesn't exist 00072 // if so, update its verbosity and return 00073 bool stream_exists = false; 00074 BOOST_FOREACH(StreamConfig& sc, streams_) 00075 { 00076 if(sc.os() == os) 00077 { 00078 sc.set_verbosity(verbosity); 00079 stream_exists = true; 00080 } 00081 } 00082 00083 if(!stream_exists) 00084 streams_.push_back(StreamConfig(os, verbosity)); 00085 00086 00087 if(verbosity == Logger::gui) 00088 { 00089 #ifdef HAS_NCURSES 00090 if(is_gui_) return; 00091 00092 is_gui_ = true; 00093 00094 curses_ = new FlexNCurses; 00095 00096 boost::mutex::scoped_lock lock(curses_mutex); 00097 00098 curses_->startup(); 00099 00100 // add any groups already on the screen as ncurses windows 00101 typedef std::pair<std::string, Group> P; 00102 BOOST_FOREACH(const P&p, groups_) 00103 curses_->add_win(&groups_[p.first]); 00104 00105 curses_->recalculate_win(); 00106 00107 input_thread_ = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&FlexNCurses::run_input, curses_))); 00108 #else 00109 throw(goby::Exception("Tried to use verbosity==gui without compiling against NCurses. Install NCurses and recompile goby or use a different verbosity")); 00110 #endif 00111 } 00112 else if(verbosity != Logger::quiet) 00113 { 00114 is_quiet_ = false; 00115 } 00116 } 00117 00118 void goby::util::FlexOStreamBuf::add_group(const std::string & name, Group g) 00119 { 00120 if(groups_.count(name)) return; 00121 00122 groups_[name] = g; 00123 00124 #ifdef HAS_NCURSES 00125 if(is_gui_) 00126 { 00127 boost::mutex::scoped_lock lock(curses_mutex); 00128 curses_->add_win(&groups_[name]); 00129 } 00130 #endif 00131 } 00132 00133 int goby::util::FlexOStreamBuf::overflow(int c /*= EOF*/) 00134 { 00135 if(c == EOF) 00136 return c; 00137 else if(c == '\n') 00138 buffer_.push_back(std::string()); 00139 else 00140 buffer_.back().push_back(c); 00141 00142 return c; 00143 } 00144 00145 // called when flush() or std::endl 00146 int goby::util::FlexOStreamBuf::sync() 00147 { 00148 // all but last one 00149 while(buffer_.size() > 1) 00150 { 00151 display(buffer_.front()); 00152 buffer_.pop_front(); 00153 } 00154 00155 group_name_.erase(); 00156 00157 00158 debug_flag_ = false; 00159 warn_flag_ = false; 00160 00161 if(die_flag_) exit(EXIT_FAILURE); 00162 return 0; 00163 } 00164 00165 void goby::util::FlexOStreamBuf::display(std::string & s) 00166 { 00167 00168 #ifdef HAS_NCURSES 00169 if(is_gui_) 00170 { 00171 if(!die_flag_) 00172 { 00173 boost::mutex::scoped_lock lock(curses_mutex); 00174 std::stringstream line; 00175 boost::posix_time::time_duration time_of_day = goby_time().time_of_day(); 00176 line << "\n" 00177 << std::setfill('0') << std::setw(2) << time_of_day.hours() << ":" 00178 << std::setw(2) << time_of_day.minutes() << ":" 00179 << std::setw(2) << time_of_day.seconds() << 00180 TermColor::esc_code_from_col(groups_[group_name_].color()) << " | " << esc_nocolor 00181 << s; 00182 00183 curses_->insert(goby_time(), line.str(), &groups_[group_name_]); 00184 } 00185 else 00186 { 00187 curses_->alive(false); 00188 input_thread_->join(); 00189 curses_->cleanup(); 00190 00191 std::cout << TermColor::esc_code_from_col(groups_[group_name_].color()) << name_ << esc_nocolor << ": " << s << esc_nocolor << std::endl; 00192 } 00193 } 00194 #endif 00195 00196 BOOST_FOREACH(const StreamConfig& cfg, streams_) 00197 { 00198 if(cfg.os() == &std::cout || cfg.os() == &std::cerr || cfg.os() == &std::clog) 00199 { 00200 switch(cfg.verbosity()) 00201 { 00202 default: 00203 case Logger::quiet: 00204 break; 00205 case Logger::warn: 00206 if(!warn_flag_) break; 00207 case Logger::verbose: 00208 if(debug_flag_) break; 00209 case Logger::debug: 00210 *cfg.os() << TermColor::esc_code_from_col(groups_[group_name_].color()) << name_ << esc_nocolor << " (" << boost::posix_time::to_iso_string(goby_time()) << "): " << s << esc_nocolor << std::endl; 00211 break; 00212 } 00213 } 00214 else if(cfg.os()) 00215 { 00216 switch(cfg.verbosity()) 00217 { 00218 default: 00219 case Logger::quiet: 00220 break; 00221 case Logger::warn: 00222 if(!warn_flag_) break; 00223 case Logger::verbose: 00224 if(debug_flag_) break; 00225 case Logger::debug: 00226 basic_log_header(*cfg.os(), group_name_); 00227 strip_escapes(s); 00228 *cfg.os() << s << std::endl; 00229 break; 00230 } 00231 } 00232 } 00233 } 00234 00235 void goby::util::FlexOStreamBuf::refresh() 00236 { 00237 #ifdef HAS_NCURSES 00238 if(is_gui_) 00239 { 00240 boost::mutex::scoped_lock lock(curses_mutex); 00241 curses_->recalculate_win(); 00242 } 00243 #endif 00244 } 00245 00246 // clean out any escape codes for non terminal streams 00247 void goby::util::FlexOStreamBuf::strip_escapes(std::string& s) 00248 { 00249 static const std::string esc = "\33["; 00250 static const std::string m = "m"; 00251 00252 size_t esc_pos, m_pos; 00253 while((esc_pos = s.find(esc)) != std::string::npos 00254 && (m_pos = s.find(m, esc_pos)) != std::string::npos) 00255 s.erase(esc_pos, m_pos-esc_pos+1); 00256 00257 } 00258