/* */ #include "Logger.h" #include #include #include #include "DlAbortEx.h" #include "fmt.h" #include "message.h" #include "A2STR.h" #include "a2time.h" #include "BufferedFile.h" #include "util.h" #include "console.h" namespace aria2 { Logger::Logger() : logLevel_(Logger::A2_DEBUG), stdoutField_(0), #ifdef __MINGW32__ // Windows DOS prompt does not handle ANSI color code, so make // this false. useColor_(false) #else // !__MINGW32__ useColor_(isatty(STDOUT_FILENO) == 1) #endif // !__MINGW32__ {} Logger::~Logger() { } void Logger::openFile(const std::string& filename) { closeFile(); if(filename == DEV_STDOUT) { fpp_ = global::cout(); } else { fpp_.reset(new BufferedFile(filename.c_str(), BufferedFile::APPEND)); if(!*static_cast(fpp_.get())) { throw DL_ABORT_EX(fmt(EX_FILE_OPEN, filename.c_str(), "n/a")); } } } void Logger::closeFile() { if(fpp_) { fpp_.reset(); } } void Logger::setStdoutLogLevel(Logger::LEVEL level, bool enabled) { if(enabled) { stdoutField_ |= level; } else { stdoutField_ &= ~level; } } bool Logger::levelEnabled(LEVEL level) { return (level >= logLevel_ && fpp_) || stdoutField_&level; } namespace { const char* levelToString(Logger::LEVEL level) { switch(level) { case Logger::A2_DEBUG: return "DEBUG"; case Logger::A2_INFO: return "INFO"; case Logger::A2_NOTICE: return "NOTICE"; case Logger::A2_WARN: return "WARN"; case Logger::A2_ERROR: return "ERROR"; default: return ""; } } } // namespace namespace { template void writeHeader (Output& fp, Logger::LEVEL level, const char* sourceFile, int lineNum) { struct timeval tv; gettimeofday(&tv, 0); char datestr[20]; // 'YYYY-MM-DD hh:mm:ss'+'\0' = 20 bytes struct tm tm; //tv.tv_sec may not be of type time_t. time_t timesec = tv.tv_sec; localtime_r(×ec, &tm); size_t dateLength = strftime(datestr, sizeof(datestr), "%Y-%m-%d %H:%M:%S", &tm); assert(dateLength <= (size_t)20); fp.printf("%s.%06ld [%s] [%s:%d] ", datestr, tv.tv_usec, levelToString(level), sourceFile, lineNum); } } // namespace namespace { const char* levelColor(Logger::LEVEL level) { switch(level) { case Logger::A2_DEBUG: case Logger::A2_INFO: // We don't print these levels in console return ""; case Logger::A2_NOTICE: return "\033[1;32m"; case Logger::A2_WARN: return "\033[1;33m"; case Logger::A2_ERROR: return "\033[1;31m"; default: return ""; } } } // namespace namespace { template void writeHeaderConsole(Output& fp, Logger::LEVEL level, bool useColor) { if(useColor) { fp.printf("[%s%s\033[0m] ", levelColor(level), levelToString(level)); } else { fp.printf("[%s] ", levelToString(level)); } } } // namespace namespace { template void writeStackTrace(Output& fp, const std::string& stackTrace) { fp.write(stackTrace.c_str()); } } // namespace void Logger::writeLog (Logger::LEVEL level, const char* sourceFile, int lineNum, const char* msg, const std::string& trace, bool toStream, bool toConsole) { if(toStream) { writeHeader(*fpp_, level, sourceFile, lineNum); fpp_->printf("%s\n", msg); writeStackTrace(*fpp_, trace); fpp_->flush(); } if(toConsole) { global::cout()->printf("\n"); writeHeaderConsole(*global::cout(), level, useColor_); global::cout()->printf("%s\n", msg); writeStackTrace(*global::cout(), trace); global::cout()->flush(); } } void Logger::log (LEVEL level, const char* sourceFile, int lineNum, const char* msg) { writeLog(level, sourceFile, lineNum, msg, A2STR::NIL, level >= logLevel_ && fpp_, stdoutField_&level); } void Logger::log (LEVEL level, const char* sourceFile, int lineNum, const std::string& msg) { log(level, sourceFile, lineNum, msg.c_str()); } void Logger::log (LEVEL level, const char* sourceFile, int lineNum, const char* msg, const Exception& ex) { writeLog(level, sourceFile, lineNum, msg, ex.stackTrace(), level >= logLevel_ && fpp_, stdoutField_&level); } void Logger::log (LEVEL level, const char* sourceFile, int lineNum, const std::string& msg, const Exception& ex) { log(level, sourceFile, lineNum, msg.c_str(), ex); } } // namespace aria2