/* * 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 Core::String &message, const Core::String &source) { if(!(level == LOG_CRITICAL && source.isEmpty())) {// 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 Core::String &message, const Core::String &source) { if(source.isEmpty()) std::cerr << message << std::endl; else std::cerr << message << " from " << source << std::endl; } LogManager::MessageLevel LogManager::parseLevel(const String &str) throw (Exception) { static const String DEBUG_LEVEL("debug"); static const String VERBOSE_LEVEL("verbose"); static const String DEFAULT_LEVEL("default"); static const String WARNING_LEVEL("warning"); static const String ERROR_LEVEL("error"); static const String CRITICAL_LEVEL("critical"); if(str.isEmpty()) return Logger::LOG_DEFAULT; if(str.matches(DEBUG_LEVEL)) return Logger::LOG_DEBUG; else if(str.matches(VERBOSE_LEVEL)) return Logger::LOG_VERBOSE; else if(str.matches(DEFAULT_LEVEL)) return Logger::LOG_DEFAULT; else if(str.matches(WARNING_LEVEL)) return Logger::LOG_WARNING; else if(str.matches(ERROR_LEVEL)) return Logger::LOG_ERROR; else if(str.matches(CRITICAL_LEVEL)) 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); } void LogManager::configure() { std::vector entries = application->getConfigManager()->getEntries("Log"); for(std::vector::iterator entry = entries.begin(); entry != entries.end(); ++entry) { const std::vector &values = (*entry)->getValues(); if(values.empty() || !values.front().matches("Console")) continue; registerLogger(consoleLogger); bool remote = false; for(std::vector::const_iterator value = values.begin()+1; value != values.end(); ++value) { if(value->matches("remote")) remote = true; } String level = (*entry)->get("Level"); if(!level.isEmpty()) { try { if(remote) consoleLogger->setRemoteLevel(parseLevel(level)); else consoleLogger->setLevel(parseLevel(level)); } catch(Core::Exception e) { application->log(Logger::LOG_WARNING, Format("Unknown log level '%1%'.") % level); } } } 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 Core::String &message, const Core::String &source) { if(level == Logger::LOG_CRITICAL && source.isEmpty()) 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) { (*logger)->log(message.category, message.level, message.timestamp, message.message, message.source); } } lock.lock(); } } } } }