libmoost
|
00001 /* vim:set ts=3 sw=3 sts=3 et: */ 00028 #include "../../include/moost/terminal_format.hpp" 00029 #include "../../include/moost/service/appender.h" 00030 00031 #include <boost/algorithm/string/split.hpp> 00032 #include <boost/algorithm/string/classification.hpp> 00033 00034 #include <log4cxx/appenderskeleton.h> 00035 #include <log4cxx/patternlayout.h> 00036 #include <log4cxx/logger.h> 00037 #include <log4cxx/helpers/transcoder.h> 00038 00039 using namespace moost::service; 00040 00041 stream_writer_iface::~stream_writer_iface() 00042 { 00043 } 00044 00045 appender_iface::~appender_iface() 00046 { 00047 } 00048 00049 appender_factory_iface::~appender_factory_iface() 00050 { 00051 } 00052 00053 //--------------------------------------------------------------------- 00054 00055 class null_appender : public appender_iface 00056 { 00057 public: 00058 null_appender(); 00059 00060 virtual bool handle_command(std::string&, const std::string&, const std::string&); 00061 virtual std::string show_help() const; 00062 virtual bool attach(); 00063 virtual bool detach(); 00064 }; 00065 00066 null_appender::null_appender() 00067 { 00068 } 00069 00070 bool null_appender::handle_command(std::string&, const std::string&, const std::string&) 00071 { 00072 return false; 00073 } 00074 00075 std::string null_appender::show_help() const 00076 { 00077 return ""; 00078 } 00079 00080 bool null_appender::attach() 00081 { 00082 return true; 00083 } 00084 00085 bool null_appender::detach() 00086 { 00087 return true; 00088 } 00089 00090 //--------------------------------------------------------------------- 00091 00092 class log4cxx_appender : public moost::service::appender_iface 00093 { 00094 private: 00095 class impl : public log4cxx::AppenderSkeleton 00096 { 00097 public: 00098 impl(stream_writer_ptr sw) 00099 : m_writer(sw) 00100 { 00101 } 00102 00103 protected: 00104 virtual void append(const log4cxx::spi::LoggingEventPtr &event, log4cxx::helpers::Pool &pool) 00105 { 00106 log4cxx::LogString ls; 00107 getLayout()->format(ls, event, pool); 00108 std::string s; 00109 log4cxx::helpers::Transcoder::encode(ls, s); 00110 m_writer->write(s.c_str(), s.length()); 00111 } 00112 00113 virtual void close() 00114 { 00115 } 00116 00117 virtual bool requiresLayout() const 00118 { 00119 return true; 00120 } 00121 00122 private: 00123 stream_writer_ptr m_writer; 00124 }; 00125 00126 public: 00127 log4cxx_appender(stream_writer_ptr sw, log4cxx::LevelPtr& level) 00128 : m_app(new impl(sw)) 00129 , m_layout(new log4cxx::PatternLayout) 00130 { 00131 set_conversion_pattern("[%d{yyyy-MMM-dd HH:mm:ss}|" + moost::terminal_format::color("%c", moost::C_CYAN) + "](%p) %m%n"); 00132 m_app->setLayout(m_layout); 00133 m_app->setThreshold(level); 00134 } 00135 00136 virtual bool handle_command(std::string& rv, const std::string& cmd, const std::string& args) 00137 { 00138 if (cmd == "level") 00139 { 00140 log_level(rv, args); 00141 } 00142 else if (cmd == "pattern") 00143 { 00144 log_pattern(rv, args); 00145 } 00146 else 00147 { 00148 return false; 00149 } 00150 00151 return true; 00152 } 00153 00154 virtual std::string show_help() const 00155 { 00156 std::string level; 00157 00158 m_app->getThreshold()->toString(level); 00159 00160 return "- level show all logging levels\r\n" 00161 "- level off|fatal|error|warn|info|debug|trace|all\r\n" 00162 " set console log level <" + level + ">\r\n" 00163 "- level root|<appender name>\r\n" 00164 " [off|fatal|error|warn|info|debug|trace|all]\r\n" 00165 " show/set root or appender log level\r\n" 00166 "- pattern [<fmt>] show/set log pattern\r\n"; 00167 } 00168 00169 virtual bool attach() 00170 { 00171 log4cxx::Logger::getRootLogger()->addAppender(m_app); 00172 return true; 00173 } 00174 00175 virtual bool detach() 00176 { 00177 log4cxx::Logger::getRootLogger()->removeAppender(m_app); 00178 return true; 00179 } 00180 00181 private: 00182 bool string_to_level(const std::string& level, log4cxx::LevelPtr& new_level) const 00183 { 00184 log4cxx::LevelPtr invalid = new log4cxx::Level(-1, LOG4CXX_STR("INVALID"), 7); 00185 new_level = log4cxx::Level::toLevel(level, invalid); 00186 return new_level != invalid; 00187 } 00188 00189 std::string level_to_string(const log4cxx::LevelPtr& level) const 00190 { 00191 if (level) 00192 { 00193 std::string str; 00194 level->toString(str); 00195 return str; 00196 } 00197 00198 return "<unknown>"; 00199 } 00200 00201 // getThreshold() is non-const so we require a non-const skeleton pointer 00202 std::string get_appender_level(log4cxx::AppenderSkeleton* skel) const 00203 { 00204 return level_to_string(skel->getThreshold()); 00205 } 00206 00207 std::string get_logger_level(const log4cxx::Logger* logger) const 00208 { 00209 return level_to_string(logger->getLevel()); 00210 } 00211 00212 bool log_level(std::string& rv, const std::string& args) 00213 { 00214 std::ostringstream oss; 00215 00216 if (args.empty()) 00217 { 00218 log4cxx::LoggerPtr root = log4cxx::Logger::getRootLogger(); 00219 00220 oss << "console log level is [" << get_appender_level(m_app) << "]\r\n"; 00221 oss << "root logger level is [" << get_logger_level(root) << "]\r\n"; 00222 00223 log4cxx::AppenderList appenders = root->getAllAppenders(); 00224 00225 for (log4cxx::AppenderList::iterator it = appenders.begin(); it != appenders.end(); ++it) 00226 { 00227 log4cxx::AppenderSkeleton* skel = dynamic_cast<log4cxx::AppenderSkeleton *>(it->operator->()); 00228 00229 if (skel && skel != m_app && !skel->getName().empty()) 00230 { 00231 std::string name; 00232 log4cxx::helpers::Transcoder::encode(skel->getName(), name); 00233 oss << name << " appender level is [" << get_appender_level(skel) << "]\r\n"; 00234 } 00235 } 00236 } 00237 else 00238 { 00239 std::vector<std::string> argv; 00240 boost::algorithm::split(argv, args, boost::algorithm::is_any_of(" \t")); 00241 log4cxx::LevelPtr new_level; 00242 bool write = false; 00243 00244 switch (argv.size()) 00245 { 00246 case 1: // write console log level OR read root logger / named appender log level 00247 if (string_to_level(argv[0], new_level)) 00248 { 00249 // write console log level 00250 00251 m_app->setThreshold(new_level); 00252 00253 rv = "console log level set to [" + get_appender_level(m_app) + "]\r\n"; 00254 return true; 00255 } 00256 break; 00257 00258 case 2: // write named logger log level 00259 if (!string_to_level(argv[1], new_level)) 00260 { 00261 rv = "invalid log level: " + argv[1] + "\r\n"; 00262 return true; 00263 } 00264 00265 write = true; 00266 00267 break; 00268 00269 default: 00270 rv = "invalid number of arguments\r\n"; 00271 return true; 00272 } 00273 00274 std::string action(write ? "set to" : "is"); 00275 00276 if (argv[0] == "root") 00277 { 00278 log4cxx::LoggerPtr root = log4cxx::Logger::getRootLogger(); 00279 00280 if (write) 00281 { 00282 root->setLevel(new_level); 00283 } 00284 00285 oss << "root logger level " << action << " [" + get_logger_level(root) << "]\r\n"; 00286 } 00287 else 00288 { 00289 log4cxx::LogString name; 00290 log4cxx::helpers::Transcoder::decode(argv[0], name); 00291 log4cxx::LoggerPtr root = log4cxx::Logger::getRootLogger(); 00292 log4cxx::AppenderPtr app = root->getAppender(name); 00293 log4cxx::AppenderSkeleton* skel = dynamic_cast<log4cxx::AppenderSkeleton *>(app.operator->()); 00294 00295 if (!skel) 00296 { 00297 rv = "no such appender: " + argv[0] + "\r\n"; 00298 return true; 00299 } 00300 00301 if (write) 00302 { 00303 skel->setThreshold(new_level); 00304 } 00305 00306 oss << name << " appender level " << action << " [" << get_appender_level(skel) << "]\r\n"; 00307 } 00308 } 00309 00310 rv = oss.str(); 00311 00312 return true; 00313 } 00314 00315 bool log_pattern(std::string& rv, const std::string& args) 00316 { 00317 if (!args.empty()) 00318 { 00319 set_conversion_pattern(args); 00320 } 00321 00322 rv = "conversion pattern set to [" + get_conversion_pattern() + "]\r\n"; 00323 00324 return true; 00325 } 00326 00327 void set_conversion_pattern(const std::string& pattern) 00328 { 00329 log4cxx::LogString ls_pattern; 00330 log4cxx::helpers::Transcoder::decode(pattern, ls_pattern); 00331 m_layout->setConversionPattern(ls_pattern); 00332 } 00333 00334 std::string get_conversion_pattern() const 00335 { 00336 std::string pattern; 00337 log4cxx::helpers::Transcoder::encode(m_layout->getConversionPattern(), pattern); 00338 return pattern; 00339 } 00340 00341 log4cxx::helpers::ObjectPtrT<impl> m_app; 00342 log4cxx::helpers::ObjectPtrT<log4cxx::PatternLayout> m_layout; 00343 }; 00344 00345 //--------------------------------------------------------------------- 00346 00347 log4cxx_appender_factory::log4cxx_appender_factory(const std::string& level) 00348 : m_default_level(log4cxx::Level::toLevel(level, log4cxx::Level::getWarn())) 00349 { 00350 } 00351 00352 appender_ptr log4cxx_appender_factory::create(stream_writer_ptr sw) 00353 { 00354 return boost::shared_ptr<appender_iface>(new log4cxx_appender(sw, m_default_level)); 00355 } 00356 00357 //--------------------------------------------------------------------- 00358 00359 null_appender_factory::null_appender_factory() 00360 { 00361 } 00362 00363 appender_ptr null_appender_factory::create(stream_writer_ptr) 00364 { 00365 return boost::shared_ptr<appender_iface>(new null_appender); 00366 }