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

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

восстановления логов после отключения от логсервера
parent e3263be4
......@@ -65,6 +65,8 @@ Version 2.5
- Использовать PIMPL
- подумать.. это серьёзная переделка кода..
- Вылетать с ошибкой если в секции <thresholds> указан не существующий датчик
libev
=======
- переписать UNetUDP (на подумать)
......@@ -72,6 +74,14 @@ libev
SM: подумать насчёт асинхронности публикации событий и посылки уведомления (setValue/push) через очередь..
LogServer: подумать насчёт автоматического отключение уровней логов, если они не пишутся в файл
и нет активных удалённых сессий (иначе включённые логи сильно грузят процессор, при обычно,
подключаются.. смотрят.. а отключить уже забывают.
(вариант реализации: запоминаем по списку умолчатльные настройки при старте сессии, после завершения восстанавливаем.
Но сделать специальную команду, отключающую восстановление при выходе.)
version 3
=========
- подумать нужен ли нам где-то ZeroMQ (zerorpc) (вместо omniORB?)
......
......@@ -23,6 +23,9 @@ static struct option longopts[] =
{ "set", required_argument, 0, 's' },
{ "off", required_argument, 0, 'o' },
{ "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' },
{ "rotate", optional_argument, 0, 'r' },
{ "logfilter", required_argument, 0, 'n' },
......@@ -49,14 +52,18 @@ static void print_help()
printf("\n");
printf("Commands:\n");
printf("[--add | -a] info,warn,crit,... [logfilter] - Add log levels.\n");
printf("[--del | -d] info,warn,crit,... [logfilter] - Delete log levels.\n");
printf("[--set | -s] info,warn,crit,... [logfilter] - Set log levels.\n");
printf("--off, -o [logfilter] - Off the write log file (if enabled).\n");
printf("--on, -e [logfilter] - On(enable) the write log file (if before disabled).\n");
printf("--rotate, -r [logfilter] - rotate log file.\n");
printf("--list, -l [logfilter] - List of managed logs.\n");
printf("--filter, -f logfilter - ('filter mode'). View log only from 'logfilter'(regexp)\n");
printf("[-a | --add] info,warn,crit,... [logfilter] - Add log levels.\n");
printf("[-d | --del] info,warn,crit,... [logfilter] - Delete log levels.\n");
printf("[-s | --set] info,warn,crit,... [logfilter] - Set log levels.\n");
printf("[-o | --off] [logfilter] - Off the write log file (if enabled).\n");
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("[-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("Note: 'logfilter' - regexp for name of log. Default: ALL logs.\n");
}
......@@ -87,7 +94,7 @@ int main( int argc, char** argv )
{
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 )
break;
......@@ -166,6 +173,46 @@ int main( int argc, char** argv )
}
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':
{
LogServerTypes::Command cmd = LogServerTypes::cmdOnLogFile;
......
......@@ -2,12 +2,17 @@ if HAVE_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 \
$(top_builddir)/extensions/SharedMemory/libUniSet2SharedMemory.la \
$(SIGC_LIBS) $(COMCPP_LIBS)
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
......@@ -19,11 +24,6 @@ clean-local:
rm -rf $(COVERAGE_REPORT_DIR)
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
endif
......@@ -40,6 +40,11 @@ LogReader. Читающих клиентов может быть скольуг
При этом через лог сервер имеется возможность управлять включением или отключением определённых уровней логов,
записью, отключением записи или ротацией файла с логами. DebugStream за которым ведётся "слежение"
задаётся в конструкторе для LogServer.
По умолчанию LogServer при завершении автоматически восстаналивает уровни логов, которые были при подключении.
Но если была передана команда LogServerTypes::cmdSaveLogLevel, то после отключения (завершения сессии),
будут сохранены те уровни, которые выставлены подключившимся клиентом.
\code
DebugStream mylog;
LogServer logsrv(mylog);
......
......@@ -22,7 +22,7 @@
// -------------------------------------------------------------------------
namespace LogServerTypes
{
const unsigned int MAGICNUM = 0x20150531;
const unsigned int MAGICNUM = 0x20160417;
enum Command
{
cmdNOP, /*!< отсутствие команды */
......@@ -33,9 +33,14 @@ namespace LogServerTypes
cmdOffLogFile, /*!< отключить запись файла логов (если включена) */
cmdOnLogFile, /*!< включить запись файла логов (если была отключена) */
// работа с логами по умолчанию
cmdSaveLogLevel, /*!< запомнить текущее состояние логов (для восстановления при завершении сессии или команде Restore) */
cmdRestoreLogLevel, /*!< восстановить последнее запоненное (cmdSaveLogLevel) состояние логов (т.е. не восстанавливать как было, при завершении сессии) */
// команды требующий ответа..
cmdList, /*!< вывести список контролируемых логов */
cmdFilterMode /*!< включить режим работы "фильтр" - вывод только от интересующих логов, заданных в lognmae (regexp) */
cmdFilterMode, /*!< включить режим работы "фильтр" - вывод только от интересующих логов, заданных в lognmae (regexp) */
cmdViewDefaultLogLevel /*!< вывести уровни логов сохранённых как умолчательный (cmdSaveLogLevel) */
// cmdSetLogFile
};
......
......@@ -20,6 +20,7 @@
#include <string>
#include <memory>
#include <queue>
#include <unordered_map>
#include <cc++/socket.h>
#include <ev++.h>
#include "Mutex.h"
......@@ -121,6 +122,12 @@ 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;
......
......@@ -46,6 +46,15 @@ std::ostream& LogServerTypes::operator<<(std::ostream& os, LogServerTypes::Comma
case LogServerTypes::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:
return os << "No command(NOP)";
......
......@@ -62,7 +62,14 @@ 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
{
......@@ -435,9 +442,6 @@ void LogSession::cmdProcessing( const string& cmdLogName, const LogServerTypes::
l.log->onLogFile(true);
break;
case LogServerTypes::cmdList: // обработали выше (в начале)
break;
case LogServerTypes::cmdOffLogFile:
l.log->offLogFile();
break;
......@@ -450,6 +454,12 @@ void LogSession::cmdProcessing( const string& cmdLogName, const LogServerTypes::
l.log->signal_stream_event().connect( sigc::mem_fun(this, &LogSession::logOnEvent) );
break;
case LogServerTypes::cmdList:
case LogServerTypes::cmdSaveLogLevel:
case LogServerTypes::cmdRestoreLogLevel:
case LogServerTypes::cmdViewDefaultLogLevel:
break;
default:
mylog.warn() << peername << "(run): Unknown command '" << msg.cmd << "'" << endl;
break;
......@@ -473,6 +483,72 @@ 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 )
{
// восстанавливаем уровни логов
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 )
......@@ -508,7 +584,7 @@ void LogSession::onCheckConnectionTimer( ev::timer& watcher, int revents )
// если клиент уже отвалился.. то при попытке write.. сессия будет закрыта.
ostringstream err;
err << "..logclient ping message.." << endl;
err << "logserver: ..keep alive message.." << endl;
logbuf.emplace(new UTCPCore::Buffer(std::move(err.str())));
io.set(ev::WRITE);
checkConnectionTimer.start( checkConnectionTime ); // restart timer
......@@ -516,6 +592,27 @@ 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);
}
// -------------------------------------------------------------------------
......
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