Commit 8a390c1d authored by Pavel Vainerman's avatar Pavel Vainerman

(Log): добавил LogAgregator для возможности "агрегировать" сразу

несколько DebugStream-ов и (например) подключать их к одному LogServer-у. (Log): добавил в DebugStream возможность задать "название" лога. Для возможности дальнейшего использования при управлении логами.. - добавил возможность задавать команду для конкретного лога (logreader) - сделал, чтобы лог в LogAgregator на экран не выводился
parent d1f6eb74
......@@ -55,12 +55,13 @@ int main( int argc, char* argv[], char* envp[] )
case 0:
{
/* Child. */
close(1); /* Close current stdout. */
dup(cp[1]); /* Make stdout go to write end of pipe. */
close(cp[0]);
// close(0); /* Close current stdin. */
// dup( pc[0]); /* Make stdin come from read end of pipe. */
close( cp[0]);
close( fileno(stderr) ); //close stderr
dup2(fileno(stdout),fileno(stderr));
close(fileno(stdout)); /* Close current stdout. */
dup2(cp[1],fileno(stdout)); /* Make stdout go to write end of pipe. */
execvpe(argv[3], argv + 3, envp);
perror("No exec");
......@@ -89,6 +90,7 @@ int main( int argc, char* argv[], char* envp[] )
ssize_t r = read(cp[0], &buf, sizeof(buf)-1 );
if( r > 0 )
{
cout << "***READ**" << endl;
buf[r] = '\0';
zlog << buf;
}
......
......@@ -21,15 +21,20 @@ static struct option longopts[] = {
{ "off", required_argument, 0, 'o' },
{ "on", required_argument, 0, 'n' },
{ "rotate", required_argument, 0, 'r' },
{ "logname", required_argument, 0, 'l' },
{ "command-only", no_argument, 0, 'b' },
{ NULL, 0, 0, 0 }
};
// --------------------------------------------------------------------------
static void print_help()
{
printf("-h, --help - this message\n");
printf("-v, --verbose - Print all messages to stdout\n");
printf("[-i|--iaddr] addr - ULogServer ip or hostname.\n");
printf("[-p|--port] port - ULogServer port.\n");
printf("-h, --help - this message\n");
printf("-v, --verbose - Print all messages to stdout\n");
printf("[-i|--iaddr] addr - LogServer ip or hostname.\n");
printf("[-p|--port] port - LogServer port.\n");
printf("[-l|--logname] name - Send command only for 'logname'.\n");
printf("[-b|--command-only] - Send command and break. (No read logs).\n");
printf("\n");
printf("Commands:\n");
......@@ -52,10 +57,12 @@ int main( int argc, char **argv )
int cmd = LogServerTypes::cmdNOP;
int data = 0;
string sdata("");
int cmdonly = 0;
string logname("");
try
{
while( (opt = getopt_long(argc, argv, "hva:p:i:d:s:onr",longopts,&optindex)) != -1 )
while( (opt = getopt_long(argc, argv, "hva:p:i:d:s:l:onrb",longopts,&optindex)) != -1 )
{
switch (opt)
{
......@@ -95,6 +102,14 @@ int main( int argc, char **argv )
addr = string(optarg);
break;
case 'l':
logname = string(optarg);
break;
case 'b':
cmdonly = 1;
break;
case 'p':
port = uni_atoi(optarg);
break;
......@@ -118,6 +133,7 @@ int main( int argc, char **argv )
}
LogReader lr;
lr.setCommandOnlyMode(cmdonly);
if( !sdata.empty() )
{
......@@ -127,7 +143,7 @@ int main( int argc, char **argv )
cout << "SEND COMMAND: '" << (LogServerTypes::Command)cmd << " data='" << sdata << "'" << endl;
}
lr.readlogs( addr, port, (LogServerTypes::Command)cmd, data, verb );
lr.readlogs( addr, port, (LogServerTypes::Command)cmd, data, logname, verb );
}
catch( SystemError& err )
{
......
......@@ -5,6 +5,7 @@
#include "UniSetTypes.h"
#include "Exceptions.h"
#include "LogServer.h"
#include "LogAgregator.h"
// --------------------------------------------------------------------------
using namespace UniSetTypes;
using namespace std;
......@@ -36,7 +37,6 @@ int main( int argc, char **argv )
string addr("localhost");
int port = 3333;
int tout = 2000;
DebugStream dlog;
timeout_t delay = 5000;
try
......@@ -78,21 +78,37 @@ int main( int argc, char **argv )
// << " timeout=" << tout << " msec "
<< endl;
dlog.addLevel( Debug::type(Debug::CRIT | Debug::WARN | Debug::INFO) );
// dlog.addLevel( Debug::type(Debug::CRIT | Debug::WARN | Debug::INFO) );
}
LogServer ls(dlog);
DebugStream dlog;
dlog.setLogName("dlog");
DebugStream dlog2;
dlog2.setLogName("dlog2");
LogAgregator la;
la.add(dlog);
la.add(dlog2);
LogServer ls(la);
// LogServer ls(cout);
dlog.addLevel(Debug::ANY);
dlog2.addLevel(Debug::ANY);
ls.run( addr, port, true );
unsigned int i=0;
while( true )
{
dlog << "[" << ++i << "] Test message for log" << endl;
dlog.info() << ": INFO message" << endl;
dlog.warn() << ": WARN message" << endl;
dlog.crit() << ": CRIT message" << endl;
dlog.info() << ": dlog : INFO message" << endl;
dlog.warn() << ": dlog : WARN message" << endl;
dlog.crit() << ": dlog : CRIT message" << endl;
dlog2.info() << ": dlog2: INFO message" << endl;
dlog2.warn() << ": dlog2: WARN message" << endl;
dlog2.crit() << ": dlog2: CRIT message" << endl;
msleep(delay);
}
......
......@@ -32,8 +32,7 @@
</Services>
</UniSet>
<dlog name="dlog"/>
<LogServer name="dlog" port="3333" host="localhost" />
<LogServer name="ulog" port="3335" host="localhost" />
<LogServer name="smplus" port="3333" host="localhost" />
<settings>
<TestProc name="TestProc1"
......
......@@ -228,7 +228,7 @@ AC_CONFIG_FILES([Makefile
src/Services/Makefile
src/Timers/Makefile
src/Various/Makefile
src/LogServer/Makefile
src/Log/Makefile
src/Makefile
include/Makefile
include/modbus/Makefile
......
......@@ -16,6 +16,7 @@
#ifdef UNISET_ENABLE_IO
#include "IOControl.h"
#endif
#include "LogAgregator.h"
#include "LogServer.h"
// --------------------------------------------------------------------------
using namespace std;
......@@ -186,15 +187,13 @@ int main( int argc, const char **argv )
(*it)->start();
#endif
if( run_logserver("ulog",ulog) == 0 )
{
ulog.crit() << "(smemory-plus): run logserver for 'ulog' FAILED" << endl;
return 1;
}
if( run_logserver("dlog",dlog) == 0 )
LogAgregator la;
la.add(ulog);
la.add(dlog);
if( run_logserver("smplus",la) == 0 )
{
dlog.crit() << "(smemory-plus): run logserver for 'dlog' FAILED" << endl;
cerr << "(smemory-plus): run logserver for 'smplus' FAILED" << endl;
return 1;
}
......
......@@ -4,7 +4,6 @@ ulimit -Sc 10000000
START=uniset2-start.sh
${START} -f ./uniset2-smemory-plus --smemory-id SharedMemory --confile test.xml \
--dlog-add-levels any \
--io-name IOControl \
--io-polltime 100 \
--io-s-filter-field io \
......@@ -31,7 +30,8 @@ ${START} -f ./uniset2-smemory-plus --smemory-id SharedMemory --confile test.xml
--mbtcp2-gateway-port 2049 \
--mbtcp2-recv-timeout 200 \
--mbtcp2-force-out 1 \
$*
# --dlog-add-levels any \
# $*
# --add-rtu \
# --rs-dev /dev/cbsideA1 \
# --rs-id RTUExchange \
......
......@@ -92,7 +92,7 @@ public:
DebugStream(char const * f, Debug::type t = Debug::NONE);
///
~DebugStream();
virtual ~DebugStream();
typedef sigc::signal<void,const std::string&> StreamEvent_Signal;
StreamEvent_Signal signal_stream_event();
......@@ -118,7 +118,7 @@ public:
}
/// Sets the debugstreams' logfile to f.
void logFile( const std::string& f );
virtual void logFile( const std::string& f );
inline std::string getLogFile(){ return fname; }
......@@ -199,24 +199,27 @@ public:
std::ostream& pos(int x, int y);
const DebugStream &operator=(const DebugStream& r);
inline void setLogName( const std::string& n ){ logname = n; }
inline std::string getLogName(){ return logname; }
protected:
void sbuf_overflow( const std::string& s );
private:
// private:
/// The current debug level
Debug::type dt;
/// The no-op stream.
std::ostream nullstream;
///
struct debugstream_internal;
struct debugstream_sbuf;
///
debugstream_internal * internal;
debugstream_sbuf * internal_sbuf;
bool show_datetime;
std::string fname;
StreamEvent_Signal s_stream;
std::string logname;
};
#endif
#ifndef LogAgregator_H_
#define LogAgregator_H_
// -------------------------------------------------------------------------
#include <string>
#include <list>
#include "DebugStream.h"
#include "LogServerTypes.h"
// -------------------------------------------------------------------------
class LogAgregator:
public DebugStream
{
public:
explicit LogAgregator( Debug::type t = Debug::NONE );
explicit LogAgregator( char const * f, Debug::type t = Debug::NONE );
virtual ~LogAgregator();
virtual void logFile( const std::string& f );
void add( DebugStream& log );
// Управление "подчинёнными" логами
void addLevel( const std::string& logname, Debug::type t );
void delLevel( const std::string& logname, Debug::type t );
void level( const std::string& logname, Debug::type t );
DebugStream* getLog( const std::string& logname );
protected:
void logOnEvent( const std::string& s );
private:
typedef std::list<DebugStream*> LogList;
LogList llst;
};
// -------------------------------------------------------------------------
#endif // LogAgregator_H_
// -------------------------------------------------------------------------
......@@ -15,10 +15,18 @@ class LogReader
LogReader();
~LogReader();
void readlogs( const std::string& addr, ost::tpport_t port, LogServerTypes::Command c, int data, bool verbose = false );
void readlogs( const std::string& addr, ost::tpport_t port,
LogServerTypes::Command c = LogServerTypes::cmdNOP,
int data = 0,
const std::string& logname="",
bool verbose = false );
void readlogs( const std::string& addr, ost::tpport_t port, LogServerTypes::lsMessage& m, bool verbose = false );
bool isConnection();
inline void setCommandOnlyMode( bool s ){ cmdonly = s; }
protected:
void connect( const std::string& addr, ost::tpport_t port, timeout_t tout=TIMEOUT_INF );
......@@ -29,6 +37,7 @@ class LogReader
UTCPStream* tcp;
std::string iaddr;
ost::tpport_t port;
bool cmdonly;
DebugStream rlog;
};
......
......@@ -3,6 +3,7 @@
#define LogServerTypes_H_
// -------------------------------------------------------------------------
#include <ostream>
#include <cstring>
// -------------------------------------------------------------------------
namespace LogServerTypes
{
......@@ -23,16 +24,21 @@ namespace LogServerTypes
struct lsMessage
{
lsMessage():magic(MAGICNUM),cmd(cmdNOP),data(0){}
lsMessage():magic(MAGICNUM),cmd(cmdNOP),data(0){ std::memset(logname,0,sizeof(logname)); }
unsigned int magic;
Command cmd;
unsigned int data;
static const size_t MAXLOGNAME = 20;
char logname[MAXLOGNAME+1]; // +1 reserverd for '\0'
void setLogName( const std::string& name );
// для команды 'cmdSetLogFile'
// static const short MAXLOGFILENAME = 100;
// char logname[MAXLOGFILENAME];
// static const size_t MAXLOGFILENAME = 200;
// char logfile[MAXLOGFILENAME];
}__attribute__((packed));
std::ostream& operator<<(std::ostream& os, lsMessage& m );
}
// -------------------------------------------------------------------------
......
......@@ -22,4 +22,4 @@ libUniSet2_la_LIBADD = -lm \
$(top_builddir)/src/Services/libServices.la \
$(top_builddir)/src/Timers/libTimers.la \
$(top_builddir)/src/Various/libVarious.la \
$(top_builddir)/src/LogServer/libLogServer.la
$(top_builddir)/src/Log/libLog.la
#ifndef DEBUGEXTBUF_H
#define DEBUGEXTBUF_H
// Created by Lars Gullik Bj�nnes
// Copyright 1999 Lars Gullik Bj�nnes (larsbj@lyx.org)
// Released into the public domain.
......@@ -30,7 +33,6 @@
#include <iomanip>
#include <time.h>
#include <iomanip>
#include <sstream>
using std::ostream;
using std::streambuf;
......@@ -238,7 +240,11 @@ public:
~stringsigbuf()
{
delete sb;
if( sb )
{
delete sb;
sb = 0;
}
}
///
......@@ -304,267 +310,13 @@ private:
stringbuf* sb;
UniSetTypes::uniset_rwmutex mut;
};
//--------------------------------------------------------------------------
/// So that public parts of DebugStream does not need to know about filebuf
struct DebugStream::debugstream_internal {
/// Used when logging to file.
filebuf fbuf;
};
//--------------------------------------------------------------------------
struct DebugStream::debugstream_sbuf {
/// Used when logging to file.
stringsigbuf sbuf;
nullbuf nbuf;
};
//--------------------------------------------------------------------------
/// Constructor, sets the debug level to t.
DebugStream::DebugStream(Debug::type t)
: ostream(new debugbuf(cerr.rdbuf())),
dt(t), nullstream(new nullbuf), internal(0),internal_sbuf(new debugstream_sbuf),
show_datetime(true),
fname("")
{
delete rdbuf(new teebuf(cerr.rdbuf(),&internal_sbuf->sbuf));
internal_sbuf->sbuf.signal_overflow().connect(sigc::mem_fun(*this, &DebugStream::sbuf_overflow));
}
//--------------------------------------------------------------------------
/// Constructor, sets the log file to f, and the debug level to t.
DebugStream::DebugStream(char const * f, Debug::type t)
: ostream(new debugbuf(cerr.rdbuf())),
dt(t), nullstream(new nullbuf),
internal(new debugstream_internal),internal_sbuf(new debugstream_sbuf),
show_datetime(true),
fname("")
{
internal->fbuf.open(f, ios::out|ios::app);
delete rdbuf(new threebuf(cerr.rdbuf(),
&internal->fbuf,&internal_sbuf->sbuf));
internal_sbuf->sbuf.signal_overflow().connect(sigc::mem_fun(*this, &DebugStream::sbuf_overflow));
}
//--------------------------------------------------------------------------
void DebugStream::sbuf_overflow( const std::string& s )
{
s_stream.emit(s);
}
//--------------------------------------------------------------------------
DebugStream::~DebugStream()
{
delete nullstream.rdbuf(0); // Without this we leak
delete rdbuf(0); // Without this we leak
delete internal;
delete internal_sbuf;
}
//--------------------------------------------------------------------------
const DebugStream& DebugStream::operator=( const DebugStream& r )
{
if( r == *this )
return *this;
dt = r.dt;
show_datetime = r.show_datetime;
fname = r.fname;
if( !r.fname.empty() )
logFile(fname);
return *this;
}
//--------------------------------------------------------------------------
/// Sets the debugstreams' logfile to f.
void DebugStream::logFile( const std::string& f )
{
fname = f;
if (internal) {
internal->fbuf.close();
} else {
internal = new debugstream_internal;
}
if( !internal_sbuf ) {
internal_sbuf = new debugstream_sbuf;
}
if( !f.empty() )
{
internal->fbuf.open(f.c_str(), ios::out|ios::app);
delete rdbuf(new threebuf(cerr.rdbuf(),
&internal->fbuf,&internal_sbuf->sbuf));
}
else
delete rdbuf(new teebuf(cerr.rdbuf(),&internal_sbuf->sbuf));
}
//--------------------------------------------------------------------------
std::ostream & DebugStream::debug(Debug::type t)
{
if(dt & t)
{
if( show_datetime )
printDateTime(t);
*this << "(" << std::setfill(' ') << std::setw(6) << t << "): "; // "):\t";
return *this;
}
return nullstream;
}
//--------------------------------------------------------------------------
std::ostream& DebugStream::operator()(Debug::type t)
{
if(dt & t)
return *this;
return nullstream;
}
//--------------------------------------------------------------------------
std::ostream& DebugStream::printDate(Debug::type t, char brk)
{
if(dt && t)
{
time_t GMTime = time(NULL);
struct tm *tms = localtime(&GMTime);
return *this << std::setw(2) << std::setfill('0') << tms->tm_mday << brk
<< std::setw(2) << std::setfill('0') << tms->tm_mon+1 << brk
<< std::setw(4) << std::setfill('0') << tms->tm_year+1900;
}
return nullstream;
}
//--------------------------------------------------------------------------
std::ostream& DebugStream::printTime(Debug::type t, char brk)
{
if(dt && t)
{
time_t GMTime = time(NULL);
struct tm *tms = localtime(&GMTime);
return *this << std::setw(2) << std::setfill('0') << tms->tm_hour << brk
<< std::setw(2) << std::setfill('0') << tms->tm_min << brk
<< std::setw(2) << std::setfill('0') << tms->tm_sec;
}
return nullstream;
}
//--------------------------------------------------------------------------
std::ostream& DebugStream::printDateTime(Debug::type t)
{
if(dt & t)
{
time_t GMTime = time(NULL);
struct tm *tms = localtime(&GMTime);
return *this << std::setw(2) << std::setfill('0') << tms->tm_mday << "/"
<< std::setw(2) << std::setfill('0') << tms->tm_mon+1 << "/"
<< std::setw(4) << std::setfill('0') << tms->tm_year+1900 << " "
<< std::setw(2) << std::setfill('0') << tms->tm_hour << ":"
<< std::setw(2) << std::setfill('0') << tms->tm_min << ":"
<< std::setw(2) << std::setfill('0') << tms->tm_sec;
}
return nullstream;
}
//--------------------------------------------------------------------------
std::ostream& DebugStream::pos(int x, int y)
{
if( !dt )
return nullstream;
return *this << "\033[" << y << ";" << x << "f";
}
//--------------------------------------------------------------------------
DebugStream::StreamEvent_Signal DebugStream::signal_stream_event()
{
return s_stream;
}
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
#ifdef TEST_DEBUGSTREAM
// Example debug stream
DebugStream debugstream;
int main(int, char **)
{
/**
I have been running some tests on this to see how much overhead
this kind of permanent debug code has. My conclusion is: not
much. In all, but the most time critical code, this will have
close to no impact at all.
In the tests that I have run the use of
if (debugstream.debugging(DebugStream::INFO))
debugstream << "some debug\n";
has close to no overhead when the debug level is not
DebugStream::INFO.
The overhead for
debugstream.debug(DebugStream::INFO) << "some debug\n";
is also very small when the debug level is not
DebugStream::INFO. However the overhead for this will increase
if complex debugging information is output.
The overhead when the debug level is DebugStream::INFO can be
significant, but since we then are running in debug mode it is
of no concern.
Why should we use this instead of the class Error that we already
have? First of all it uses C++ iostream and constructs, secondly
it will be a lot easier to output the debug info that we need
without a lot of manual conversions, thirdly we can now use
iomanipulators and the complete iostream formatting functions.
pluss it will work for all types that have a operator<<
defined, and can be used in functors that take a ostream & as
parameter. And there should be less need for temporary objects.
And one nice bonus is that we get a log file almost for
free.
Some of the names are of course open to modifications. I will try
to use the names we already use in LyX.
*/
// Just a few simple debugs to show how it can work.
debugstream << "Debug level set to Debug::NONE\n";
if (debugstream.debugging()) {
debugstream << "Something must be debugged\n";
}
debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
debugstream.level(Debug::value("INFO"));
debugstream << "Setting debug level to Debug::INFO\n";
if (debugstream.debugging()) {
debugstream << "Something must be debugged\n";
}
debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
debugstream.addLevel(Debug::type(Debug::CRIT |
Debug::WARN));
debugstream << "Adding Debug::CRIT and Debug::WARN\n";
debugstream[Debug::WARN] << "more debug(WARN)\n";
debugstream[Debug::INFO] << "even more debug(INFO)\n";
debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
debugstream.delLevel(Debug::INFO);
debugstream << "Removing Debug::INFO\n";
debugstream[Debug::WARN] << "more debug(WARN)\n";
debugstream[Debug::INFO] << "even more debug(INFO)\n";
debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
debugstream.logFile("logfile");
debugstream << "Setting logfile to \"logfile\"\n";
debugstream << "Value: " << 123 << " " << "12\n";
int i = 0;
int * p = new int;
// note: the (void*) is needed on g++ 2.7.x since it does not
// support partial specialization. In egcs this should not be
// needed.
debugstream << "automatic " << &i
<< ", free store " << p << endl;
delete p;
/*
for (int j = 0; j < 200000; ++j) {
DebugStream tmp;
tmp << "Test" << endl;
}
*/
}
#endif
#endif
\ No newline at end of file
// Created by Lars Gullik Bj�nnes
// Copyright 1999 Lars Gullik Bj�nnes (larsbj@lyx.org)
// Released into the public domain.
// Primarily developed for use in the LyX Project http://www.lyx.org/
// but should be adaptable to any project.
// (c) 2002 adapted for UniSet by Lav, GNU GPL license
//#define TEST_DEBUGSTREAM
#ifdef __GNUG__
#pragma implementation
#endif
//#include "DebugStream.h"
#include "Debug.h"
#include "Mutex.h"
//�Since the current C++ lib in egcs does not have a standard implementation
// of basic_streambuf and basic_filebuf we don't have to include this
// header.
//#define MODERN_STL_STREAMS
#ifdef MODERN_STL_STREAMS
#include <fstream>
#endif
#include <iostream>
#include <sstream>
#include <iomanip>
#include <time.h>
#include <iomanip>
#include "DebugExtBuf.h"
using std::ostream;
using std::streambuf;
using std::streamsize;
using std::filebuf;
using std::stringbuf;
using std::cerr;
using std::ios;
//--------------------------------------------------------------------------
/// Constructor, sets the debug level to t.
DebugStream::DebugStream(Debug::type t)
: ostream(new debugbuf(cerr.rdbuf())),
dt(t), nullstream(new nullbuf), internal(new debugstream_internal),
show_datetime(true),
fname(""),
logname("")
{
delete rdbuf(new teebuf(cerr.rdbuf(),&internal->sbuf));
internal->sbuf.signal_overflow().connect(sigc::mem_fun(*this, &DebugStream::sbuf_overflow));
}
//--------------------------------------------------------------------------
/// Constructor, sets the log file to f, and the debug level to t.
DebugStream::DebugStream(char const * f, Debug::type t)
: ostream(new debugbuf(cerr.rdbuf())),
dt(t), nullstream(new nullbuf),
internal(new debugstream_internal),
show_datetime(true),
fname(""),
logname("")
{
internal->fbuf.open(f, ios::out|ios::app);
delete rdbuf(new threebuf(cerr.rdbuf(),
&internal->fbuf,&internal->sbuf));
internal->sbuf.signal_overflow().connect(sigc::mem_fun(*this, &DebugStream::sbuf_overflow));
}
//--------------------------------------------------------------------------
void DebugStream::sbuf_overflow( const std::string& s )
{
s_stream.emit(s);
}
//--------------------------------------------------------------------------
DebugStream::~DebugStream()
{
delete nullstream.rdbuf(0); // Without this we leak
delete rdbuf(0); // Without this we leak
delete internal;
}
//--------------------------------------------------------------------------
const DebugStream& DebugStream::operator=( const DebugStream& r )
{
if( r == *this )
return *this;
dt = r.dt;
show_datetime = r.show_datetime;
fname = r.fname;
if( !r.fname.empty() )
logFile(fname);
// s_stream = r.s_stream;
return *this;
}
//--------------------------------------------------------------------------
/// Sets the debugstreams' logfile to f.
void DebugStream::logFile( const std::string& f )
{
fname = f;
if( internal ) {
internal->fbuf.close();
} else {
internal = new debugstream_internal;
}
if( !f.empty() )
{
internal->fbuf.open(f.c_str(), ios::out|ios::app);
delete rdbuf(new threebuf(cerr.rdbuf(),
&internal->fbuf,&internal->sbuf));
}
else
delete rdbuf(new teebuf(cerr.rdbuf(),&internal->sbuf));
}
//--------------------------------------------------------------------------
std::ostream & DebugStream::debug(Debug::type t)
{
if(dt & t)
{
if( show_datetime )
printDateTime(t);
*this << "(" << std::setfill(' ') << std::setw(6) << t << "): "; // "):\t";
return *this;
}
return nullstream;
}
//--------------------------------------------------------------------------
std::ostream& DebugStream::operator()(Debug::type t)
{
if(dt & t)
return *this;
return nullstream;
}
//--------------------------------------------------------------------------
std::ostream& DebugStream::printDate(Debug::type t, char brk)
{
if(dt && t)
{
time_t GMTime = time(NULL);
struct tm *tms = localtime(&GMTime);
return *this << std::setw(2) << std::setfill('0') << tms->tm_mday << brk
<< std::setw(2) << std::setfill('0') << tms->tm_mon+1 << brk
<< std::setw(4) << std::setfill('0') << tms->tm_year+1900;
}
return nullstream;
}
//--------------------------------------------------------------------------
std::ostream& DebugStream::printTime(Debug::type t, char brk)
{
if(dt && t)
{
time_t GMTime = time(NULL);
struct tm *tms = localtime(&GMTime);
return *this << std::setw(2) << std::setfill('0') << tms->tm_hour << brk
<< std::setw(2) << std::setfill('0') << tms->tm_min << brk
<< std::setw(2) << std::setfill('0') << tms->tm_sec;
}
return nullstream;
}
//--------------------------------------------------------------------------
std::ostream& DebugStream::printDateTime(Debug::type t)
{
if(dt & t)
{
time_t GMTime = time(NULL);
struct tm *tms = localtime(&GMTime);
return *this << std::setw(2) << std::setfill('0') << tms->tm_mday << "/"
<< std::setw(2) << std::setfill('0') << tms->tm_mon+1 << "/"
<< std::setw(4) << std::setfill('0') << tms->tm_year+1900 << " "
<< std::setw(2) << std::setfill('0') << tms->tm_hour << ":"
<< std::setw(2) << std::setfill('0') << tms->tm_min << ":"
<< std::setw(2) << std::setfill('0') << tms->tm_sec;
}
return nullstream;
}
//--------------------------------------------------------------------------
std::ostream& DebugStream::pos(int x, int y)
{
if( !dt )
return nullstream;
return *this << "\033[" << y << ";" << x << "f";
}
//--------------------------------------------------------------------------
DebugStream::StreamEvent_Signal DebugStream::signal_stream_event()
{
return s_stream;
}
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
#ifdef TEST_DEBUGSTREAM
// Example debug stream
DebugStream debugstream;
int main(int, char **)
{
/**
I have been running some tests on this to see how much overhead
this kind of permanent debug code has. My conclusion is: not
much. In all, but the most time critical code, this will have
close to no impact at all.
In the tests that I have run the use of
if (debugstream.debugging(DebugStream::INFO))
debugstream << "some debug\n";
has close to no overhead when the debug level is not
DebugStream::INFO.
The overhead for
debugstream.debug(DebugStream::INFO) << "some debug\n";
is also very small when the debug level is not
DebugStream::INFO. However the overhead for this will increase
if complex debugging information is output.
The overhead when the debug level is DebugStream::INFO can be
significant, but since we then are running in debug mode it is
of no concern.
Why should we use this instead of the class Error that we already
have? First of all it uses C++ iostream and constructs, secondly
it will be a lot easier to output the debug info that we need
without a lot of manual conversions, thirdly we can now use
iomanipulators and the complete iostream formatting functions.
pluss it will work for all types that have a operator<<
defined, and can be used in functors that take a ostream & as
parameter. And there should be less need for temporary objects.
And one nice bonus is that we get a log file almost for
free.
Some of the names are of course open to modifications. I will try
to use the names we already use in LyX.
*/
// Just a few simple debugs to show how it can work.
debugstream << "Debug level set to Debug::NONE\n";
if (debugstream.debugging()) {
debugstream << "Something must be debugged\n";
}
debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
debugstream.level(Debug::value("INFO"));
debugstream << "Setting debug level to Debug::INFO\n";
if (debugstream.debugging()) {
debugstream << "Something must be debugged\n";
}
debugstream.debug(Debug::WARN) << "more debug(WARN)\n";
debugstream.debug(Debug::INFO) << "even more debug(INFO)\n";
debugstream.debug(Debug::CRIT) << "even more debug(CRIT)\n";
debugstream.addLevel(Debug::type(Debug::CRIT |
Debug::WARN));
debugstream << "Adding Debug::CRIT and Debug::WARN\n";
debugstream[Debug::WARN] << "more debug(WARN)\n";
debugstream[Debug::INFO] << "even more debug(INFO)\n";
debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
debugstream.delLevel(Debug::INFO);
debugstream << "Removing Debug::INFO\n";
debugstream[Debug::WARN] << "more debug(WARN)\n";
debugstream[Debug::INFO] << "even more debug(INFO)\n";
debugstream[Debug::CRIT] << "even more debug(CRIT)\n";
debugstream.logFile("logfile");
debugstream << "Setting logfile to \"logfile\"\n";
debugstream << "Value: " << 123 << " " << "12\n";
int i = 0;
int * p = new int;
// note: the (void*) is needed on g++ 2.7.x since it does not
// support partial specialization. In egcs this should not be
// needed.
debugstream << "automatic " << &i
<< ", free store " << p << endl;
delete p;
/*
for (int j = 0; j < 200000; ++j) {
DebugStream tmp;
tmp << "Test" << endl;
}
*/
}
#endif
#include "DebugExtBuf.h"
#include "LogAgregator.h"
// -------------------------------------------------------------------------
LogAgregator::LogAgregator( char const * f, Debug::type t ):
DebugStream(f,t)
{
delete rdbuf(new teebuf(&internal->fbuf,&internal->sbuf));
}
// -------------------------------------------------------------------------
LogAgregator::LogAgregator( Debug::type t ):
DebugStream(t)
{
delete rdbuf(new teebuf(&internal->nbuf,&internal->sbuf));
}
// -------------------------------------------------------------------------
void LogAgregator::logFile( const std::string& f )
{
DebugStream::logFile(f);
if( f.empty() )
delete rdbuf(new teebuf(&internal->fbuf,&internal->sbuf));
else
delete rdbuf(new teebuf(&internal->nbuf,&internal->sbuf));
}
// -------------------------------------------------------------------------
LogAgregator::~LogAgregator()
{
}
// -------------------------------------------------------------------------
void LogAgregator::logOnEvent( const std::string& s )
{
(*this) << s;
}
// -------------------------------------------------------------------------
void LogAgregator::add( DebugStream& l )
{
l.signal_stream_event().connect( sigc::mem_fun(this, &LogAgregator::logOnEvent) );
for( LogList::iterator i=llst.begin(); i!=llst.end(); i++ )
{
if( &l == (*i) )
return;
}
llst.push_back(&l);
}
// -------------------------------------------------------------------------
void LogAgregator::addLevel( const std::string& logname, Debug::type t )
{
for( auto& i: llst )
{
if( i->getLogName() == logname )
{
i->addLevel(t);
break;
}
}
}
// -------------------------------------------------------------------------
void LogAgregator::delLevel( const std::string& logname, Debug::type t )
{
for( auto& i: llst )
{
if( i->getLogName() == logname )
{
i->delLevel(t);
break;
}
}
}
// -------------------------------------------------------------------------
void LogAgregator::level( const std::string& logname, Debug::type t )
{
for( auto& i: llst )
{
if( i->getLogName() == logname )
{
i->level(t);
break;
}
}
}
// -------------------------------------------------------------------------
DebugStream* LogAgregator::getLog( const std::string& logname )
{
if( logname.empty() )
return 0;
for( auto& i: llst )
{
if( i->getLogName() == logname )
return i;
}
return 0;
}
// -------------------------------------------------------------------------
\ No newline at end of file
......@@ -11,7 +11,8 @@ using namespace UniSetTypes;
// -------------------------------------------------------------------------
LogReader::LogReader():
tcp(0),
iaddr("")
iaddr(""),
cmdonly(false)
{
}
......@@ -102,7 +103,16 @@ bool LogReader::isConnection()
return tcp && tcp->isConnected();
}
// -------------------------------------------------------------------------
void LogReader::readlogs( const std::string& _addr, ost::tpport_t _port, LogServerTypes::Command cmd, int data, bool verbose )
void LogReader::readlogs( const std::string& _addr, ost::tpport_t _port, LogServerTypes::Command cmd, int data, const std::string& logname, bool verbose )
{
LogServerTypes::lsMessage msg;
msg.cmd = cmd;
msg.data = data;
msg.setLogName(logname);
readlogs(_addr,_port,msg,verbose );
}
// -------------------------------------------------------------------------
void LogReader::readlogs( const std::string& _addr, ost::tpport_t _port, LogServerTypes::lsMessage& msg, bool verbose )
{
timeout_t inTimeout = 10000;
timeout_t outTimeout = 6000;
......@@ -126,15 +136,15 @@ void LogReader::readlogs( const std::string& _addr, ost::tpport_t _port, LogServ
continue;
}
if( !send_ok && cmd != LogServerTypes::cmdNOP )
if( !send_ok && msg.cmd != LogServerTypes::cmdNOP )
{
if( tcp->isPending(ost::Socket::pendingOutput,outTimeout) )
{
rlog.info() << "** send command: '" << cmd << "' data='" << data << "'" << endl;
rlog.info() << "** send command: logname='" << msg.logname << "' cmd='" << msg.cmd << "' data='" << msg.data << "'" << endl;
LogServerTypes::lsMessage msg;
msg.cmd = cmd;
msg.data = data;
// LogServerTypes::lsMessage msg;
// msg.cmd = cmd;
// msg.data = data;
for( size_t i=0; i<sizeof(msg); i++ )
(*tcp) << ((unsigned char*)(&msg))[i];
......@@ -142,10 +152,13 @@ void LogReader::readlogs( const std::string& _addr, ost::tpport_t _port, LogServ
send_ok = true;
}
else
rlog.warn() << "**** SEND COMMAND ('" << cmd << "' FAILED!" << endl;
rlog.warn() << "**** SEND COMMAND ('" << msg.cmd << "' FAILED!" << endl;
if( cmdonly )
return;
}
while( tcp->isPending(ost::Socket::pendingInput,inTimeout) )
while( !cmdonly && tcp->isPending(ost::Socket::pendingInput,inTimeout) )
{
int n = tcp->peek( buf,sizeof(buf)-1 );
if( n > 0 )
......
......@@ -37,3 +37,10 @@ std::ostream& LogServerTypes::operator<<(std::ostream& os, LogServerTypes::lsMes
return os << " magic=" << m.magic << " cmd=" << m.cmd << " data=" << m.data;
}
// -------------------------------------------------------------------------
void LogServerTypes::lsMessage::setLogName( const std::string& name )
{
size_t s = name.size()> MAXLOGNAME ? MAXLOGNAME : name.size();
memcpy( &logname, name.c_str(), s );
logname[s] = '\0';
}
// -------------------------------------------------------------------------
......@@ -8,6 +8,7 @@
#include "LogSession.h"
#include "UniSetTypes.h"
#include "LogServerTypes.h"
#include "LogAgregator.h"
// -------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
......@@ -82,47 +83,60 @@ void LogSession::run()
{
slog.info() << peername << "(run): receive command: '" << msg.cmd << "'" << endl;
// Обработка команд..
// \warning Работа с логом ведётся без mutex-а, хотя он разделяется отдельными потоками
switch( msg.cmd )
string cmdLogName(msg.logname);
DebugStream* cmdlog = 0;
if( !cmdLogName.empty () )
{
LogAgregator* lag = dynamic_cast<LogAgregator*>(log);
cmdlog = lag ? lag->getLog( cmdLogName ) : log;
}
// обрабатываем команды только если нашли log
if( cmdlog )
{
case LogServerTypes::cmdSetLevel:
log->level( (Debug::type)msg.data );
break;
case LogServerTypes::cmdAddLevel:
log->addLevel((Debug::type)msg.data );
break;
case LogServerTypes::cmdDelLevel:
log->delLevel( (Debug::type)msg.data );
break;
case LogServerTypes::cmdRotate:
{
string lfile( log->getLogFile() );
if( !lfile.empty() )
log->logFile(lfile);
}
break;
case LogServerTypes::cmdOffLogFile:
{
string lfile( log->getLogFile() );
if( !lfile.empty() )
log->logFile("");
}
break;
case LogServerTypes::cmdOnLogFile:
{
if( !oldLogFile.empty() && oldLogFile != log->getLogFile() )
log->logFile(oldLogFile);
}
break;
default:
slog.warn() << peername << "(run): Unknown command '" << msg.cmd << "'" << endl;
break;
}
// Обработка команд..
// \warning Работа с логом ведётся без mutex-а, хотя он разделяется отдельными потоками
switch( msg.cmd )
{
case LogServerTypes::cmdSetLevel:
cmdlog->level( (Debug::type)msg.data );
break;
case LogServerTypes::cmdAddLevel:
cmdlog->addLevel((Debug::type)msg.data );
break;
case LogServerTypes::cmdDelLevel:
cmdlog->delLevel( (Debug::type)msg.data );
break;
case LogServerTypes::cmdRotate:
{
string lfile( cmdlog->getLogFile() );
if( !lfile.empty() )
cmdlog->logFile(lfile);
}
break;
case LogServerTypes::cmdOffLogFile:
{
string lfile( cmdlog->getLogFile() );
if( !lfile.empty() )
cmdlog->logFile("");
}
break;
case LogServerTypes::cmdOnLogFile:
{
if( !oldLogFile.empty() && oldLogFile != cmdlog->getLogFile() )
cmdlog->logFile(oldLogFile);
}
break;
default:
slog.warn() << peername << "(run): Unknown command '" << msg.cmd << "'" << endl;
break;
}
}
}
}
}
......
############################################################################
# This file is part of the UniSet library #
############################################################################
noinst_LTLIBRARIES = libLog.la
libLog_la_CPPFLAGS = $(SIGC_CFLAGS) $(COMCPP_CFLAGS)
libLog_la_LIBADD = $(SIGC_LIBS) $(COMCPP_LIBS)
libLog_la_SOURCES = DebugStream.cc Debug.cc LogServerTypes.cc LogServer.cc LogSession.cc LogReader.cc LogAgregator.cc
############################################################################
# This file is part of the UniSet library #
############################################################################
noinst_LTLIBRARIES = libLogServer.la
libLogServer_la_CPPFLAGS = $(SIGC_CFLAGS) $(COMCPP_CFLAGS)
libLogServer_la_LIBADD = $(SIGC_LIBS) $(COMCPP_LIBS)
libLogServer_la_SOURCES = LogServerTypes.cc LogServer.cc LogSession.cc LogReader.cc
......@@ -2,5 +2,5 @@
# This file is part of the UniSet library #
############################################################################
SUBDIRS=ObjectRepository Processes Interfaces Timers Services Various Communications LogServer
SUBDIRS=ObjectRepository Processes Interfaces Timers Services Various Communications Log
......@@ -701,7 +701,10 @@ xmlNode* Configuration::initDebug( DebugStream& deb, const string& _debname )
else
{
if( !getProp(dnode,"name").empty() )
{
debname = getProp(dnode,"name");
deb.setLogName(debname);
}
}
string no_deb("--"+debname+"-no-debug");
......@@ -978,6 +981,7 @@ UniversalIO::IOType Configuration::getIOType( const std::string& name )
void uniset_init( int argc, const char* const* argv, const std::string& xmlfile )
{
string confile = UniSetTypes::getArgParam( "--confile", argc, argv, xmlfile );
ulog.setLogName("ulog");
UniSetTypes::conf = new Configuration(argc, argv, confile);
}
// -------------------------------------------------------------------------
......
......@@ -5,7 +5,7 @@
noinst_LTLIBRARIES = libVarious.la
libVarious_la_CPPFLAGS = $(SIGC_CFLAGS) $(COMCPP_CFLAGS)
libVarious_la_LIBADD = $(SIGC_LIBS) $(COMCPP_LIBS)
libVarious_la_SOURCES = DebugStream.cc Debug.cc UniXML.cc MessageType.cc Configuration.cc \
libVarious_la_SOURCES = UniXML.cc MessageType.cc Configuration.cc \
Restorer_XML.cc RunLock.cc Mutex.cc SViewer.cc SMonitor.cc LT_Object.cc WDTInterface.cc
local-clean:
......
#include <time.h>
#include "Debug.h"
#include "UniSetTypes.h"
#include "LogAgregator.h"
using namespace std;
using namespace UniSetTypes;
std::ostringstream ss;
std::ostringstream ss1;
void check_log_signal( const string& s )
{
ss << s;
}
void check_alog_signal( const string& s )
{
ss1 << s;
}
int main( int argc, const char **argv )
{
DebugStream tlog;
......@@ -30,9 +37,31 @@ int main( int argc, const char **argv )
if( tlog.is_level1() )
tlog.level1() << ": is level1..." << endl;
cout << "==================" << endl;
cout << "===== Test 1 =====" << endl;
cout << ss.str();
cout << "==================" << endl;
DebugStream log1;
log1.setLogName("log1");
DebugStream log2;
log2.setLogName("log2");
LogAgregator la;
la.signal_stream_event().connect(&check_alog_signal);
la.add(log1);
la.add(log2);
log1 << "log1: test message..." << endl;
log2 << "log2: test message..." << endl;
la << "la: test message.." << endl;
cout << "===== Test 2 =====" << endl;
cout << ss1.str();
cout << "==================" << endl;
DebugStream* l = la.getLog("log1");
if( l != &log1 )
cout << "**** TEST FAILED: LogAgregator::getLog() " << endl;
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment