Added sharedLog and sharedMessageDispatch libraries

This commit is contained in:
Anonymous
2014-01-14 05:51:48 -07:00
parent 765616a540
commit 23bf1cd329
56 changed files with 3985 additions and 0 deletions
@@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 2.8)
project(sharedLog)
if(WIN32)
add_definitions(/D_CRT_SECURE_NO_WARNINGS)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/public)
add_subdirectory(src)
@@ -0,0 +1 @@
#include "../../src/shared/ConfigSharedLog.h"
@@ -0,0 +1 @@
#include "../../src/shared/FileLogObserver.h"
@@ -0,0 +1 @@
#include "../../src/shared/FirstSharedLog.h"
@@ -0,0 +1 @@
#include "../../src/shared/Log.h"
@@ -0,0 +1 @@
#include "../../src/shared/LogManager.h"
@@ -0,0 +1 @@
#include "../../src/shared/LogObserver.h"
@@ -0,0 +1 @@
#include "../../src/shared/NetLogConnection.h"
@@ -0,0 +1 @@
#include "../../src/shared/NetLogObserver.h"
@@ -0,0 +1 @@
#include "../../src/shared/SetupSharedLog.h"
@@ -0,0 +1 @@
#include "../../src/shared/StderrLogger.h"
@@ -0,0 +1 @@
#include "../../src/shared/TailFileLogObserver.h"
@@ -0,0 +1,56 @@
set(SHARED_SOURCES
shared/ConfigSharedLog.cpp
shared/ConfigSharedLog.h
shared/TailFileLogObserver.cpp
shared/TailFileLogObserver.h
shared/FileLogObserver.cpp
shared/FileLogObserver.h
shared/FirstSharedLog.cpp
shared/FirstSharedLog.h
shared/Log.h
shared/LogManager.cpp
shared/LogManager.h
shared/LogObserver.cpp
shared/LogObserver.h
shared/NetLogConnection.cpp
shared/NetLogConnection.h
shared/NetLogObserver.cpp
shared/NetLogObserver.h
shared/SetupSharedLog.cpp
shared/SetupSharedLog.h
shared/StderrLogger.h
)
if(WIN32)
set(PLATFORM_SOURCES
win32/StderrLogger.cpp
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/win32)
else()
set(PLATFORM_SOURCES
linux/StderrLogger.cpp
)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/linux)
endif()
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/shared
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDebug/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMessageDispatch/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetwork/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetworkMessages/include/public
${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedSynchronization/include/public
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/archive/include
${SWG_EXTERNALS_SOURCE_DIR}/ours/library/fileInterface/include/public
)
add_library(sharedLog STATIC
${SHARED_SOURCES}
${PLATFORM_SOURCES}
)
@@ -0,0 +1,74 @@
// ======================================================================
//
// StderrLogger.cpp
//
// Copyright 2003 Sony Online Entertainment
//
// ======================================================================
#include "sharedLog/FirstSharedLog.h"
#include "sharedLog/StderrLogger.h"
#include "sharedLog/Log.h"
#include <string>
#include <fcntl.h>
// ======================================================================
namespace StderrLoggerNamespace
{
bool s_installed;
int s_oldStderr;
int s_stderrPipe[2];
}
using namespace StderrLoggerNamespace;
// ======================================================================
void StderrLogger::install()
{
DEBUG_FATAL(s_installed, ("StderrLogger already installed"));
s_installed = true;
s_oldStderr = dup(2);
pipe(s_stderrPipe);
dup2(s_stderrPipe[1], 2);
fcntl(s_stderrPipe[0], F_SETFL, O_NONBLOCK);
}
// ----------------------------------------------------------------------
void StderrLogger::remove()
{
DEBUG_FATAL(!s_installed, ("StderrLogger not installed"));
dup2(s_oldStderr, 2);
close(s_stderrPipe[0]);
close(s_stderrPipe[1]);
s_installed = false;
}
// ----------------------------------------------------------------------
void StderrLogger::update()
{
if (!s_installed)
return;
char buf[8192];
int nRead = read(s_stderrPipe[0], buf, sizeof(buf)-1);
if (nRead > 0)
{
int startPos = 0;
while (startPos < nRead)
{
int endPos = startPos;
while (buf[endPos] != '\n' && endPos < nRead)
++endPos;
buf[endPos] = 0;
if (endPos > startPos)
LOG("stderr", ("%s", buf+startPos));
startPos = endPos+1;
}
}
}
// ======================================================================
@@ -0,0 +1,114 @@
// ======================================================================
//
// ConfigSharedLog.cpp
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#include "sharedLog/FirstSharedLog.h"
#include "sharedLog/ConfigSharedLog.h"
#include "sharedFoundation/ConfigFile.h"
#include <vector>
// ======================================================================
namespace ConfigSharedLogNamespace
{
typedef std::vector<char const *> StringPtrArray;
int ms_logNetQueueSize;
int ms_logNetReconnectTimeMs;
bool ms_logReportLogs;
bool ms_logReportWarnings;
bool ms_logReportFatals;
bool ms_logStderr;
StringPtrArray ms_logTargets; // ConfigFile owns the pointer
}
using namespace ConfigSharedLogNamespace;
#define KEY_BOOL(a,b) (ms_ ## a = ConfigFile::getKeyBool("SharedLog", #a, b))
#define KEY_INT(a,b) (ms_ ## a = ConfigFile::getKeyInt("SharedLog", #a, b))
// ======================================================================
void ConfigSharedLog::install()
{
KEY_INT (logNetQueueSize, 2000);
KEY_INT (logNetReconnectTimeMs, 10000);
KEY_BOOL(logReportLogs, false);
KEY_BOOL(logReportWarnings, true);
KEY_BOOL(logReportFatals, true);
KEY_BOOL(logStderr, false);
int index = 0;
char const * result = 0;
do
{
result = ConfigFile::getKeyString("SharedLog", "logTarget", index++, 0);
if (result)
ms_logTargets.push_back(result);
}
while (result);
}
// ----------------------------------------------------------------------
int ConfigSharedLog::getLogNetQueueSize()
{
return ms_logNetQueueSize;
}
// ----------------------------------------------------------------------
int ConfigSharedLog::getLogNetReconnectTimeMs()
{
return ms_logNetReconnectTimeMs;
}
// ----------------------------------------------------------------------
bool ConfigSharedLog::getLogReportLogs()
{
return ms_logReportLogs;
}
// ----------------------------------------------------------------------
bool ConfigSharedLog::getLogReportWarnings()
{
return ms_logReportWarnings;
}
// ----------------------------------------------------------------------
bool ConfigSharedLog::getLogReportFatals()
{
return ms_logReportFatals;
}
// ----------------------------------------------------------------------
bool ConfigSharedLog::getLogStderr()
{
return ms_logStderr;
}
// ----------------------------------------------------------------------
int ConfigSharedLog::getNumberOfLogTargets()
{
return static_cast<int>(ms_logTargets.size());
}
// ----------------------------------------------------------------------
char const * ConfigSharedLog::getLogTarget(int const index)
{
VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfLogTargets());
return ms_logTargets[static_cast<size_t>(index)];
}
// ======================================================================
@@ -0,0 +1,32 @@
// ======================================================================
//
// ConfigSharedLog.h
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_ConfigSharedLog_H
#define INCLUDED_ConfigSharedLog_H
// ======================================================================
class ConfigSharedLog
{
public:
static void install();
static int getLogNetQueueSize();
static int getLogNetReconnectTimeMs();
static bool getLogReportLogs();
static bool getLogReportWarnings();
static bool getLogReportFatals();
static bool getLogStderr();
static int getNumberOfLogTargets();
static char const * getLogTarget(int index);
};
// ======================================================================
#endif // INCLUDED_ConfigSharedLog_H
@@ -0,0 +1,122 @@
// ======================================================================
//
// FileLogObserver.cpp
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#include "sharedLog/FirstSharedLog.h"
#include "sharedFoundation/NetworkIdArchive.h"
#include "sharedLog/FileLogObserver.h"
#include "sharedLog/LogManager.h"
#include "fileInterface/StdioFile.h"
#include "sharedNetworkMessages/LogMessage.h"
#include "UnicodeUtils.h"
#include <string>
#include <cstdio>
// ======================================================================
const int LOG_FILESIZE_NEXT = 2000000000; // point at which we roll over to another log file
// ======================================================================
void FileLogObserver::install()
{
LogManager::registerObserverType("file", create);
}
// ----------------------------------------------------------------------
LogObserver *FileLogObserver::create(std::string const &spec)
{
return new FileLogObserver(spec);
}
// ----------------------------------------------------------------------
FileLogObserver::FileLogObserver(std::string const &filename) :
LogObserver(),
m_filename(filename),
m_file(0),
m_fileIndex(0)
{
prepareFile();
}
// ----------------------------------------------------------------------
void FileLogObserver::prepareFile()
{
while (!m_file || m_file->tell() >= LOG_FILESIZE_NEXT)
{
if (m_file)
{
++m_fileIndex;
delete m_file;
m_file = 0;
}
if (m_fileIndex == 0)
m_file = new StdioFile(m_filename.c_str(), "a");
else
{
char buf[512];
IGNORE_RETURN( snprintf(buf, 512, "%s-%d", m_filename.c_str(), m_fileIndex+1) );
m_file = new StdioFile(buf, "a");
}
NOT_NULL(m_file);
FATAL(!m_file->isOpen(), ("Could not open %s", m_filename.c_str()));
}
}
// ----------------------------------------------------------------------
FileLogObserver::~FileLogObserver()
{
delete m_file;
}
// ----------------------------------------------------------------------
void FileLogObserver::log(LogMessage const &msg)
{
prepareFile();
NOT_NULL(m_file);
uint64 timestamp = msg.getTimestamp();
std::string const &procId = msg.getProcId();
std::string const &channel = msg.getChannel();
std::string const &text = msg.getText();
std::string uniAttach(Unicode::wideToNarrow(msg.getUnicodeAttach()));
char tsbuf[16]; // yyyymmddhhmmss (14)
IGNORE_RETURN( sprintf(tsbuf, UINT64_FORMAT_SPECIFIER, timestamp) );
IGNORE_RETURN( m_file->write(14, tsbuf) );
IGNORE_RETURN( m_file->write(1, ":") );
IGNORE_RETURN( m_file->write(static_cast<int>(procId.length()), procId.c_str()) );
IGNORE_RETURN( m_file->write(1, ":") );
IGNORE_RETURN( m_file->write(static_cast<int>(channel.length()), channel.c_str()) );
IGNORE_RETURN( m_file->write(1, ":") );
IGNORE_RETURN( m_file->write(static_cast<int>(text.length()), text.c_str()) );
if (uniAttach.length())
{
IGNORE_RETURN( m_file->write(1, ":") );
IGNORE_RETURN( m_file->write(static_cast<int>(uniAttach.length()), uniAttach.c_str()) );
}
IGNORE_RETURN( m_file->write(1, "\n") );
if (LogManager::getFlushOnWrite())
m_file->flush();
}
// ----------------------------------------------------------------------
void FileLogObserver::flush()
{
if (m_file)
m_file->flush();
}
// ======================================================================
@@ -0,0 +1,52 @@
// ======================================================================
//
// FileLogObserver.h
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_FileLogObserver_H
#define INCLUDED_FileLogObserver_H
// ======================================================================
#include "sharedLog/LogObserver.h"
#include <string>
// ======================================================================
class AbstractFile;
// ======================================================================
// A FileLogObserver saves log messages to a file
class FileLogObserver: public LogObserver
{
public:
static void install();
static LogObserver *create(std::string const &spec);
FileLogObserver(std::string const &filename);
virtual ~FileLogObserver();
virtual void log(LogMessage const &msg);
virtual void flush();
private:
FileLogObserver(FileLogObserver const &);
FileLogObserver &operator=(FileLogObserver const &);
void prepareFile();
private:
std::string m_filename;
AbstractFile *m_file;
int m_fileIndex;
};
// ======================================================================
#endif
@@ -0,0 +1,10 @@
// ======================================================================
//
// FirstSharedLog.cpp
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#include "sharedLog/FirstSharedLog.h"
@@ -0,0 +1,19 @@
// ======================================================================
//
// FirstSharedLog.h
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_FirstSharedLog_H
#define INCLUDED_FirstSharedLog_H
// ======================================================================
#include "sharedFoundation/FirstSharedFoundation.h"
// ======================================================================
#endif
@@ -0,0 +1,39 @@
// ======================================================================
//
// Log.h
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_Log_H
#define INCLUDED_Log_H
// ======================================================================
#include "LogManager.h"
// ======================================================================
// Un-conditional
#define LOG(stream, varArgs) (LogManager::setArgs(stream), LogManager::log varArgs)
#define LOGU(stream, varArgs, unicodeAttach) (LogManager::setArgs(stream, unicodeAttach), LogManager::log varArgs)
// Conditional
#define LOGC(forceLog, stream, varArgs) ((forceLog) ? (LogManager::setArgs(stream), LogManager::log varArgs) : NOP)
#define LOGUC(forceLog, stream, varArgs, unicodeAttach) ((forceLog) ? (LogManager::setArgs(stream, unicodeAttach), LogManager::log varArgs) : NOP)
#ifdef _DEBUG
#define DEBUG_LOG(stream, varArgs) LOG(stream, varArgs)
#define DEBUG_LOGU(stream, varArgs, unicodeAttach) LOGU(stream, varArgs, unicodeAttach)
#else
#define DEBUG_LOG(stream, varArgs) NOP
#define DEBUG_LOGU(stream, varArgs, unicodeAttach) NOP
#endif
// ======================================================================
#endif
@@ -0,0 +1,367 @@
// ======================================================================
//
// LogManager.cpp
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#include "sharedLog/FirstSharedLog.h"
#include "sharedFoundation/NetworkIdArchive.h"
#include "sharedFoundation/ExitChain.h"
#include "sharedFoundation/ConfigFile.h"
#include "sharedLog/LogManager.h"
#include "sharedLog/LogObserver.h"
#include "sharedLog/ConfigSharedLog.h"
#include "sharedLog/StderrLogger.h"
#include "sharedNetworkMessages/LogMessage.h"
#include "sharedSynchronization/RecursiveMutex.h"
#include <list>
#include <map>
#include <string>
#include <cstdio>
#include <time.h>
// ======================================================================
typedef std::list<LogObserver *> ObserverList;
typedef std::map<std::string, LogObserverCreateFunc> ObserverCreateMap;
// ======================================================================
namespace LogManagerNamespace
{
void remove();
const int MaxLogMessageLen = 16384;
struct LogManagerData
{
LogManagerData() :
mutex(),
observers(),
observerCreateMap(),
channel(),
unicodeAttach(),
processIdentifier(),
flushOnWrite(true),
logging(0)
{
}
RecursiveMutex mutex;
ObserverList observers;
ObserverCreateMap observerCreateMap;
std::string channel;
Unicode::String unicodeAttach;
std::string processIdentifier;
bool flushOnWrite;
int logging; // used for catching recursive log attempts from the same thread
private:
LogManagerData(LogManagerData const &);
LogManagerData &operator=(LogManagerData const &);
};
LogManagerData *s_data;
}
using namespace LogManagerNamespace;
// ======================================================================
void LogManager::install(std::string const &procId, bool flushOnWrite)
{
DEBUG_FATAL(s_data, ("LogManager already installed"));
s_data = new LogManagerData;
s_data->processIdentifier = procId;
s_data->flushOnWrite = flushOnWrite;
ExitChain::add(LogManagerNamespace::remove, "LogManagerNamespace::remove");
if (ConfigSharedLog::getLogStderr())
StderrLogger::install();
}
// ----------------------------------------------------------------------
void LogManager::update()
{
if (!s_data)
return;
if (ConfigSharedLog::getLogStderr())
StderrLogger::update();
for (ObserverList::iterator i = s_data->observers.begin(); i != s_data->observers.end(); ++i)
(*i)->update();
}
// ----------------------------------------------------------------------
void LogManagerNamespace::remove()
{
DEBUG_FATAL(!s_data, ("LogManager not installed"));
// we own any observers we have, so delete them
while (!s_data->observers.empty())
{
delete (*s_data->observers.begin());
IGNORE_RETURN( s_data->observers.erase(s_data->observers.begin()) );
}
if (ConfigSharedLog::getLogStderr())
StderrLogger::remove();
delete s_data;
s_data = 0;
}
// ----------------------------------------------------------------------
void LogManager::setProcessIdentifier(std::string const &procId)
{
s_data->processIdentifier = procId;
}
// ----------------------------------------------------------------------
void LogManager::setArgs(std::string const &channel, Unicode::String const &unicodeAttach)
{
if (!s_data)
return;
s_data->mutex.enter(); // leave() called from log which should always follow setArgs
if (s_data->logging == 0)
{
++s_data->logging;
s_data->channel = channel;
s_data->unicodeAttach = unicodeAttach;
}
}
// ----------------------------------------------------------------------
void LogManager::setArgs(std::string const &channel)
{
if (!s_data)
return;
s_data->mutex.enter(); // leave() called from log which should always follow setArgs
++s_data->logging;
if (s_data->logging == 1)
{
s_data->channel = channel;
s_data->unicodeAttach.clear();
}
}
// ----------------------------------------------------------------------
void LogManager::log(char const *format, ...)
{
if (!s_data)
return;
// if noone is observing log messages, no need to process them
if (s_data->observers.size() && s_data->logging == 1)
{
++s_data->logging;
static char text[MaxLogMessageLen];
{
va_list ap;
va_start(ap, format); //lint !e746 !e1055
IGNORE_RETURN( _vsnprintf(text, sizeof(text), format, ap) );
text[sizeof(text)-1] = '\0';
size_t len = strlen(text);
// if string was truncated, stick a + on the end
if (len == sizeof(text)-1)
text[len-1] = '+';
va_end(ap);
}
uint64 timestamp;
{
// format current date/time gmt as yyyymmddhhmmss, in a uint64
time_t now;
tm t;
IGNORE_RETURN( time(&now) );
IGNORE_RETURN( gmtime_r(&now, &t) );
timestamp = t.tm_year+1900; //lint !e732 !e737 !e776
timestamp *= 100;
timestamp += t.tm_mon+1; //lint !e737 !e776
timestamp *= 100;
timestamp += static_cast<unsigned int>(t.tm_mday);
timestamp *= 100;
timestamp += static_cast<unsigned int>(t.tm_hour);
timestamp *= 100;
timestamp += static_cast<unsigned int>(t.tm_min);
timestamp *= 100;
timestamp += static_cast<unsigned int>(t.tm_sec);
}
observeLogMessage(LogMessage(timestamp, s_data->processIdentifier, s_data->channel, text, s_data->unicodeAttach));
--s_data->logging;
}
--s_data->logging;
s_data->mutex.leave(); // enter() called from setArgs which should always precede log
}
// ----------------------------------------------------------------------
void LogManager::observeLogMessage(LogMessage const &msg)
{
for (ObserverList::iterator i = s_data->observers.begin(); i != s_data->observers.end(); ++i)
if (!(*i)->isFiltered(msg))
(*i)->log(msg);
}
// ----------------------------------------------------------------------
void LogManager::addObserver(LogObserver *observer)
{
s_data->observers.push_back(observer);
}
// ----------------------------------------------------------------------
void LogManager::removeObserver(LogObserver const *observer)
{
// we own any observers given to us, so delete it when it is removed
for (ObserverList::iterator i = s_data->observers.begin(); i != s_data->observers.end(); ++i)
{
if ((*i) == observer)
{
delete (*i);
IGNORE_RETURN( s_data->observers.erase(i) );
break;
}
}
}
// ----------------------------------------------------------------------
void LogManager::registerObserverType(std::string const &name, LogObserverCreateFunc func)
{
s_data->observerCreateMap[name] = func;
char buffer[256];
sprintf(buffer, "%s:", name.c_str());
// run through SharedLog keys looking for logTarget=name:
{
int const numberLogTargets = ConfigSharedLog::getNumberOfLogTargets();
for (int i = 0; i < numberLogTargets; ++i)
{
char const * const result = ConfigSharedLog::getLogTarget(i);
if (result && strstr(result, buffer) == result)
{
setupObserver(result);
}
}
}
// run through SharedLog keys looking for logTarget#=name:
{
char key[16];
strcpy(key, "logTarget");
for (int i = 0; i < 20; ++i)
{
char const * result = 0;
sprintf(key+9, "%d", i);
int count = 0;
do
{
result = ConfigFile::getKeyString("SharedLog", key, count, 0);
if (result && strstr(result, buffer) == result)
setupObserver(result);
++count;
} while (result);
}
}
}
// ----------------------------------------------------------------------
bool LogManager::setupObserver(std::string const &desc)
{
REPORT_LOG(true, ("Log observer setup: %s\n", desc.c_str()));
// description should be "type:spec{filter1:filter2:...}"
size_t pos = desc.find(":");
if (pos != std::string::npos)
{
std::string type(desc.substr(0, pos));
std::string spec;
std::string filt;
size_t pos2 = desc.find("{");
if (pos2 == std::string::npos)
spec = desc.substr(pos+1);
else
{
spec = desc.substr(pos+1, (pos2-(pos+1)));
filt = desc.substr(pos2+1);
if (filt.length() && filt[filt.length()-1] == '}')
{
IGNORE_RETURN( filt.erase(filt.length()-1) );
}
}
ObserverCreateMap::iterator i = s_data->observerCreateMap.find(type);
if (i != s_data->observerCreateMap.end())
{
LogObserver *observer = (*(*i).second)(spec);
if (observer)
{
if (filt.length())
observer->setFilter(filt);
addObserver(observer);
return true;
}
}
}
return false;
}
// ----------------------------------------------------------------------
bool LogManager::getFlushOnWrite()
{
return s_data->flushOnWrite;
}
// ----------------------------------------------------------------------
void LogManager::flush()
{
for (ObserverList::iterator i = s_data->observers.begin(); i != s_data->observers.end(); ++i)
(*i)->flush();
}
// ----------------------------------------------------------------------
void LogManager::logLongText(std::string const & channel, std::string const & longText)
{
int const targetLineLength=80;
int const maxLineLength=100;
char buffer[maxLineLength+1];
int pos=0;
for (std::string::const_iterator i=longText.begin(); i!=longText.end(); ++i)
{
buffer[pos++]=*i;
if ((pos>=targetLineLength && *i==' ') || (pos==maxLineLength))
{
buffer[pos]='\0';
setArgs(channel);
log("%s", buffer);
pos=0;
}
}
if (pos!=0)
{
buffer[pos]='\0';
setArgs(channel);
log("%s", buffer);
pos=0;
}
}
// ======================================================================
@@ -0,0 +1,58 @@
// ======================================================================
//
// LogManager.h
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_LogManager_H
#define INCLUDED_LogManager_H
// ======================================================================
class LogMessage;
class LogObserver;
// ======================================================================
// The LogManager is a static class which catches log messages,
// processes them from varArgs into straight ascii text, and passes the
// processed string on to any observers, along with a timestamp,
// process identifier, and any unicode text attached.
typedef LogObserver *(*LogObserverCreateFunc)(std::string const &);
class LogManager
{
public:
static void install(std::string const &procId, bool flushOnWrite = true);
static void update();
static void setProcessIdentifier(std::string const &procId);
// note: setArgs() and log() always come as a pair, and must do so to avoid deadlocks
static void setArgs(std::string const &channel, Unicode::String const &unicodeAttach);
static void setArgs(std::string const &channel);
static void log(char const *format, ...);
static void logLongText(std::string const & channel, std::string const & longText);
static void observeLogMessage(LogMessage const &msg);
static void addObserver(LogObserver *observer);
static void removeObserver(LogObserver const *observer);
static void registerObserverType(std::string const &name, LogObserverCreateFunc func);
static bool setupObserver(std::string const &desc);
static bool getFlushOnWrite();
static void flush();
private:
LogManager();
LogManager(LogManager const &);
LogManager &operator=(LogManager const &);
};
// ======================================================================
#endif
@@ -0,0 +1,111 @@
// ======================================================================
//
// LogObserver.cpp
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#include "sharedLog/FirstSharedLog.h"
#include "sharedFoundation/NetworkIdArchive.h"
#include "sharedLog/LogObserver.h"
#include "sharedNetworkMessages/LogMessage.h"
#include <string>
#include <vector>
// ======================================================================
LogObserver::LogObserver() :
m_filters(new std::vector<std::string>())
{
}
// ----------------------------------------------------------------------
LogObserver::~LogObserver()
{
delete m_filters;
}
// ----------------------------------------------------------------------
void LogObserver::setFilter(std::string const &filter)
{
// filter is a : separated list of filter rules. split them and add
// valid ones to the filter list
m_filters->clear();
size_t curPos = 0;
while (curPos < filter.length())
{
size_t endPos = filter.find(":", curPos);
if (endPos == std::string::npos)
endPos = filter.length()+1;
m_filters->push_back(filter.substr(curPos, endPos-curPos));
curPos = endPos+1;
}
}
// ----------------------------------------------------------------------
bool LogObserver::isFiltered(LogMessage const &msg) const
{
bool filtered = false;
// run through the list of filters comparing them
std::vector<std::string>::const_iterator i;
for (i = m_filters->begin(); i != m_filters->end(); ++i)
{
std::string const &filter = (*i);
std::string const *source = 0;
// source specifier (c or d - channel or data)
if (filter[0] == 'c')
source = &msg.getChannel();
else if (filter[0] == 'd')
source = &msg.getText();
else if (filter[0] == 'p')
source = &msg.getProcId();
else
continue; // invalid source specifier, skip filter
// filter action (+ or -)
bool action = false;
if (filter[1] == '+')
action = false;
else if (filter[1] == '-')
action = true;
else
continue; // invalid action specifier, skip filter
// may be a comparison negation specifier
size_t filterPos = 2;
bool negateCompare = false;
if (filter[2] == '!')
{
++filterPos;
negateCompare = true;
}
bool match;
// either '*' or a substring to search for, may change this to regex
if (filter[filterPos] == '*')
match = true;
else
match = (source->find(filter.c_str()+filterPos) != std::string::npos);
if (negateCompare)
match = !match;
if (match)
filtered = action;
}
return filtered;
}
// ----------------------------------------------------------------------
void LogObserver::flush()
{
}
//------------------------------------------------------------------------------------------
void LogObserver::update()
{
}
// ======================================================================
@@ -0,0 +1,47 @@
// ======================================================================
//
// LogObserver.h
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_LogObserver_H
#define INCLUDED_LogObserver_H
// ======================================================================
class LogMessage;
// ======================================================================
// A LogObserver is derived from in order to provide a mechanism for
// catching log messages and doing something with them. A derived
// observer object must be added to the logManager before it will
// have any effect.
class LogObserver
{
public:
LogObserver();
virtual ~LogObserver();
virtual void log(LogMessage const &msg) = 0;
virtual void flush();
void setFilter(std::string const &filter);
bool isFiltered(LogMessage const &msg) const;
virtual void update();
private:
LogObserver(LogObserver const &);
LogObserver &operator=(LogObserver const &);
stdvector<std::string>::fwd* m_filters;
};
// ======================================================================
#endif
@@ -0,0 +1,69 @@
// ======================================================================
//
// NetLogConnection.cpp
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#include "sharedLog/FirstSharedLog.h"
#include "sharedFoundation/NetworkIdArchive.h"
#include "sharedLog/NetLogObserver.h"
#include "sharedNetwork/NetworkSetupData.h"
#include "NetLogConnection.h"
// ======================================================================
NetLogConnection::NetLogConnection(NetLogObserver *owner) :
Connection(owner->getRemoteAddress(), owner->getRemotePort(), NetworkSetupData()),
m_owner(owner)
{
}
// ----------------------------------------------------------------------
NetLogConnection::~NetLogConnection()
{
if (m_owner)
m_owner->onConnectionDestroyed(this);
m_owner = 0;
}
// ----------------------------------------------------------------------
void NetLogConnection::onConnectionClosed()
{
if (m_owner)
m_owner->onConnectionClosed();
}
// ----------------------------------------------------------------------
void NetLogConnection::onConnectionOpened()
{
if (m_owner)
m_owner->onConnectionOpened();
}
// ----------------------------------------------------------------------
void NetLogConnection::clearOwner()
{
m_owner = 0;
}
// ----------------------------------------------------------------------
void NetLogConnection::onReceive(Archive::ByteStream const &)
{
}
// ----------------------------------------------------------------------
bool NetLogConnection::isNetLogConnection() const
{
return true;
}
// ======================================================================
@@ -0,0 +1,48 @@
// ======================================================================
//
// NetLogConnection.h
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_NetLogConnection_H
#define INCLUDED_NetLogConnection_H
// ======================================================================
#include "sharedNetwork/Connection.h"
// ======================================================================
class NetLogObserver;
// ======================================================================
class NetLogConnection: public Connection
{
public:
explicit NetLogConnection(NetLogObserver *owner);
virtual ~NetLogConnection();
virtual void onConnectionClosed();
virtual void onConnectionOpened();
virtual void onReceive(Archive::ByteStream const &);
void clearOwner();
protected:
virtual bool isNetLogConnection() const;
private:
NetLogConnection();
NetLogConnection(NetLogConnection const &);
NetLogConnection &operator=(NetLogConnection const &);
NetLogObserver *m_owner;
};
// ======================================================================
#endif
@@ -0,0 +1,174 @@
// ======================================================================
//
// NetLogObserver.cpp
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#include "sharedLog/FirstSharedLog.h"
#include "sharedLog/NetLogObserver.h"
#include "sharedFoundation/Clock.h"
#include "sharedFoundation/NetworkIdArchive.h"
#include "sharedLog/LogManager.h"
#include "sharedLog/ConfigSharedLog.h"
#include "sharedNetworkMessages/GameNetworkMessage.h"
#include "sharedNetworkMessages/LogMessage.h"
#include "Archive/ByteStream.h"
#include "NetLogConnection.h"
#include <string>
#include <vector>
// ======================================================================
void NetLogObserver::install()
{
LogManager::registerObserverType("net", create);
}
// ----------------------------------------------------------------------
LogObserver *NetLogObserver::create(std::string const &spec)
{
// parse spec into address:port
size_t pos = spec.find(":");
if (pos != std::string::npos)
{
std::string address = spec.substr(0, pos);
unsigned short port = static_cast<unsigned short>(atoi(spec.c_str()+pos+1));
// create a NetLogObserver to forward to the specified address/port
return new NetLogObserver(address, port);
}
return 0;
}
// ----------------------------------------------------------------------
NetLogObserver::NetLogObserver(const std::string &remoteAddress, unsigned short remotePort) :
LogObserver(),
m_mutex(),
m_remoteAddress(remoteAddress),
m_remotePort(remotePort),
m_connection(0),
m_connectionOpen(false),
m_connectTime(0),
m_logMessageQueue1(new std::vector<LogMessage>),
m_logMessageQueue2(new std::vector<LogMessage>)
{
}
// ----------------------------------------------------------------------
NetLogObserver::~NetLogObserver()
{
delete m_logMessageQueue1;
delete m_logMessageQueue2;
m_logMessageQueue1 = 0;
m_logMessageQueue2 = 0;
// the observer owns the connection
if (m_connection)
{
m_connection->clearOwner();
m_connection->setDisconnectReason("NetLogObserver destroyed");
m_connection->disconnect();
m_connection = 0;
}
}
// ----------------------------------------------------------------------
void NetLogObserver::onConnectionOpened()
{
m_connectionOpen = true;
}
// ----------------------------------------------------------------------
void NetLogObserver::onConnectionClosed()
{
m_connectionOpen = false;
if (m_connection)
{
m_connection->clearOwner();
m_connection = 0;
}
}
// ----------------------------------------------------------------------
void NetLogObserver::onConnectionDestroyed(NetLogConnection *connection)
{
if (m_connection == connection)
m_connection = 0;
}
// ----------------------------------------------------------------------
void NetLogObserver::sendLogMessage(LogMessage const &msg) const
{
if (m_connection)
{
Archive::ByteStream a;
a.clear();
msg.pack(a);
m_connection->send(a, true);
}
}
// ----------------------------------------------------------------------
void NetLogObserver::log(LogMessage const &msg)
{
static unsigned int logNetQueueSize = static_cast<unsigned int>(ConfigSharedLog::getLogNetQueueSize());
if (logNetQueueSize)
{
m_mutex.enter();
if (m_logMessageQueue1->size() < logNetQueueSize)
m_logMessageQueue1->push_back(msg);
m_mutex.leave();
}
}
//------------------------------------------------------------------------------------------
void NetLogObserver::update()
{
static unsigned long reconnectTime = static_cast<unsigned long>(ConfigSharedLog::getLogNetReconnectTimeMs());
if (m_connection && m_connectionOpen)
{
m_mutex.enter();
std::vector<LogMessage> *q = m_logMessageQueue1;
m_logMessageQueue1 = m_logMessageQueue2;
m_logMessageQueue2 = q;
m_mutex.leave();
// send any queued up log messages
for (std::vector<LogMessage>::const_iterator i = m_logMessageQueue2->begin(); i != m_logMessageQueue2->end(); ++i)
sendLogMessage(*i);
m_logMessageQueue2->clear();
}
else if (Clock::timeMs()-m_connectTime > reconnectTime)
connect();
}
// ----------------------------------------------------------------------
void NetLogObserver::connect()
{
if (m_connection)
{
m_connection->clearOwner();
m_connection->setDisconnectReason("About to connect again");
m_connection->disconnect();
m_connection = 0;
}
m_connectTime = Clock::timeMs();
m_connection = new NetLogConnection(this);
}
// ======================================================================
@@ -0,0 +1,80 @@
// ======================================================================
//
// NetLogObserver.h
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_NetLogObserver_H
#define INCLUDED_NetLogObserver_H
// ======================================================================
#include "sharedLog/LogObserver.h"
#include "sharedSynchronization/Mutex.h"
#include <string>
// ======================================================================
class NetLogConnection;
// ======================================================================
// A NetLogObserver sends log messages to a another process
class NetLogObserver: public LogObserver
{
public:
static void install();
static LogObserver *create(std::string const &spec);
NetLogObserver(std::string const &remoteAddress, unsigned short remotePort);
virtual ~NetLogObserver();
virtual void log(LogMessage const &msg);
virtual void onConnectionOpened();
virtual void onConnectionClosed();
virtual void onConnectionDestroyed(NetLogConnection *connection);
virtual void update();
std::string const &getRemoteAddress() const;
unsigned short getRemotePort() const;
private:
NetLogObserver();
NetLogObserver(NetLogObserver const &);
NetLogObserver &operator=(NetLogObserver const &);
void connect();
void sendLogMessage(LogMessage const &msg) const;
Mutex m_mutex;
std::string m_remoteAddress;
unsigned short m_remotePort;
NetLogConnection * m_connection;
bool m_connectionOpen;
unsigned long m_connectTime;
stdvector<LogMessage>::fwd* m_logMessageQueue1;
stdvector<LogMessage>::fwd* m_logMessageQueue2;
};
// ======================================================================
inline std::string const &NetLogObserver::getRemoteAddress() const
{
return m_remoteAddress;
}
// ----------------------------------------------------------------------
inline unsigned short NetLogObserver::getRemotePort() const
{
return m_remotePort;
}
// ======================================================================
#endif
@@ -0,0 +1,92 @@
// ======================================================================
//
// SetupSharedLog.cpp
//
// Copyright 2002-2003 Sony Online Entertainment
// All Rights Reserved.
//
// ======================================================================
#include "sharedLog/FirstSharedLog.h"
#include "sharedLog/SetupSharedLog.h"
#include "sharedDebug/InstallTimer.h"
#include "sharedFoundation/ExitChain.h"
#include "sharedLog/ConfigSharedLog.h"
#include "sharedLog/FileLogObserver.h"
#include "sharedLog/NetLogObserver.h"
#include "sharedLog/LogManager.h"
#include "sharedLog/Log.h"
#include "sharedLog/TailFileLogObserver.h"
// ======================================================================
namespace SetupSharedLogNamespace
{
void logReportLog(char const *message);
void logReportWarning(char const *message);
void logReportFatal(char const *message);
bool ms_installed;
std::string const cms_reportLogChannel("reportLog");
std::string const cms_reportWarningChannel("warning");
std::string const cms_reportFatalChannel("fatal");
}
using namespace SetupSharedLogNamespace;
// ======================================================================
void SetupSharedLogNamespace::logReportLog(char const *message)
{
LOG(cms_reportLogChannel, ("%s", message));
}
// ----------------------------------------------------------------------
void SetupSharedLogNamespace::logReportWarning(char const *message)
{
LOG(cms_reportWarningChannel, ("%s", message));
}
// ----------------------------------------------------------------------
void SetupSharedLogNamespace::logReportFatal(char const *message)
{
LOG(cms_reportFatalChannel, ("%s", message));
}
// ======================================================================
void SetupSharedLog::install(std::string const &procId, bool flushOnWrite)
{
InstallTimer const installTimer("SetupSharedLog::install");
DEBUG_FATAL (ms_installed, ("SetupSharedLog::install already installed"));
ms_installed = true;
ConfigSharedLog::install();
LogManager::install(procId, flushOnWrite);
FileLogObserver::install();
NetLogObserver::install();
TailFileLogObserver::install();
if (ConfigSharedLog::getLogReportLogs())
Report::bindLogCallback(logReportLog);
if (ConfigSharedLog::getLogReportWarnings())
Report::bindWarningCallback(logReportWarning);
if (ConfigSharedLog::getLogReportFatals())
Report::bindFatalCallback(logReportFatal);
}
// ----------------------------------------------------------------------
void SetupSharedLog::remove()
{
DEBUG_FATAL (!ms_installed, ("SetupSharedLog::remove not installed"));
ms_installed = false;
}
// ======================================================================
@@ -0,0 +1,31 @@
// ======================================================================
//
// SetupSharedLog.h
//
// Copyright 2002-2003 Sony Online Entertainment
// All Rights Reserved.
//
// ======================================================================
#ifndef INCLUDED_SetupSharedLog_H
#define INCLUDED_SetupSharedLog_H
// ======================================================================
class SetupSharedLog
{
public:
static void install(std::string const &procId, bool flushOnWrite = true);
static void remove();
private:
SetupSharedLog(SetupSharedLog const &);
SetupSharedLog &operator=(SetupSharedLog const &);
};
// ======================================================================
#endif
@@ -0,0 +1,26 @@
// ======================================================================
//
// StderrLogger.h
//
// Copyright 2003 Sony Online Entertainment
//
// ======================================================================
#ifndef _StderrLogger_H_
#define _StderrLogger_H_
// ======================================================================
class StderrLogger
{
public:
static void install();
static void remove();
static void update();
};
// ======================================================================
#endif // _StderrLogger_H_
@@ -0,0 +1,188 @@
// ======================================================================
//
// TailFileLogObserver.cpp
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#include "sharedLog/FirstSharedLog.h"
#include "sharedFoundation/NetworkIdArchive.h"
#include "sharedLog/TailFileLogObserver.h"
#include "sharedLog/LogManager.h"
#include "fileInterface/StdioFile.h"
#include "sharedNetworkMessages/LogMessage.h"
#include "UnicodeUtils.h"
#include <string>
#include <cstdio>
// ======================================================================
const int LOG_FILESIZE_NEXT = 2000000000; // point at which we roll over to another log file
const int DEFAULT_NUM_LINES = 100;
namespace TailFileLogObserverNamespace
{
std::vector<TailFileLogObserver *> s_tailFileLogObservers;
};
using namespace TailFileLogObserverNamespace;
// ======================================================================
void TailFileLogObserver::install()
{
LogManager::registerObserverType("tailfile", create);
}
// ----------------------------------------------------------------------
LogObserver *TailFileLogObserver::create(std::string const &spec)
{
return new TailFileLogObserver(spec);
}
// ----------------------------------------------------------------------
TailFileLogObserver::TailFileLogObserver(std::string const &filename) :
LogObserver(),
m_filename(filename),
m_file(0),
m_fileIndex(0),
m_numLines(DEFAULT_NUM_LINES),
m_textBuffer(0),
m_nextTextBufferEntry(0)
{
int filenameAsNumber = -1;
filenameAsNumber = atoi(m_filename.c_str());
m_numLines = filenameAsNumber;
std::string::size_type const index = filename.find_last_of(',');
if(index != std::string::npos)
m_filename = filename.substr(index + 1, filename.length());
else
m_filename.clear();
m_textBuffer = new std::vector<std::string>(m_numLines);
s_tailFileLogObservers.push_back(this);
}
// ----------------------------------------------------------------------
void TailFileLogObserver::setNumberOfLinesToKeep(int numLines)
{
m_numLines = numLines;
m_textBuffer->clear();
m_nextTextBufferEntry = 0;
m_textBuffer->reserve(m_numLines);
}
// ----------------------------------------------------------------------
void TailFileLogObserver::prepareFile()
{
while (!m_file || m_file->tell() >= LOG_FILESIZE_NEXT)
{
if (m_file)
{
++m_fileIndex;
delete m_file;
m_file = 0;
}
if (m_fileIndex == 0)
m_file = new StdioFile(m_filename.c_str(), "a");
else
{
char buf[512];
IGNORE_RETURN( snprintf(buf, 512, "%s-%d", m_filename.c_str(), m_fileIndex+1) );
m_file = new StdioFile(buf, "a");
}
NOT_NULL(m_file);
FATAL(!m_file->isOpen(), ("Could not open %s", m_filename.c_str()));
}
}
// ----------------------------------------------------------------------
TailFileLogObserver::~TailFileLogObserver()
{
delete m_file;
delete m_textBuffer;
}
// ----------------------------------------------------------------------
void TailFileLogObserver::log(LogMessage const &msg)
{
std::string & newLogMessage = (*m_textBuffer)[m_nextTextBufferEntry++];
uint64 timestamp = msg.getTimestamp();
std::string const &procId = msg.getProcId();
std::string const &channel = msg.getChannel();
std::string const &text = msg.getText();
std::string uniAttach(Unicode::wideToNarrow(msg.getUnicodeAttach()));
char tsbuf[16]; // yyyymmddhhmmss (14)
newLogMessage.clear();
IGNORE_RETURN( sprintf(tsbuf, UINT64_FORMAT_SPECIFIER, timestamp) );
newLogMessage.append(tsbuf);
newLogMessage.append(":");
newLogMessage.append(procId);
newLogMessage.append(":");
newLogMessage.append(channel);
newLogMessage.append(":");
newLogMessage.append(text);
if(uniAttach.length())
{
newLogMessage.append(":");
newLogMessage.append(uniAttach);
}
if(m_nextTextBufferEntry >= m_numLines)
m_nextTextBufferEntry = 0;
}
// ----------------------------------------------------------------------
void TailFileLogObserver::flush(const char * filename)
{
if(m_filename.empty())
m_filename = filename;
prepareFile();
NOT_NULL(m_file);
int i;
for(i = m_nextTextBufferEntry; i < m_numLines; ++i)
{
if(!(*m_textBuffer)[i].empty())
{
IGNORE_RETURN(m_file->write((*m_textBuffer)[i].length(), (*m_textBuffer)[i].c_str()) );
}
}
for(i = 0; i < m_nextTextBufferEntry; ++i)
{
if(!(*m_textBuffer)[i].empty())
{
IGNORE_RETURN(m_file->write((*m_textBuffer)[i].length(), (*m_textBuffer)[i].c_str()) );
}
}
if (m_file)
m_file->flush();
m_file->close();
}
// ----------------------------------------------------------------------
void TailFileLogObserver::flushAllTailFileLogObservers(const char * filename)
{
for(std::vector<TailFileLogObserver *>::iterator i = s_tailFileLogObservers.begin(); i != s_tailFileLogObservers.end(); ++i)
{
TailFileLogObserver *tflo = *i;
if(tflo)
{
tflo->flush(filename);
}
}
}
// ======================================================================
@@ -0,0 +1,61 @@
// ======================================================================
//
// TailFileLogObserver.h
//
// Copyright 2002 Sony Online Entertainment
//
// ======================================================================
#ifndef INCLUDED_TailFileLogObserver_H
#define INCLUDED_TailFileLogObserver_H
// ======================================================================
#include "sharedLog/LogObserver.h"
#include <string>
// ======================================================================
class AbstractFile;
// ======================================================================
// A TailFileLogObserver saves log messages to a file, but only the last N,
// and only when requested (not constantly).
class TailFileLogObserver: public LogObserver
{
public:
static void install();
static LogObserver *create(std::string const &spec);
TailFileLogObserver(std::string const &filename);
virtual ~TailFileLogObserver();
virtual void log(LogMessage const &msg);
virtual void flush(const char * filename);
virtual void setNumberOfLinesToKeep(int numLines);
static void flushAllTailFileLogObservers(const char *filename);
private:
TailFileLogObserver(TailFileLogObserver const &);
TailFileLogObserver &operator=(TailFileLogObserver const &);
void prepareFile();
private:
std::string m_filename;
AbstractFile *m_file;
int m_fileIndex;
int m_numLines;
stdvector<std::string>::fwd *m_textBuffer;
int m_nextTextBufferEntry;
};
// ======================================================================
#endif
@@ -0,0 +1,35 @@
// ======================================================================
//
// StderrLogger.cpp
//
// Copyright 2003 Sony Online Entertainment
//
// ======================================================================
#include "sharedLog/FirstSharedLog.h"
#include "sharedLog/StderrLogger.h"
// ======================================================================
// Unimplemented for win32
// ======================================================================
void StderrLogger::install()
{
}
// ----------------------------------------------------------------------
void StderrLogger::remove()
{
}
// ----------------------------------------------------------------------
void StderrLogger::update()
{
}
// ======================================================================