/* */ #include "Logger.h" #include #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), consoleLogLevel_(Logger::A2_NOTICE), consoleOutput_(true), useColor_(global::cout()->supportsColor()) {} 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::setConsoleOutput(bool enabled) { consoleOutput_ = enabled; } bool Logger::fileLogEnabled(LEVEL level) { return level >= logLevel_ && fpp_; } bool Logger::consoleLogEnabled(LEVEL level) { return consoleOutput_ && level >= consoleLogLevel_; } bool Logger::levelEnabled(LEVEL level) { return fileLogEnabled(level) || consoleLogEnabled(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, nullptr); 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: return "\033[1;37m"; case Logger::A2_INFO: return "\033[1;36m"; 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) { struct timeval tv; gettimeofday(&tv, nullptr); char datestr[15]; // 'MM/DD hh:mm:ss'+'\0' = 15 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), "%m/%d %H:%M:%S", &tm); assert(dateLength <= (size_t)15); if(useColor) { fp.printf("%s [%s%s\033[0m] ", datestr, levelColor(level), levelToString(level)); } else { fp.printf("%s [%s] ", datestr, levelToString(level)); } } } // namespace namespace { template void writeStackTrace(Output& fp, const char* stackTrace) { fp.write(stackTrace); } } // namespace void Logger::writeLog (Logger::LEVEL level, const char* sourceFile, int lineNum, const char* msg, const char* trace) { if(fileLogEnabled(level)) { writeHeader(*fpp_, level, sourceFile, lineNum); fpp_->printf("%s\n", msg); writeStackTrace(*fpp_, trace); fpp_->flush(); } if(consoleLogEnabled(level)) { 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, ""); } 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().c_str()); } 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