// 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