Commit 6b0af9f6 authored by Pavel Vainerman's avatar Pavel Vainerman

(LogServer): первая версия реализации автоматического

восстановления логов после отключения от логсервера
parent e3263be4
...@@ -65,6 +65,8 @@ Version 2.5 ...@@ -65,6 +65,8 @@ Version 2.5
- Использовать PIMPL - Использовать PIMPL
- подумать.. это серьёзная переделка кода.. - подумать.. это серьёзная переделка кода..
- Вылетать с ошибкой если в секции <thresholds> указан не существующий датчик
libev libev
======= =======
- переписать UNetUDP (на подумать) - переписать UNetUDP (на подумать)
...@@ -72,6 +74,14 @@ libev ...@@ -72,6 +74,14 @@ libev
SM: подумать насчёт асинхронности публикации событий и посылки уведомления (setValue/push) через очередь.. SM: подумать насчёт асинхронности публикации событий и посылки уведомления (setValue/push) через очередь..
LogServer: подумать насчёт автоматического отключение уровней логов, если они не пишутся в файл
и нет активных удалённых сессий (иначе включённые логи сильно грузят процессор, при обычно,
подключаются.. смотрят.. а отключить уже забывают.
(вариант реализации: запоминаем по списку умолчатльные настройки при старте сессии, после завершения восстанавливаем.
Но сделать специальную команду, отключающую восстановление при выходе.)
version 3 version 3
========= =========
- подумать нужен ли нам где-то ZeroMQ (zerorpc) (вместо omniORB?) - подумать нужен ли нам где-то ZeroMQ (zerorpc) (вместо omniORB?)
......
...@@ -23,6 +23,9 @@ static struct option longopts[] = ...@@ -23,6 +23,9 @@ static struct option longopts[] =
{ "set", required_argument, 0, 's' }, { "set", required_argument, 0, 's' },
{ "off", required_argument, 0, 'o' }, { "off", required_argument, 0, 'o' },
{ "on", required_argument, 0, 'e' }, { "on", required_argument, 0, 'e' },
{ "save-loglevels", required_argument, 0, 'u' },
{ "restore-loglevels", required_argument, 0, 'g' },
{ "view-default-loglevels", required_argument, 0, 'b' },
{ "list", optional_argument, 0, 'l' }, { "list", optional_argument, 0, 'l' },
{ "rotate", optional_argument, 0, 'r' }, { "rotate", optional_argument, 0, 'r' },
{ "logfilter", required_argument, 0, 'n' }, { "logfilter", required_argument, 0, 'n' },
...@@ -49,14 +52,18 @@ static void print_help() ...@@ -49,14 +52,18 @@ static void print_help()
printf("\n"); printf("\n");
printf("Commands:\n"); printf("Commands:\n");
printf("[--add | -a] info,warn,crit,... [logfilter] - Add log levels.\n"); printf("[-a | --add] info,warn,crit,... [logfilter] - Add log levels.\n");
printf("[--del | -d] info,warn,crit,... [logfilter] - Delete log levels.\n"); printf("[-d | --del] info,warn,crit,... [logfilter] - Delete log levels.\n");
printf("[--set | -s] info,warn,crit,... [logfilter] - Set log levels.\n"); printf("[-s | --set] info,warn,crit,... [logfilter] - Set log levels.\n");
printf("--off, -o [logfilter] - Off the write log file (if enabled).\n"); printf("[-o | --off] [logfilter] - Off the write log file (if enabled).\n");
printf("--on, -e [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("--rotate, -r [logfilter] - rotate log file.\n"); printf("[-r | --rotate] [logfilter] - rotate log file.\n");
printf("--list, -l [logfilter] - List of managed logs.\n"); printf("[-u | --save-loglevels] [logfilter] - save log levels (disable restore after disconnected).\n");
printf("--filter, -f logfilter - ('filter mode'). View log only from 'logfilter'(regexp)\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");
printf("[-f | --filter] logfilter - ('filter mode'). View log only from 'logfilter'(regexp)\n");
printf("\n"); printf("\n");
printf("Note: 'logfilter' - regexp for name of log. Default: ALL logs.\n"); printf("Note: 'logfilter' - regexp for name of log. Default: ALL logs.\n");
} }
...@@ -87,7 +94,7 @@ int main( int argc, char** argv ) ...@@ -87,7 +94,7 @@ int main( int argc, char** argv )
{ {
while(1) while(1)
{ {
opt = getopt_long(argc, argv, "chvlf:a:p:i:d:s:n:eorbx:w:zt:", longopts, &optindex); opt = getopt_long(argc, argv, "chvlf:a:p:i:d:s:n:eorbx:w:zt:gub", longopts, &optindex);
if( opt == -1 ) if( opt == -1 )
break; break;
...@@ -166,6 +173,46 @@ int main( int argc, char** argv ) ...@@ -166,6 +173,46 @@ int main( int argc, char** argv )
} }
break; break;
case 'u': // --save-loglevels
{
LogServerTypes::Command cmd = LogServerTypes::cmdSaveLogLevel;
std::string filter("");
char* arg2 = checkArg(optind, argc, argv);
if( arg2 )
filter = string(arg2);
vcmd.push_back( LogReader::Command(cmd, 0, filter) );
}
break;
case 'g': // --restore-loglevels
{
LogServerTypes::Command cmd = LogServerTypes::cmdRestoreLogLevel;
std::string filter("");
char* arg2 = checkArg(optind, argc, argv);
if( arg2 )
filter = string(arg2);
vcmd.push_back( LogReader::Command(cmd, 0, filter) );
}
break;
case 'b': // --view-default-loglevels
{
cmdonly = 1;
LogServerTypes::Command cmd = LogServerTypes::cmdViewDefaultLogLevel;
std::string filter("");
char* arg2 = checkArg(optind, argc, argv);
if( arg2 )
filter = string(arg2);
vcmd.push_back( LogReader::Command(cmd, 0, filter) );
}
break;
case 'e': case 'e':
{ {
LogServerTypes::Command cmd = LogServerTypes::cmdOnLogFile; LogServerTypes::Command cmd = LogServerTypes::cmdOnLogFile;
......
...@@ -2,12 +2,17 @@ if HAVE_TESTS ...@@ -2,12 +2,17 @@ if HAVE_TESTS
noinst_PROGRAMS = tests noinst_PROGRAMS = tests
tests_SOURCES = NullSM.cc TestObject_SK.h TestObject_SK.cc TestObject.cc tests.cc test_sm.cc BUILT_SOURCES = TestObject_SK.cc TestObject_SK.h
TestObject_SK.cc TestObject_SK.h: testobject.src.xml
$(UNISET_CODEGEN) -l $(top_builddir)/Utilities/codegen -n TestObject --topdir $(top_builddir)/ --ask --no-main testobject.src.xml
tests_SOURCES = TestObject_SK.cc NullSM.cc TestObject.cc test_sm.cc tests.cc
tests_LDADD = $(top_builddir)/lib/libUniSet2.la $(top_builddir)/extensions/lib/libUniSet2Extensions.la \ tests_LDADD = $(top_builddir)/lib/libUniSet2.la $(top_builddir)/extensions/lib/libUniSet2Extensions.la \
$(top_builddir)/extensions/SharedMemory/libUniSet2SharedMemory.la \ $(top_builddir)/extensions/SharedMemory/libUniSet2SharedMemory.la \
$(SIGC_LIBS) $(COMCPP_LIBS) $(SIGC_LIBS) $(COMCPP_LIBS)
tests_CPPFLAGS = -I$(top_builddir)/include -I$(top_builddir)/extensions/include \ tests_CPPFLAGS = -I$(top_builddir)/include -I$(top_builddir)/extensions/include \
-I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS) $(COMCPP_CFLAGS) -I$(top_builddir)/extensions/SharedMemory $(SIGC_CFLAGS) $(COMCPP_CFLAGS)
include $(top_builddir)/testsuite/testsuite-common.mk include $(top_builddir)/testsuite/testsuite-common.mk
...@@ -19,11 +24,6 @@ clean-local: ...@@ -19,11 +24,6 @@ clean-local:
rm -rf $(COVERAGE_REPORT_DIR) rm -rf $(COVERAGE_REPORT_DIR)
rm -rf *_SK.* rm -rf *_SK.*
BUILT_SOURCES = TestObject_SK.cc TestObject.h
TestObject_SK.cc TestObject.h: testobject.src.xml
$(UNISET_CODEGEN) -l $(top_builddir)/Utilities/codegen -n TestObject --topdir $(top_builddir)/ --ask --no-main testobject.src.xml
include $(top_builddir)/include.mk include $(top_builddir)/include.mk
endif endif
...@@ -40,6 +40,11 @@ LogReader. Читающих клиентов может быть скольуг ...@@ -40,6 +40,11 @@ LogReader. Читающих клиентов может быть скольуг
При этом через лог сервер имеется возможность управлять включением или отключением определённых уровней логов, При этом через лог сервер имеется возможность управлять включением или отключением определённых уровней логов,
записью, отключением записи или ротацией файла с логами. DebugStream за которым ведётся "слежение" записью, отключением записи или ротацией файла с логами. DebugStream за которым ведётся "слежение"
задаётся в конструкторе для LogServer. задаётся в конструкторе для LogServer.
По умолчанию LogServer при завершении автоматически восстаналивает уровни логов, которые были при подключении.
Но если была передана команда LogServerTypes::cmdSaveLogLevel, то после отключения (завершения сессии),
будут сохранены те уровни, которые выставлены подключившимся клиентом.
\code \code
DebugStream mylog; DebugStream mylog;
LogServer logsrv(mylog); LogServer logsrv(mylog);
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
namespace LogServerTypes namespace LogServerTypes
{ {
const unsigned int MAGICNUM = 0x20150531; const unsigned int MAGICNUM = 0x20160417;
enum Command enum Command
{ {
cmdNOP, /*!< отсутствие команды */ cmdNOP, /*!< отсутствие команды */
...@@ -33,9 +33,14 @@ namespace LogServerTypes ...@@ -33,9 +33,14 @@ namespace LogServerTypes
cmdOffLogFile, /*!< отключить запись файла логов (если включена) */ cmdOffLogFile, /*!< отключить запись файла логов (если включена) */
cmdOnLogFile, /*!< включить запись файла логов (если была отключена) */ cmdOnLogFile, /*!< включить запись файла логов (если была отключена) */
// работа с логами по умолчанию
cmdSaveLogLevel, /*!< запомнить текущее состояние логов (для восстановления при завершении сессии или команде Restore) */
cmdRestoreLogLevel, /*!< восстановить последнее запоненное (cmdSaveLogLevel) состояние логов (т.е. не восстанавливать как было, при завершении сессии) */
// команды требующий ответа.. // команды требующий ответа..
cmdList, /*!< вывести список контролируемых логов */ cmdList, /*!< вывести список контролируемых логов */
cmdFilterMode /*!< включить режим работы "фильтр" - вывод только от интересующих логов, заданных в lognmae (regexp) */ cmdFilterMode, /*!< включить режим работы "фильтр" - вывод только от интересующих логов, заданных в lognmae (regexp) */
cmdViewDefaultLogLevel /*!< вывести уровни логов сохранённых как умолчательный (cmdSaveLogLevel) */
// cmdSetLogFile // cmdSetLogFile
}; };
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#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"
...@@ -121,6 +122,12 @@ class LogSession ...@@ -121,6 +122,12 @@ 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;
......
...@@ -46,6 +46,15 @@ std::ostream& LogServerTypes::operator<<(std::ostream& os, LogServerTypes::Comma ...@@ -46,6 +46,15 @@ std::ostream& LogServerTypes::operator<<(std::ostream& os, LogServerTypes::Comma
case LogServerTypes::cmdFilterMode: case LogServerTypes::cmdFilterMode:
return os << "cmdFilterMode"; return os << "cmdFilterMode";
case LogServerTypes::cmdSaveLogLevel:
return os << "cmdSaveLogLevel";
case LogServerTypes::cmdRestoreLogLevel:
return os << "cmdRestoreLogLevel";
case LogServerTypes::cmdViewDefaultLogLevel:
return os << "cmdViewRestoreLogLevel";
case LogServerTypes::cmdNOP: case LogServerTypes::cmdNOP:
return os << "No command(NOP)"; return os << "No command(NOP)";
......
...@@ -62,7 +62,14 @@ LogSession::LogSession( int sfd, std::shared_ptr<DebugStream>& _log, timeout_t _ ...@@ -62,7 +62,14 @@ 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
{ {
...@@ -435,9 +442,6 @@ void LogSession::cmdProcessing( const string& cmdLogName, const LogServerTypes:: ...@@ -435,9 +442,6 @@ void LogSession::cmdProcessing( const string& cmdLogName, const LogServerTypes::
l.log->onLogFile(true); l.log->onLogFile(true);
break; break;
case LogServerTypes::cmdList: // обработали выше (в начале)
break;
case LogServerTypes::cmdOffLogFile: case LogServerTypes::cmdOffLogFile:
l.log->offLogFile(); l.log->offLogFile();
break; break;
...@@ -450,6 +454,12 @@ void LogSession::cmdProcessing( const string& cmdLogName, const LogServerTypes:: ...@@ -450,6 +454,12 @@ void LogSession::cmdProcessing( const string& cmdLogName, const LogServerTypes::
l.log->signal_stream_event().connect( sigc::mem_fun(this, &LogSession::logOnEvent) ); l.log->signal_stream_event().connect( sigc::mem_fun(this, &LogSession::logOnEvent) );
break; break;
case LogServerTypes::cmdList:
case LogServerTypes::cmdSaveLogLevel:
case LogServerTypes::cmdRestoreLogLevel:
case LogServerTypes::cmdViewDefaultLogLevel:
break;
default: default:
mylog.warn() << peername << "(run): Unknown command '" << msg.cmd << "'" << endl; mylog.warn() << peername << "(run): Unknown command '" << msg.cmd << "'" << endl;
break; break;
...@@ -473,6 +483,72 @@ void LogSession::cmdProcessing( const string& cmdLogName, const LogServerTypes:: ...@@ -473,6 +483,72 @@ void LogSession::cmdProcessing( const string& cmdLogName, const LogServerTypes::
io.set(ev::WRITE); 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 )
{
// восстанавливаем уровни логов
if( alog )
{
for( const auto& l : loglist )
{
auto i = defaultLogLevels.find(l.log.get());
if( i!= defaultLogLevels.end() )
l.log->level(i->second);
}
}
else if( log )
log->level(defaultLogLevels[log.get()]);
}
else if( msg.cmd == LogServerTypes::cmdViewDefaultLogLevel )
{
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);
}
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void LogSession::onCmdTimeout( ev::timer& watcher, int revents ) void LogSession::onCmdTimeout( ev::timer& watcher, int revents )
...@@ -508,7 +584,7 @@ void LogSession::onCheckConnectionTimer( ev::timer& watcher, int revents ) ...@@ -508,7 +584,7 @@ void LogSession::onCheckConnectionTimer( ev::timer& watcher, int revents )
// если клиент уже отвалился.. то при попытке write.. сессия будет закрыта. // если клиент уже отвалился.. то при попытке write.. сессия будет закрыта.
ostringstream err; ostringstream err;
err << "..logclient ping message.." << endl; err << "logserver: ..keep alive message.." << endl;
logbuf.emplace(new UTCPCore::Buffer(std::move(err.str()))); logbuf.emplace(new UTCPCore::Buffer(std::move(err.str())));
io.set(ev::WRITE); io.set(ev::WRITE);
checkConnectionTimer.start( checkConnectionTime ); // restart timer checkConnectionTimer.start( checkConnectionTime ); // restart timer
...@@ -516,6 +592,27 @@ void LogSession::onCheckConnectionTimer( ev::timer& watcher, int revents ) ...@@ -516,6 +592,27 @@ 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);
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
......
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