Commit 30c0a338 authored by Pavel Vainerman's avatar Pavel Vainerman

[logserver]: supported byte order, supported log filter by name

parent be4f3692
......@@ -8,6 +8,7 @@
#include "Exceptions.h"
#include "LogReader.h"
#include "LogServerTypes.h"
#include "LogAgregator.h"
// --------------------------------------------------------------------------
using namespace uniset;
using namespace std;
......
......@@ -154,15 +154,13 @@ int main( int argc, char** argv )
}
la->add(dlog);
auto la2 = make_shared<LogAgregator>("la2");
auto dlog3 = la2->create("dlog3");
auto dlog4 = la2->create("dlog4");
la2->add(dlog);
la2->add(dlog2);
la2->add(dlog3);
la2->add(dlog4);
la->add(la2);
......
......@@ -134,7 +134,7 @@ namespace uniset
{
public:
const std::string sep = {"/"}; /*< разделитель для имён подчинённых агрегаторов */
static const std::string sep; /*< разделитель для имён подчинённых агрегаторов ('/') */
explicit LogAgregator( const std::string& name, Debug::type t );
explicit LogAgregator( const std::string& name = "" );
......@@ -155,9 +155,11 @@ namespace uniset
void offLogFile( const std::string& logname );
void onLogFile( const std::string& logname );
// найти лог..
// найти лог.. (по полному составному имени)
std::shared_ptr<DebugStream> getLog( const std::string& logname );
bool logExist( std::shared_ptr<DebugStream>& l ) const;
std::shared_ptr<DebugStream> findByLogName( const std::string& logname ) const;
// -------------------------------------------------------------------------
struct iLog
{
......@@ -197,6 +199,9 @@ namespace uniset
// получить список с именами (длинными) и с указателями на логи
std::list<iLog> makeLogNameList( const std::string& prefix ) const;
// получить список по именам удовлетворяющим регулярному выражению (рекурсивная функция)
void getListByLogNameWithRule( std::list<iLog>& lst, const std::regex& rule, const std::string& prefix ) const;
private:
typedef std::unordered_map<std::string, std::shared_ptr<DebugStream>> LogMap;
LogMap lmap;
......
......@@ -26,7 +26,7 @@ namespace uniset
namespace LogServerTypes
{
const uint MAGICNUM = 0x20160417;
const uint32_t MAGICNUM = 20201222;
enum Command
{
cmdNOP, /*!< отсутствие команды */
......@@ -41,7 +41,7 @@ namespace uniset
cmdSaveLogLevel, /*!< запомнить текущее состояние логов (для восстановления при завершении сессии или команде Restore) */
cmdRestoreLogLevel, /*!< восстановить последнее запомненное (cmdSaveLogLevel) состояние логов (т.е. не восстанавливать как было, при завершении сессии) */
// команды требующий ответа..
// команды требующие ответа..
cmdList, /*!< вывести список контролируемых логов */
cmdFilterMode, /*!< включить режим работы "фильтр" - вывод только от интересующих логов, заданных в logname (regexp) */
cmdViewDefaultLogLevel /*!< вывести уровни логов сохранённых как умолчательный (cmdSaveLogLevel) */
......@@ -52,25 +52,19 @@ namespace uniset
struct lsMessage
{
lsMessage(): magic(MAGICNUM), cmd(cmdNOP), data(0)
{
std::memset(logname, 0, sizeof(logname));
}
explicit lsMessage( Command c, uint d, const std::string& logname ):
magic(MAGICNUM), cmd(c), data(d)
{
setLogName(logname);
}
lsMessage();
explicit lsMessage( Command c, uint32_t d, const std::string& logname );
uint magic;
Command cmd;
uint data;
uint8_t _be_order; // 1 - BE byte order, 0 - LE byte order
uint32_t magic;
uint32_t data;
uint8_t cmd;
static const size_t MAXLOGNAME = 120;
char logname[MAXLOGNAME + 1]; // +1 reserverd for '\0'
void setLogName( const std::string& name );
void convertFromNet() noexcept;
// для команды 'cmdSetLogFile'
// static const size_t MAXLOGFILENAME = 200;
......
......@@ -17,6 +17,7 @@
#include <memory>
#include <iomanip>
#include <sstream>
#include "UniSetTypes.h"
#include "DebugExtBuf.h"
#include "LogAgregator.h"
// -------------------------------------------------------------------------
......@@ -25,6 +26,8 @@ namespace uniset
// -------------------------------------------------------------------------
using namespace std;
// -------------------------------------------------------------------------
const std::string LogAgregator::sep = "/";
// -------------------------------------------------------------------------
LogAgregator::LogAgregator( const std::string& name ):
LogAgregator(name, Debug::ANY)
{
......@@ -200,34 +203,45 @@ namespace uniset
const std::string::size_type tab_width = 15;
ostringstream s;
s << " ." << g_tab;
s << setw(tab_width) << "." << g_tab;
string s_tab(s.str());
std::ios_base::fmtflags old_flags = os.flags();
uniset::ios_fmt_restorer ifs(os);
os << std::right << g_tab << setw(tab_width - 1) << std::right << getLogName() << sep << endl; // << setw(6) << " " << "[ " << Debug::str(DebugStream::level()) << " ]" << endl;
os << std::left << g_tab << getLogName() << sep << endl; // << setw(6) << " " << "[ " << Debug::str(DebugStream::level()) << " ]" << endl;
std::list<std::shared_ptr<LogAgregator>> lstA;
std::list<std::shared_ptr<DebugStream>> lst;
for( const auto& l : lmap )
{
auto ag = dynamic_pointer_cast<LogAgregator>(l.second);
if( ag )
lstA.push_back(ag);
else
lst.push_back(l.second);
}
lst.sort([](const std::shared_ptr<DebugStream>& a, const std::shared_ptr<DebugStream>& b)
{
return a->getLogName() < b->getLogName();
});
for( auto&& l : lst )
lstA.sort([](const std::shared_ptr<LogAgregator>& a, const std::shared_ptr<LogAgregator>& b)
{
auto ag = dynamic_pointer_cast<LogAgregator>(l);
return a->getLogName() < b->getLogName();
});
if( ag )
ag->printTree(os, s_tab);
else
// сперва выводим просто логи
for( auto&& l : lst )
os << s_tab << setw(tab_width) << std::right << l->getLogName() << std::left << " [ " << Debug::str(l->level()) << " ]" << endl;
}
os.setf(old_flags);
// потом дочерние агрегаторы
for( auto&& ag : lstA )
ag->printTree(os, s_tab);
return os;
}
// -------------------------------------------------------------------------
......@@ -276,6 +290,29 @@ namespace uniset
return false;
}
// -------------------------------------------------------------------------
std::shared_ptr<DebugStream> LogAgregator::findByLogName( const std::string& logname ) const
{
std::shared_ptr<DebugStream> log;
for( const auto& l : lmap )
{
if( l.second->getLogName() == logname )
return l.second;
auto ag = dynamic_pointer_cast<LogAgregator>(l.second);
if( ag )
{
log = ag->findByLogName(logname);
if( log != nullptr )
return log;
}
}
return nullptr;
}
// -------------------------------------------------------------------------
std::shared_ptr<DebugStream> LogAgregator::findLog( const std::string& lname ) const
{
auto v = splitFirst(lname, sep);
......@@ -303,30 +340,52 @@ namespace uniset
return ag->findLog(v[1]); // рекурсия
}
// -------------------------------------------------------------------------
std::list<LogAgregator::iLog> LogAgregator::getLogList( const std::string& regex_str ) const
void LogAgregator::getListByLogNameWithRule( std::list<LogAgregator::iLog>& lst, const std::regex& rule, const std::string& prefix ) const
{
std::list<LogAgregator::iLog> l;
ostringstream s;
s << prefix << getLogName();
const string p2 = s.str() + sep;
try
for( const auto& l : lmap )
{
std::regex rule(regex_str);
auto lst = getLogList();
auto ag = dynamic_pointer_cast<LogAgregator>(l.second);
for( const auto& i : lst )
if( !std::regex_match(l.second->getLogName(), rule) )
{
if( std::regex_search(i.name, rule) )
// recursive
if( ag )
ag->getListByLogNameWithRule(lst, rule, p2);
continue;
}
if( !ag )
{
l.push_back(i);
const std::string nm(p2 + l.second->getLogName());
lst.emplace_back(l.second, std::move(nm) );
continue;
}
// add all childs
lst.splice(lst.end(), ag->getLogList());
}
}
// -------------------------------------------------------------------------
std::list<LogAgregator::iLog> LogAgregator::getLogList( const std::string& regex_str ) const
{
std::list<LogAgregator::iLog> lst;
try
{
std::regex rule(regex_str);
getListByLogNameWithRule(lst, rule, "");
}
catch( const std::exception& ex )
{
cerr << "(LogAgregator::getLogList): " << ex.what() << std::endl;
}
return l;
return lst;
}
// -------------------------------------------------------------------------
std::list<LogAgregator::iLog> LogAgregator::getLogList() const
......@@ -345,12 +404,9 @@ namespace uniset
ostringstream s;
s << prefix << getLogName();
const string p2 = s.str() + sep;
string p(s.str());
string p2(p + sep);
for( auto&& l : lmap )
for( const auto& l : lmap )
{
auto ag = dynamic_pointer_cast<LogAgregator>(l.second);
......
......@@ -17,13 +17,73 @@
#include "UniSetTypes.h"
#include "LogServerTypes.h"
#include "Debug.h"
// -------------------------------------------------------------------------
#if __BYTE_ORDER != __LITTLE_ENDIAN && __BYTE_ORDER != __BIG_ENDIAN
#error LogServerTypes: Unknown byte order!
#endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define LE32_TO_H(x) {}
#else
#define LE32_TO_H(x) x = le32toh(x)
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
#define BE32_TO_H(x) {}
#else
#define BE32_TO_H(x) x = be32toh(x)
#endif
// -------------------------------------------------------------------------
namespace uniset
{
// -------------------------------------------------------------------------
using namespace std;
// -------------------------------------------------------------------------
LogServerTypes::lsMessage::lsMessage():
magic(MAGICNUM),
cmd(cmdNOP),
data(0)
{
std::memset(logname, 0, sizeof(logname));
#if __BYTE_ORDER == __LITTLE_ENDIAN
_be_order = 0;
#elif __BYTE_ORDER == __BIG_ENDIAN
_be_order = 1;
#endif
}
// -------------------------------------------------------------------------
LogServerTypes::lsMessage::lsMessage( Command c, uint32_t d, const std::string& logname ):
magic(MAGICNUM), cmd(c), data(d)
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
_be_order = 0;
#elif __BYTE_ORDER == __BIG_ENDIAN
_be_order = 1;
#endif
setLogName(logname);
}
// -------------------------------------------------------------------------
void LogServerTypes::lsMessage::convertFromNet() noexcept
{
if( _be_order )
{
BE32_TO_H(data);
BE32_TO_H(magic);
}
else
{
LE32_TO_H(data);
LE32_TO_H(magic);
}
#if __BYTE_ORDER == __LITTLE_ENDIAN
_be_order = 0;
#elif __BYTE_ORDER == __BIG_ENDIAN
_be_order = 1;
#endif
}
// -------------------------------------------------------------------------
std::ostream& LogServerTypes::operator<<(std::ostream& os, LogServerTypes::Command cmd )
{
switch( cmd )
......@@ -130,7 +190,7 @@ namespace uniset
else if( c == "-d" || c == "--del" )
{
LogServerTypes::Command cmd = LogServerTypes::cmdDelLevel;
vcmd.emplace_back(cmd, (int)Debug::value(arg1), filter);
vcmd.emplace_back(cmd, (uint32_t)Debug::value(arg1), filter);
}
}
......
......@@ -401,6 +401,8 @@ namespace uniset
if( ret == 0 || cancelled )
return;
msg.convertFromNet();
if( ret != sizeof(msg) || msg.magic != LogServerTypes::MAGICNUM )
{
if( mylog.is_warn() )
......@@ -421,7 +423,7 @@ namespace uniset
}
if( mylog.is_info() )
mylog.info() << peername << "(LogSession::readEvent): receive command: '" << msg.cmd << "'" << endl;
mylog.info() << peername << "(LogSession::readEvent): receive command: '" << (LogServerTypes::Command)msg.cmd << "'" << endl;
string cmdLogName(msg.logname);
......@@ -483,14 +485,14 @@ namespace uniset
if( alog ) // если у нас "агрегатор", то работаем с его списком потоков
{
if( cmdLogName.empty() || cmdLogName == "ALL" )
if( cmdLogName.empty() || cmdLogName == "ALL" || cmdLogName == alog->getLogName())
loglist = alog->getLogList();
else
loglist = alog->getLogList(cmdLogName);
}
else
{
if( cmdLogName.empty() || cmdLogName == "ALL" || log->getLogFile() == cmdLogName )
if( cmdLogName.empty() || cmdLogName == "ALL" || log->getLogName() == cmdLogName )
loglist.emplace_back(log, log->getLogName());
}
......@@ -568,7 +570,7 @@ namespace uniset
try
{
std::string ret( m_command_sig.emit(this, msg.cmd, cmdLogName) );
std::string ret( m_command_sig.emit(this, LogServerTypes::Command(msg.cmd), cmdLogName) );
if( !ret.empty() )
{
......
......@@ -262,25 +262,95 @@ TEST_CASE("MaxSessions", "[LogServer]" )
ret2.get();
}
// --------------------------------------------------------------------------
TEST_CASE("LogAgregator regexp", "[LogAgregator]" )
TEST_CASE("LogAgregator regexp", "[LogAgregator][regexp]" )
{
auto la = make_shared<LogAgregator>("ROOT");
auto log1 = la->create("log1");
auto log2 = la->create("log2");
auto log3 = la->create("a3/log1");
auto log4 = la->create("a3/log2");
auto log5 = la->create("a3/log3");
auto log6 = la->create("a3/a4/log1");
auto log7 = la->create("a3/a4/log2");
auto log31 = la->create("a3-log1");
auto log32 = la->create("a3-log2");
auto log33 = la->create("a3-log3");
auto log341 = la->create("a3-a4-log1");
auto log342 = la->create("a3-a4-log2");
auto lst = la->getLogList(".*/a4/.*");
auto lst = la->getLogList(".*a4.*");
REQUIRE( lst.size() == 2 );
lst = la->getLogList(".*a3/.*");
lst = la->getLogList(".*a3.*");
REQUIRE( lst.size() == 5 );
lst = la->getLogList(".*log1.*");
REQUIRE( lst.size() == 3 );
lst = la->getLogList("log1");
REQUIRE( lst.size() == 1 );
lst = la->getLogList("log2");
REQUIRE( lst.size() == 1 );
lst = la->getLogList("a3-log3");
REQUIRE( lst.size() == 1 );
lst = la->getLogList("a4-.*");
REQUIRE( lst.size() == 0 );
// la/la2/log5
// la/la2/log6
// la/la2/la3/log7
// la/la2/la3/log8
auto la2 = make_shared<LogAgregator>("la2");
auto la3 = make_shared<LogAgregator>("la3");
la2->add(la3);
la->add(la2);
auto log5 = la2->create("log5");
auto log6 = la2->create("log6");
auto log7 = la3->create("log7");
auto log8 = la3->create("log8");
lst = la->getLogList("la2"); // log5,log6 + la3/log7,la3/log8
REQUIRE( lst.size() == 4 );
lst = la->getLogList("la3"); // log7,log8
REQUIRE( lst.size() == 2 );
lst = la->getLogList("log.*"); // log[125678]
REQUIRE( lst.size() == 6 );
}
// --------------------------------------------------------------------------
TEST_CASE("LogAgregator findlog", "[LogAgregator][getLog]" )
{
auto la = make_shared<LogAgregator>("ROOT");
auto log1 = la->create("log1");
auto la2 = make_shared<LogAgregator>("la2");
la->add(la2);
auto log2 = la2->create("log2");
auto la3 = make_shared<LogAgregator>("la3");
auto log3 = la3->create("log3");
la2->add(la3);
auto log = la->findByLogName("log1");
REQUIRE( log != nullptr );
REQUIRE( log->getLogName() == "log1" );
log = la->findByLogName("log2");
REQUIRE( log != nullptr );
REQUIRE( log->getLogName() == "log2" );
log = la->findByLogName("log3");
REQUIRE( log != nullptr );
REQUIRE( log->getLogName() == "log3" );
auto agg = la->findByLogName("la2");
REQUIRE( agg != nullptr );
REQUIRE( agg->getLogName() == "la2" );
agg = la->findByLogName("la3");
REQUIRE( agg != nullptr );
REQUIRE( agg->getLogName() == "la3" );
}
// --------------------------------------------------------------------------
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