// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" #include "nel/net/module.h" #include "nel/net/module_builder_parts.h" #include "game_share/utils.h" #include "logger_service_client.h" using namespace std; using namespace NLMISC; using namespace NLNET; CVariable VerboseLogger("LGS", "VerboseLogger", "Activate verbose logging in serive output", false, 0, true); extern void forceLinkOfAllLogs(); namespace LGS { class CLoggerServiceClient : public ILoggerServiceClient, public CEmptyModuleServiceBehav > >, IModuleTrackerCb { friend class ILoggerServiceClient; /// A flag stating if the logger comm is started NL_MISC_SAFE_CLASS_GLOBAL(bool, CommStarted, false); // static bool _CommStarted; /// The module proxies of the logger service // set _LoggerServices; typedef CModuleTracker TLoggerServices; TLoggerServices _LoggerServices; typedef map TLogDefinitions; /// The log definitions, stored by log name static CLoggerServiceClient::TLogDefinitions &getLogDefinitions() { static TLogDefinitions logDefinitions; return logDefinitions; } typedef vector TLogInfos; /// the list of log stored during a service loop TLogInfos _LogInfos; /// keep track of the number of open context, must be 0 at end of service loop uint32 _NbOpenContext; public: CLoggerServiceClient() : _LoggerServices(TModuleClassPred("LoggerService")), _NbOpenContext(0) { _LoggerServices.init(this, this); if (getGlobal_CommStarted()) startLoggerComm(); // this call is jsut to make sure ALL log definition are included by // the linker forceLinkOfAllLogs(); } void onModuleUpdate() { if (getGlobal_CommStarted()) { if (_NbOpenContext != 0) { WARN("LoggerClient : there are "<<_NbOpenContext<<" open context not closed !. Logs for this loop will be lost"); // TODO : have a better handling of unpaired log context to not loast all logs _LogInfos.clear(); } else { // send the logs to all known logger services const TLoggerServices::TTrackedModules &loggers = _LoggerServices.getTrackedModules(); TLoggerServices::TTrackedModules::iterator first(loggers.begin()), last(loggers.end()); for (; first != last; ++first) { CLoggerServiceProxy logger(*first); logger.reportLog(this, _LogInfos); } // cleanup accumulated logs _LogInfos.clear(); } } } void registerWithLogger(IModuleProxy *loggerService) { // build a simple vector of log definitions vector logDefs; TLogDefinitions::iterator first(getLogDefinitions().begin()), last(getLogDefinitions().end()); for (; first != last; ++first) { logDefs.push_back(first->second); } // register the client CLoggerServiceProxy logger(loggerService); logger.registerClient(this, IService::getInstance()->getShardId(), logDefs); } /// Add a set of log description static void addLogDefinitions(const std::vector &logDefs) { BOMB_IF(getGlobal_CommStarted(), "Registering of log definition done AFTER comm started !", return); for (uint i=0; isecond.getParams().size() != logInfo.getParams().size(), "sendLog : on log "<second.getParams().size()<<", received "<second; char buffer[1024]; int pos = sprintf(buffer, "LGS : log : %s : %s", ld.getLogName().c_str(), ld.getLogText().c_str()); for (uint i=0; isecond; BOMB_IF(!ld.getContext(), "Push log context with name '"<getTimeStamp() != 0 && it->getLogName() != contextName) ++it; BOMB_IF(it == _LogInfos.rend(), "popLogContext : Can't find opening context", return); // ok, we have found the opening tag if (it == _LogInfos.rbegin()) { // the log context is empty, remove it _LogInfos.pop_back(); } else { // create the log context closing _LogInfos.push_back(TLogInfo()); _LogInfos.back().setLogName(contextName); // tag as 'closing' with ~0 _LogInfos.back().setTimeStamp(~0); } --_NbOpenContext; if (VerboseLogger) { nlinfo("LGS : Close log context '%s'", contextName.c_str()); } } }; NLNET_REGISTER_MODULE_FACTORY(CLoggerServiceClient, "LoggerServiceClient"); /////////////////////////////////////////////////////////////////////////// // Logger service client static member instance /////////////////////////////////////////////////////////////////////////// // bool CLoggerServiceClient::_CommStarted = false; /////////////////////////////////////////////////////////////////////////// // ILogger service client static functions /////////////////////////////////////////////////////////////////////////// /// Add a set of log description void ILoggerServiceClient::addLogDefinitions(const std::vector &logDefs) { CLoggerServiceClient::addLogDefinitions(logDefs); } void ILoggerServiceClient::startLoggerComm() { CLoggerServiceClient::getGlobal_CommStarted() = true; if (CLoggerServiceClient::isInitialized()) { // call the start logger method in the concrete class static_cast(ILoggerServiceClient::getInstance())->startLoggerComm(); } } } // namespace LGS