/* * LogManager.cpp * * Copyright (C) 2008 Matthias Schiffer * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along * with this program. If not, see . */ #include "LogManager.h" #include "Application.h" #include "ConfigEntry.h" #include "ConfigManager.h" #include namespace Mad { namespace Core { void LogManager::ConsoleLogger::logMessage(MessageCategory category, MessageLevel level, boost::posix_time::ptime timestamp, const std::string &message, const std::string &source) { if(!(level == LOG_CRITICAL && source.empty())) {// Critical messages are printed to cerr directly, so don't print them a second time boost::lock_guard lock(cerrMutex); logMessageDirect(category, level, timestamp, message, source); } } void LogManager::ConsoleLogger::logMessageDirect(MessageCategory /*category*/, MessageLevel /*level*/, boost::posix_time::ptime /*timestamp*/, const std::string &message, const std::string &source) { if(source.empty()) std::cerr << message << std::endl; else std::cerr << message << " from " << source << std::endl; } LogManager::MessageLevel LogManager::parseLevel(const std::string &str) throw (Exception) { if(str.empty()) return Logger::LOG_DEFAULT; std::string lowerStr = boost::algorithm::to_lower_copy(str); if(lowerStr == "debug") return Logger::LOG_DEBUG; else if(lowerStr == "verbose") return Logger::LOG_VERBOSE; else if(lowerStr == "default") return Logger::LOG_DEFAULT; else if(lowerStr == "warning") return Logger::LOG_WARNING; else if(lowerStr == "error") return Logger::LOG_ERROR; else if(lowerStr == "critical") return Logger::LOG_CRITICAL; else throw Exception(Exception::INVALID_INPUT); } LogManager::LogManager(Application *application0) : application(application0), consoleLogger(new ConsoleLogger), configured(false), running(false) { application->getConfigManager()->registerConfigurable(this); } LogManager::~LogManager() { application->getConfigManager()->unregisterConfigurable(this); } bool LogManager::handleConfigEntry(const ConfigEntry &entry, bool handled) { if(entry[0].getKey().matches("Log")) { if(entry[0][0].matches("Console")) { if(entry[1].empty()) { registerLogger(consoleLogger); return true; } else if(entry[1].getKey().matches("Level")) { if(entry[2].empty()) { try { consoleLogger->setLevel(parseLevel(entry[1][0])); } catch(Core::Exception e) { application->logf(Logger::LOG_WARNING, "Unknown log level '%s'.", entry[1][0].c_str()); } return true; } } } else if(entry[1].empty()) { if(!handled) { application->logf(Logger::LOG_WARNING, "Unknown logger '%s'.", entry[0][0].c_str()); return true; } } } return false; } void LogManager::configFinished() { if(loggers.empty()) registerLogger(consoleLogger); boost::lock_guard lock(queueMutex); configured = true; queueCond.notify_one(); } void LogManager::log(MessageCategory category, MessageLevel level, boost::posix_time::ptime timestamp, const std::string &message, const std::string &source) { if(level == Logger::LOG_CRITICAL && source.empty()) consoleLogger->logMessageDirect(category, level, timestamp, message, source); boost::lock_guard lock(queueMutex); Message m = {category, level, timestamp, message, source}; messageQueue.push(m); queueCond.notify_one(); } void LogManager::loggerThread() { boost::unique_lock lock(queueMutex); running = true; while(running) { while(running && ((messageQueue.empty() && messageQueue.empty()) || !configured)) queueCond.wait(lock); while(!messageQueue.empty()) { Message message = messageQueue.front(); messageQueue.pop(); lock.unlock(); { boost::lock_guard loggerLock(loggerMutex); for(std::set >::iterator logger = loggers.begin(); logger != loggers.end(); ++logger) { if((*logger)->getLevel() >= message.level && (*logger)->isCategorySet(message.category)) (*logger)->logMessage(message.category, message.level, message.timestamp, message.message, message.source); } } lock.lock(); } } } } }