From: Markus R. <rol...@us...> - 2005-12-05 21:01:53
|
Update of /cvsroot/simspark/simspark/spark/zeitgeist/logserver In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10883 Added Files: logserver.cpp logserver.h logserver_c.cpp logserverstreambuf.cpp logserverstreambuf.h Log Message: --- NEW FILE: logserverstreambuf.h --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of rcssserver3D Fri May 9 2003 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group $Id: logserverstreambuf.h,v 1.1 2005/12/05 21:01:39 rollmark Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef ZEITGEIST_LOGSERVERSTREAMBUF_H #define ZEITGEIST_LOGSERVERSTREAMBUF_H /*! \class LogServerStreamBuf $Id: logserverstreambuf.h,v 1.1 2005/12/05 21:01:39 rollmark Exp $ ForwarderStreamBuf The ForwarderStreamBuf is a special std::streambuf derived class, which can stream to a list of streams. In addition to the multiplexing functionality this class also supports priorization of streamed data. Every registered stream is associated with a priority mask. This is a bitfield mask which tells the system which kind of messages should be muxed to a particular stream. The ForwarderStreamBuf also manages the current priority level to be used for incoming data. If the state is changed, the buffers are flushed! HISTORY: The forwarder subsystem was taken from a student project at the AI Research Group, Koblenz University. Original development by Marco Koegler <ko...@un...>, Marcus Rollmann <rol...@un...>, Alexander Fuchs <al...@un...>, et.al. It was built into the rcssserver3D, and then converted back into the diploma thesis of Marco Koegler, which was the base for rcssserver3D. */ #include <functional> #include <vector> #include <streambuf> namespace zeitgeist { class LogServerStreamBuf : public std::streambuf { // types // protected: typedef std::char_traits<char> TTraitsType; typedef traits_type::int_type TIntType; private: typedef std::pair<unsigned int, std::ostream*> TMaskStream; typedef std::vector<TMaskStream> TMaskStreams; // functions // public: LogServerStreamBuf(unsigned int size); virtual ~LogServerStreamBuf(); /*! Add a stream to the list of streams. First, it is checked if the stream is already in. If the stream is found, we only add a new priority mask to the existing ones, so no stream can be added twice. @param stream the stream to add @param mask the (new) priority mask for the stream */ void AddStream(std::ostream *stream, unsigned int mask); /*! Remove a stream from the list of streams. @param stream the stream to remove @return true if the stream was found (and thus removed) */ bool RemoveStream(const std::ostream *stream); /*! Set priority mask of a stream in the list. @param stream the stream for which we want to set the priority mask @param mask the new priority mask @return true if the stream was found */ bool SetPriorityMask(const std::ostream *stream, unsigned int mask); /*! Get priority mask of a stream in the list. @param stream the stream for which we want to set the priority mask @return the priority mask; 0 if stream was not found */ unsigned int GetPriorityMask(const std::ostream *stream) const; /*! Set the current priority level. All data which is streamed into the forwarder after this point will use the current priority level. Before the priority level is adjusted, all buffered data is flushed. @param priority current priority level (see EPriorityLevel) */ void SetCurrentPriority(unsigned int priority); protected: // these functions implement the streambuf interface ... handle with care TIntType overflow(TIntType c); int sync(); private: LogServerStreamBuf(const LogServerStreamBuf &obj); LogServerStreamBuf& operator=(const LogServerStreamBuf &obj); //! multiplex to all registered streams void Forward(const char *buffer, unsigned int length); //! stream out complete internal buffer void PutBuffer(); //! stream out a single character void PutChar(TIntType chr); //! A predicate to compare streams in a MaskStream list (or vector). class MaskStreamEQ : public std::unary_function<TMaskStream, bool> { private: const std::ostream *stream; public: explicit MaskStreamEQ(const std::ostream *str) : stream(str) {} bool operator ()(const TMaskStream &ms) { return ms.second == stream; } }; // members // private: //! size of the internal buffer to use unsigned int mSize; unsigned int mCurrentPriority; TMaskStreams mStreams; }; } //namespace #endif // ZEITGEIST_LOGSERVERSTREAMBUF_H --- NEW FILE: logserverstreambuf.cpp --- #include <algorithm> #include <iostream> #include "logserverstreambuf.h" using namespace std; using namespace zeitgeist; LogServerStreamBuf::LogServerStreamBuf(unsigned int size) : streambuf(), mSize(size), mCurrentPriority(0xffffffff) { // Here we set up the 'put' area, where data is streamed in if (mSize) { char* ptr = new char[mSize]; setp(ptr, ptr + mSize); } else { setp(0, 0); } // we don't support a 'get' area ... no istream support setg(0, 0, 0); } LogServerStreamBuf::~LogServerStreamBuf() { // flush buffer sync(); // delete mask-stream elements. The streams will not be deleted. while (mStreams.size() != 0) { if (mStreams.back().second != &std::cout && mStreams.back().second != &std::cerr) delete mStreams.back().second; mStreams.pop_back(); } // delete buffer delete[] pbase(); } void LogServerStreamBuf::AddStream(std::ostream *stream, unsigned int mask) { TMaskStreams::iterator i; i = find_if(mStreams.begin(), mStreams.end(), MaskStreamEQ(stream)); if (i == mStreams.end()) { TMaskStream pstream(mask, stream); mStreams.push_back(pstream); } else { i->first |= mask; } } bool LogServerStreamBuf::RemoveStream(const std::ostream *stream) { // flush buffer sync(); TMaskStreams::iterator i; i = find_if(mStreams.begin(), mStreams.end(), MaskStreamEQ(stream)); if (i != mStreams.end()) { mStreams.erase(i); return true; } return false; } bool LogServerStreamBuf::SetPriorityMask(const std::ostream *stream, unsigned int mask) { // flush buffer sync(); TMaskStreams::iterator i; i = find_if(mStreams.begin(), mStreams.end(), MaskStreamEQ(stream)); if (i != mStreams.end()) { i->first = mask; return true; } return false; } unsigned int LogServerStreamBuf::GetPriorityMask(const std::ostream *stream) const { TMaskStreams::const_iterator i; i = find_if(mStreams.begin(), mStreams.end(), MaskStreamEQ(stream)); if (i != mStreams.end()) { return i->first; } return 0; } void LogServerStreamBuf::SetCurrentPriority(unsigned int priority) { sync(); mCurrentPriority = priority; } /*! This routine is called by the iostream library if our internal buffer is overflowing (the put area is full). */ LogServerStreamBuf::TIntType LogServerStreamBuf::overflow(TIntType c) { // write out the buffered content PutBuffer(); // handle the extra character if it isn't eof if (c != TTraitsType::eof()) { // if we don't do buffering if (pbase() == epptr()) { // write out the character directly PutChar(c); } else { // buffer it sputc(c); } } return 0; } /*! This routine synchronizes the internal state with the external state. It is used to flush the streambuf object. */ int LogServerStreamBuf::sync() { PutBuffer(); return 0; } void LogServerStreamBuf::Forward(const char *buffer, unsigned int length) { TMaskStreams::iterator i; for (i=mStreams.begin(); i!= mStreams.end(); ++i) { if ((*i).first & mCurrentPriority) { (*i).second->write(buffer, length); } } } void LogServerStreamBuf::PutBuffer() { // if we have data to stream out if (pbase() != pptr()) { int len = (pptr() - pbase()); // pbase() = buffer address Forward(pbase(), len); // reset pointers == put area is empty setp(pbase(), epptr()); } } void LogServerStreamBuf::PutChar(TIntType chr) { char a[1]; a[0] = chr; Forward(a, 1); } --- NEW FILE: logserver.h --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of rcssserver3D Fri May 9 2003 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group $Id: logserver.h,v 1.1 2005/12/05 21:01:39 rollmark Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. LogServer HISTORY: 22.08.2002 MK - initial version - reclaimed from rcssserver3D :) */ #ifndef ZEITGEIST_LOGSERVER_H #define ZEITGEIST_LOGSERVER_H #include <iostream> #include "../node.h" namespace zeitgeist { class LogServerStreamBuf; /** The log server is responsible for holding a bunch of ostreams, which data can be streamed to. It is THE logging facility used within zeitgeist. */ class LogServer : public Node , public std::ostream { // types // public: /** defines different priority levels assigned to a log message. The values are designed as a bitmap and can be combined, to trigger different filters */ enum EPriorityLevel { eNone = 0, eDebug = 1, eNormal = 2, eWarning = 4, eError = 8, eAll = 0xffffffff }; // // functions // public: /** constructs a logserver with a an internal stream buffer of size */ LogServer(unsigned int size = 1024); virtual ~LogServer(); /** adds a stream to the list of streams. First, it is checked if the stream is already in. If the stream is found, we only install a new priority mask, so no stream can be added twice. @param stream the stream to add @param mask the (new) priority mask for the stream */ void AddStream(std::ostream *stream, unsigned int mask = eAll); /** removes a stream from the list of streams. @param stream the stream to remove @return true if the stream was found (and thus removed) */ bool RemoveStream(const std::ostream *stream); /** sets the priority mask of a stream in the list. @param stream the stream for which we want to set the priority mask @param mask the new priority mask @return true if the stream was found */ bool SetPriorityMask(const std::ostream *stream, unsigned int mask); /** gets priority mask of a stream in the list. @param stream the stream for which we want to set the priority mask @return the priority mask; 0 if stream was not found */ unsigned int GetPriorityMask(const std::ostream *stream) const; /** selects the priority for the messages to be written. It returns a reference to this logserver instance, allowing multiple priority changes in one stream expression, e.g. log << Priority(eNormal) << "normal msg" << Priority(eDbug) << "debug msg" */ LogServer& Priority(unsigned int prio); /** selects the debug priority and returns a reference to this logserver */ LogServer& Debug() { return Priority(eDebug); } /** selects the normal priority and returns a reference to this logserver */ LogServer& Normal() { return Priority(eNormal); } /** selects the warning priority and returns a reference to this logserver */ LogServer& Warning() { return Priority(eWarning); } /** selects the error priority and returns a reference to this logserver */ LogServer& Error() { return Priority(eError); } /** provides an printf-style interface. */ void Printf(const char *inFormat, ...); private: LogServer(const LogServer& obj); LogServer& operator=(const LogServer& obj); const LogServerStreamBuf& GetStreamBuf() const; LogServerStreamBuf& GetStreamBuf(); }; DECLARE_CLASS(LogServer); } //namespace zeitgeist #endif //ZEITGEIST_LOGSERVER_H --- NEW FILE: logserver.cpp --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of rcssserver3D Fri May 9 2003 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group $Id: logserver.cpp,v 1.1 2005/12/05 21:01:39 rollmark Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "logserver.h" #include "logserverstreambuf.h" #include <stdarg.h> using namespace std; using namespace zeitgeist; LogServer::LogServer(unsigned int size) : Node(), ostream(new LogServerStreamBuf(size)) { } LogServer::~LogServer() { flush(); // delete the created streambuf delete rdbuf(); } void LogServer::AddStream(std::ostream* stream, unsigned int mask) { GetStreamBuf().AddStream(stream, mask); } bool LogServer::RemoveStream(const std::ostream* stream) { return GetStreamBuf().RemoveStream(stream); } unsigned int LogServer::GetPriorityMask(const std::ostream* stream) const { return GetStreamBuf().GetPriorityMask(stream); } bool LogServer::SetPriorityMask(const std::ostream* stream, unsigned int mask) { return GetStreamBuf().SetPriorityMask(stream, mask); } LogServer& LogServer::Priority(unsigned int prio) { GetStreamBuf().SetCurrentPriority(prio); return *this; } void LogServer::Printf(const char *inFormat, ...) { const int size = 4096; char copyBuffer[size]; va_list args; va_start(args, inFormat); if (vsnprintf(copyBuffer, size, inFormat, args) == size) { copyBuffer[size-1] = 0; } va_end(args); (*this) << copyBuffer; this->flush(); } const LogServerStreamBuf& LogServer::GetStreamBuf() const { LogServerStreamBuf* streamBuf = (LogServerStreamBuf*)(rdbuf()); return *streamBuf; } LogServerStreamBuf& LogServer::GetStreamBuf() { LogServerStreamBuf* streamBuf = (LogServerStreamBuf*)(rdbuf()); return *streamBuf; } --- NEW FILE: logserver_c.cpp --- /* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- this file is part of rcssserver3D Fri May 9 2003 Copyright (C) 2002,2003 Koblenz University Copyright (C) 2003 RoboCup Soccer Server 3D Maintenance Group $Id: logserver_c.cpp,v 1.1 2005/12/05 21:01:39 rollmark Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "logserver.h" #include <fstream> using namespace boost; using namespace zeitgeist; FUNCTION(LogServer,addStream) { std::string inName; std::string inPriority; if ( (in.GetSize() != 2) || (! in.GetValue(in[0],inName)) || (! in.GetValue(in[1],inPriority)) ) { return false; } std::ostream *stream = NULL; if (inName == ":cout") { stream = &std::cout; } else if (inName == ":cerr") { stream = &std::cerr; } else { stream = new std::ofstream(inName.c_str()); } unsigned int pLevel = LogServer::eNone; do { if (inPriority == "eNone") { pLevel = LogServer::eNone; break; } if (inPriority == "eDebug") { pLevel = LogServer::eDebug; break; } if (inPriority == "eNormal") { pLevel = LogServer::eNormal; break; } if (inPriority == "eWarning") { pLevel = LogServer::eWarning; break; } if (inPriority == "eError") { pLevel = LogServer::eError; break; } if (inPriority == "eAll") { pLevel = LogServer::eAll; break; } // no match return false; } while(true); obj->AddStream(stream, pLevel); return true; } void CLASS(LogServer)::DefineClass() { DEFINE_BASECLASS(zeitgeist/Node); DEFINE_FUNCTION(addStream); } |