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

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

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