Commit 44ddbeb2 authored by Pavel Vainerman's avatar Pavel Vainerman

(LogServer): вторая версия реализации восстановления уровней логов,

при завершении работы. Перенёс логику в LogServer. Теперь уровни запоминаются при первом подключении, а восстанавливаются при отключении последней сессии.
parent 6b0af9f6
...@@ -74,14 +74,6 @@ libev ...@@ -74,14 +74,6 @@ libev
SM: подумать насчёт асинхронности публикации событий и посылки уведомления (setValue/push) через очередь.. SM: подумать насчёт асинхронности публикации событий и посылки уведомления (setValue/push) через очередь..
LogServer: подумать насчёт автоматического отключение уровней логов, если они не пишутся в файл
и нет активных удалённых сессий (иначе включённые логи сильно грузят процессор, при обычно,
подключаются.. смотрят.. а отключить уже забывают.
(вариант реализации: запоминаем по списку умолчатльные настройки при старте сессии, после завершения восстанавливаем.
Но сделать специальную команду, отключающую восстановление при выходе.)
version 3 version 3
========= =========
- подумать нужен ли нам где-то ZeroMQ (zerorpc) (вместо omniORB?) - подумать нужен ли нам где-то ZeroMQ (zerorpc) (вместо omniORB?)
......
...@@ -59,7 +59,7 @@ static void print_help() ...@@ -59,7 +59,7 @@ static void print_help()
printf("[-e | --on] [logfilter] - On(enable) the write log file (if before disabled).\n"); printf("[-e | --on] [logfilter] - On(enable) the write log file (if before disabled).\n");
printf("[-r | --rotate] [logfilter] - rotate log file.\n"); printf("[-r | --rotate] [logfilter] - rotate log file.\n");
printf("[-u | --save-loglevels] [logfilter] - save log levels (disable restore after disconnected).\n"); printf("[-u | --save-loglevels] [logfilter] - save log levels (disable restore after disconnected).\n");
// printf("[-g | --restore-loglevels] [logfilter] - restore default log levels.\n"); printf("[-g | --restore-loglevels] [logfilter] - restore default log levels.\n");
printf("[-b | --view-default-loglevels] [logfilter] - list of default log levels.\n"); printf("[-b | --view-default-loglevels] [logfilter] - list of default log levels.\n");
printf("[-l | --list] [logfilter] - List of managed logs.\n"); printf("[-l | --list] [logfilter] - List of managed logs.\n");
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <list> #include <list>
#include <string> #include <string>
#include <memory> #include <memory>
#include <unordered_map>
#include <cc++/socket.h> #include <cc++/socket.h>
#include <ev++.h> #include <ev++.h>
#include "Mutex.h" #include "Mutex.h"
...@@ -28,6 +29,7 @@ ...@@ -28,6 +29,7 @@
#include "ThreadCreator.h" #include "ThreadCreator.h"
#include "UTCPSocket.h" #include "UTCPSocket.h"
#include "CommonEventLoop.h" #include "CommonEventLoop.h"
#include "LogServerTypes.h"
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
class LogSession; class LogSession;
class LogAgregator; class LogAgregator;
...@@ -41,9 +43,12 @@ LogReader. Читающих клиентов может быть скольуг ...@@ -41,9 +43,12 @@ LogReader. Читающих клиентов может быть скольуг
записью, отключением записи или ротацией файла с логами. DebugStream за которым ведётся "слежение" записью, отключением записи или ротацией файла с логами. DebugStream за которым ведётся "слежение"
задаётся в конструкторе для LogServer. задаётся в конструкторе для LogServer.
По умолчанию LogServer при завершении автоматически восстаналивает уровни логов, которые были при подключении. По умолчанию, при завершении \b ВСЕХ подключений, LogServer автоматически восстанавливает уровни логов,
Но если была передана команда LogServerTypes::cmdSaveLogLevel, то после отключения (завершения сессии), которые были на момент \b первого \b подключения.
будут сохранены те уровни, которые выставлены подключившимся клиентом. Но если была передана команда LogServerTypes::cmdSaveLogLevel (в любом из подключений), то будут сохранены те уровни,
которые выставлены подключившимся клиентом.
Для этого LogServer подключается к сигналу на получение команд у каждой сессии и сам обрабатывает команды,
на сохранение, восстановление и показ текущих "умолчательных" логов.
\code \code
DebugStream mylog; DebugStream mylog;
...@@ -127,10 +132,14 @@ class LogServer: ...@@ -127,10 +132,14 @@ class LogServer:
void ioAccept( ev::io& watcher, int revents ); void ioAccept( ev::io& watcher, int revents );
void sessionFinished( LogSession* s ); void sessionFinished( LogSession* s );
void saveDefaultLogLevels( const std::string& logname );
void restoreDefaultLogLevels( const std::string& logname );
std::string onCommand( LogSession* s, LogServerTypes::Command cmd, const std::string& logname );
private: private:
typedef std::list< std::shared_ptr<LogSession> > SessionList; typedef std::list< std::shared_ptr<LogSession> > SessionList;
SessionList slist; SessionList slist;
size_t scount = { 0 };
UniSetTypes::uniset_rwmutex mutSList; UniSetTypes::uniset_rwmutex mutSList;
timeout_t timeout; timeout_t timeout;
...@@ -147,6 +156,12 @@ class LogServer: ...@@ -147,6 +156,12 @@ class LogServer:
std::shared_ptr<UTCPSocket> sock; std::shared_ptr<UTCPSocket> sock;
std::shared_ptr<DebugStream> elog; // eventlog.. std::shared_ptr<DebugStream> elog; // eventlog..
// map с уровнями логов по умолчанию (инициализируются при создании первой сессии),
// (они необходимы для восстановления настроек после завершения всех (!) сессий)
// т.к. shared_ptr-ов может быть много, то в качестве ключа используем указатель на "реальный объект"(внутри shared_ptr)
// но только для этого(!), пользоваться этим указателем ни в коем случае нельзя (и нужно проверять shared_ptr на существование)
std::unordered_map< DebugStream*,Debug::type > defaultLogLevels;
std::string myname = { "LogServer" }; std::string myname = { "LogServer" };
std::string addr; std::string addr;
ost::tpport_t port; ost::tpport_t port;
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include <queue> #include <queue>
#include <unordered_map>
#include <cc++/socket.h> #include <cc++/socket.h>
#include <ev++.h> #include <ev++.h>
#include "Mutex.h" #include "Mutex.h"
...@@ -40,6 +39,11 @@ class LogSession ...@@ -40,6 +39,11 @@ class LogSession
typedef sigc::slot<void, LogSession*> FinalSlot; typedef sigc::slot<void, LogSession*> FinalSlot;
void connectFinalSession( FinalSlot sl ); void connectFinalSession( FinalSlot sl );
// сигнал о приходе команды: std::string func( LogSession*, command, logname );
// \return какую-то информацию, которая будет послана client-у. Если return.empty(), то ничего послано не будет.
typedef sigc::signal<std::string,LogSession*,LogServerTypes::Command, const std::string& > LogSessionCommand_Signal;
LogSessionCommand_Signal signal_logsession_command();
inline void cancel() inline void cancel()
{ {
cancelled = true; cancelled = true;
...@@ -97,7 +101,7 @@ class LogSession ...@@ -97,7 +101,7 @@ class LogSession
float checkConnectionTime = { 10. }; // время на проверку живости соединения..(сек) float checkConnectionTime = { 10. }; // время на проверку живости соединения..(сек)
// Т.к. сообщений может быть ОЧЕНЬ МНОГО.. сеть медленная // Т.к. сообщений может быть ОЧЕНЬ МНОГО.. сеть медленная
// очередь может не успевать рассасываться, // очередь будет не успевать рассасываться,
// то потенциально может "скушаться" вся память. // то потенциально может "скушаться" вся память.
// Поэтому приходиться ограничить доступное количество записей. // Поэтому приходиться ограничить доступное количество записей.
// Рассчитываем, что средний размер одного сообщения 150 символов (байт) // Рассчитываем, что средний размер одного сообщения 150 символов (байт)
...@@ -122,12 +126,6 @@ class LogSession ...@@ -122,12 +126,6 @@ class LogSession
std::shared_ptr<LogAgregator> alog; std::shared_ptr<LogAgregator> alog;
sigc::connection conn; sigc::connection conn;
// map с уровнями логов по умолчанию (инициализируются при создании сессии),
// (они необходимы для восстановления настроек после завершения сессии)
// т.к. shared_ptr-ов может быть много, то в качестве ключа используем указатель на "реальный объект"(внутри shared_ptr)
// но только для этого(!), пользоваться этим указателем ни в коем случае нельзя (и нужно проверять shared_ptr на существование)
std::unordered_map< DebugStream*,Debug::type > defaultLogLevels;
std::shared_ptr<USocket> sock; std::shared_ptr<USocket> sock;
ev::io io; ev::io io;
...@@ -138,6 +136,8 @@ class LogSession ...@@ -138,6 +136,8 @@ class LogSession
FinalSlot slFin; FinalSlot slFin;
std::atomic_bool cancelled = { false }; std::atomic_bool cancelled = { false };
LogSessionCommand_Signal m_command_sig;
DebugStream mylog; DebugStream mylog;
}; };
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
#include <sstream> #include <sstream>
#include <iomanip>
#include "LogServer.h" #include "LogServer.h"
#include "UniSetTypes.h" #include "UniSetTypes.h"
#include "Exceptions.h" #include "Exceptions.h"
...@@ -176,7 +177,7 @@ void LogServer::ioAccept( ev::io& watcher, int revents ) ...@@ -176,7 +177,7 @@ void LogServer::ioAccept( ev::io& watcher, int revents )
{ {
uniset_rwmutex_wrlock l(mutSList); uniset_rwmutex_wrlock l(mutSList);
if( slist.size() >= sessMaxCount ) if( scount >= sessMaxCount )
{ {
if( mylog.is_crit() ) if( mylog.is_crit() )
mylog.crit() << myname << "(LogServer::ioAccept): session limit(" << sessMaxCount << ")" << endl; mylog.crit() << myname << "(LogServer::ioAccept): session limit(" << sessMaxCount << ")" << endl;
...@@ -191,8 +192,14 @@ void LogServer::ioAccept( ev::io& watcher, int revents ) ...@@ -191,8 +192,14 @@ void LogServer::ioAccept( ev::io& watcher, int revents )
auto s = make_shared<LogSession>( watcher.fd, elog, cmdTimeout ); auto s = make_shared<LogSession>( watcher.fd, elog, cmdTimeout );
s->setSessionLogLevel(sessLogLevel); s->setSessionLogLevel(sessLogLevel);
s->connectFinalSession( sigc::mem_fun(this, &LogServer::sessionFinished) ); s->connectFinalSession( sigc::mem_fun(this, &LogServer::sessionFinished) );
s->signal_logsession_command().connect( sigc::mem_fun(this, &LogServer::onCommand) );
{ {
uniset_rwmutex_wrlock l(mutSList); uniset_rwmutex_wrlock l(mutSList);
scount++;
// на первой сессии запоминаем состояние логов
if( scount == 1 )
saveDefaultLogLevels("ALL");
slist.push_back(s); slist.push_back(s);
} }
...@@ -213,9 +220,17 @@ void LogServer::sessionFinished( LogSession* s ) ...@@ -213,9 +220,17 @@ void LogServer::sessionFinished( LogSession* s )
if( i->get() == s ) if( i->get() == s )
{ {
slist.erase(i); slist.erase(i);
return; scount--;
break;
} }
} }
if( slist.empty() )
{
scount = 0;
// восстанавливаем уровни логов по умолчанию
restoreDefaultLogLevels("ALL");
}
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void LogServer::init( const std::string& prefix, xmlNode* cnode ) void LogServer::init( const std::string& prefix, xmlNode* cnode )
...@@ -250,3 +265,110 @@ string LogServer::getShortInfo() ...@@ -250,3 +265,110 @@ string LogServer::getShortInfo()
return std::move(inf.str()); return std::move(inf.str());
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void LogServer::saveDefaultLogLevels( const std::string& logname )
{
if( mylog.is_info() )
mylog.info() << myname << "(saveDefaultLogLevels): SAVE DEFAULT LOG LEVELS.." << endl;
auto alog = dynamic_pointer_cast<LogAgregator>(elog);
if( alog )
{
std::list<LogAgregator::iLog> lst;
if( logname.empty() || logname == "ALL" )
lst = alog->getLogList();
else
lst = alog->getLogList(logname);
for( auto&& l: lst )
defaultLogLevels[l.log.get()] = l.log->level();
}
else if( elog )
defaultLogLevels[elog.get()] = elog->level();
}
// -----------------------------------------------------------------------------
void LogServer::restoreDefaultLogLevels( const std::string& logname )
{
if( mylog.is_info() )
mylog.info() << myname << "(restoreDefaultLogLevels): RESTORE DEFAULT LOG LEVELS.." << endl;
auto alog = dynamic_pointer_cast<LogAgregator>(elog);
if( alog )
{
std::list<LogAgregator::iLog> lst;
if( logname.empty() || logname == "ALL" )
lst = alog->getLogList();
else
lst = alog->getLogList(logname);
for( auto&& l: lst )
{
auto d = defaultLogLevels.find(l.log.get());
if( d != defaultLogLevels.end() )
l.log->level(d->second);
}
}
else if( elog )
{
auto d = defaultLogLevels.find(elog.get());
if( d != defaultLogLevels.end() )
elog->level(d->second);
}
}
// -----------------------------------------------------------------------------
std::string LogServer::onCommand( LogSession* s, LogServerTypes::Command cmd, const std::string& logname )
{
if( cmd == LogServerTypes::cmdSaveLogLevel )
{
saveDefaultLogLevels(logname);
}
else if( cmd == LogServerTypes::cmdRestoreLogLevel )
{
restoreDefaultLogLevels(logname);
}
else if( cmd == LogServerTypes::cmdViewDefaultLogLevel )
{
ostringstream s;
s << "List of saved default log levels (filter='" << logname << "')[" << defaultLogLevels.size() << "]: " << endl;
s << "=================================" << endl;
auto alog = dynamic_pointer_cast<LogAgregator>(elog);
if( alog ) // если у нас "агрегатор", то работаем с его списком потоков
{
std::list<LogAgregator::iLog> lst;
if( logname.empty() || logname == "ALL" )
lst = alog->getLogList();
else
lst = alog->getLogList(logname);
std::string::size_type max_width = 1;
// ищем максимальное название для выравнивания по правому краю
for( const auto& l : lst )
max_width = std::max(max_width, l.name.length() );
for( const auto& l : lst )
{
Debug::type deflevel = Debug::NONE;
auto i = defaultLogLevels.find(l.log.get());
if( i != defaultLogLevels.end() )
deflevel = i->second;
s << std::left << setw(max_width) << l.name << std::left << " [ " << Debug::str(deflevel) << " ]" << endl;
}
}
else if( elog )
{
Debug::type deflevel = Debug::NONE;
auto i = defaultLogLevels.find(elog.get());
if( i != defaultLogLevels.end() )
deflevel = i->second;
s << elog->getLogName() << " [" << Debug::str(deflevel) << " ]" << endl;
}
s << "=================================" << endl << endl;
return std::move(s.str());
}
return "";
}
// -----------------------------------------------------------------------------
...@@ -62,14 +62,7 @@ LogSession::LogSession( int sfd, std::shared_ptr<DebugStream>& _log, timeout_t _ ...@@ -62,14 +62,7 @@ LogSession::LogSession( int sfd, std::shared_ptr<DebugStream>& _log, timeout_t _
auto ag = dynamic_pointer_cast<LogAgregator>(log); auto ag = dynamic_pointer_cast<LogAgregator>(log);
if( ag ) if( ag )
{
alog = ag; alog = ag;
auto lst = alog->getLogList();
for( auto&& l: lst )
defaultLogLevels.emplace(l.log.get(),l.log->level());
}
else
defaultLogLevels.emplace(log.get(),log->level());
try try
{ {
...@@ -483,71 +476,24 @@ void LogSession::cmdProcessing( const string& cmdLogName, const LogServerTypes:: ...@@ -483,71 +476,24 @@ void LogSession::cmdProcessing( const string& cmdLogName, const LogServerTypes::
io.set(ev::WRITE); io.set(ev::WRITE);
} }
else if( msg.cmd == LogServerTypes::cmdSaveLogLevel )
{ try
// обновляем умолчательные значения для текущих уровней логов
if( alog )
{
for( const auto& l : loglist )
defaultLogLevels[l.log.get()] = l.log->level();
}
else if( log )
defaultLogLevels[log.get()] = log->level();
}
else if( msg.cmd == LogServerTypes::cmdRestoreLogLevel )
{ {
// восстанавливаем уровни логов std::string ret( std::move(m_command_sig.emit(this,msg.cmd,cmdLogName)) );
if( alog ) if( !ret.empty() )
{ {
for( const auto& l : loglist )
{ {
auto i = defaultLogLevels.find(l.log.get()); std::unique_lock<std::mutex> lk(logbuf_mutex);
if( i!= defaultLogLevels.end() ) logbuf.emplace(new UTCPCore::Buffer( std::move(ret) ));
l.log->level(i->second);
} }
io.set(ev::WRITE);
} }
else if( log )
log->level(defaultLogLevels[log.get()]);
} }
else if( msg.cmd == LogServerTypes::cmdViewDefaultLogLevel ) catch( std::exception& ex )
{ {
ostringstream s; if( mylog.is_warn() )
s << "List of saved default log levels (filter='" << cmdLogName << "')[" << defaultLogLevels.size() << "]: " << endl; mylog.warn() << peername << "(cmdProcessing): " << ex.what() << endl;
s << "=================================" << endl;
if( alog ) // если у нас "агрегатор", то работаем с его списком потоков
{
std::string::size_type max_width = 1;
// ищем максимальное название для выравнивания по правому краю
for( const auto& l : loglist )
max_width = std::max(max_width, l.name.length() );
for( const auto& l : loglist )
{
Debug::type deflevel = Debug::NONE;
auto i = defaultLogLevels.find(l.log.get());
if( i != defaultLogLevels.end() )
deflevel = i->second;
s << std::left << setw(max_width) << l.name << std::left << " [ " << Debug::str(deflevel) << " ]" << endl;
}
}
else if( log )
{
Debug::type deflevel = Debug::NONE;
auto i = defaultLogLevels.find(log.get());
if( i != defaultLogLevels.end() )
deflevel = i->second;
s << log->getLogName() << " [" << Debug::str(deflevel) << " ]" << endl;
}
s << "=================================" << endl << endl;
{
std::unique_lock<std::mutex> lk(logbuf_mutex);
logbuf.emplace(new UTCPCore::Buffer(s.str()));
}
io.set(ev::WRITE);
} }
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
...@@ -592,27 +538,6 @@ void LogSession::onCheckConnectionTimer( ev::timer& watcher, int revents ) ...@@ -592,27 +538,6 @@ void LogSession::onCheckConnectionTimer( ev::timer& watcher, int revents )
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void LogSession::final() void LogSession::final()
{ {
// восстаналиваем уровни логов, какие были в начале или были сохранены командой cmdSaveLogLevel
if( alog )
{
auto lst = alog->getLogList();
for( auto&& l: lst )
{
if( !l.log )
continue;
auto i = defaultLogLevels.find(l.log.get());
if( i!=defaultLogLevels.end() )
l.log->level( i->second );
}
}
else if( log )
{
auto i = defaultLogLevels.find(log.get());
if( i!=defaultLogLevels.end() )
log->level(i->second);
}
slFin(this); slFin(this);
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
...@@ -621,6 +546,11 @@ void LogSession::connectFinalSession( FinalSlot sl ) ...@@ -621,6 +546,11 @@ void LogSession::connectFinalSession( FinalSlot sl )
slFin = sl; slFin = sl;
} }
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
LogSession::LogSessionCommand_Signal LogSession::signal_logsession_command()
{
return m_command_sig;
}
// ---------------------------------------------------------------------
void LogSession::setMaxBufSize( size_t num ) void LogSession::setMaxBufSize( size_t num )
{ {
std::unique_lock<std::mutex> lk(logbuf_mutex); std::unique_lock<std::mutex> lk(logbuf_mutex);
......
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