#include "WorkerTelegrafControl.h" #include "Logger.h" #include "TelegrafControl.h" #include #include #include #include #include #include #include #include // Telegraf check 주기 (sec) #define TELEGRAF_CHECK_INTERVAL 60 // telegraf 미기동 상태가 지정된 횟수 이상인 경우.. 기동 처리 수행 // - 운영자 요청으로 10분 초과 미기동 상태인 경우.. 자동 기동 처리 #define TELEGRAF_NO_ACTIVE_COUNT_MAX 10 // telegraf 가 hang 상태 관련 지정된 횟수 이상인 경우.. 재기동 처리 수행 #define TELEGRAF_HANG_COUNT_MAX 2 // telegraf 의 MAX 기동 시간 (sec) // - telegraf 기동 후 elapsed time 이 현재 설정값을 초과하는 경우.. 재기동 처리를 수행한다. // - 이는 telegraf 장기 운영시.. 삭제된 log 파일을 tail 에서 붙잡고 있어.... OS Disk full 상황을 방지하기 위함 // - 운영자 의견 수렴 결과.. 2일 단위로 재기동 요청. #define TELEGRAF_ELAPSED_TIME_MAX 172800LL // Worker::TelegrafControl 프로세스의 Main 역활을 수행하기 위한 함수. int WorkerTelegrafControlMain( void ) { setproctitle( "TelegrafControl [initialize]" ); // Set signal handler SetWorkerTelegrafControlSignalHandler(); // telegraf control 객체 생성 CTelegrafControl telegraf; // 전체 프로세스의 생성이 완료될때까지 대기 후 작업 시작 sleep( 2 ); setproctitle( "TelegrafControl" ); int iProcessId = 0; int iProcessNotActiveCount = 0; int iProcessHangCount = 0; long long llProcessElapsedSec = 0; // 주기적으로 telegraf 상태를 점검한다. while( 1 ) { // 지정된 시간동안 sleep 처리 sleep( TELEGRAF_CHECK_INTERVAL ); _LOG( LDBG, "[TelegrafControl:%d] check start.", getpid() ); // 1. process 기동 여부 check iProcessId = telegraf.GetProcessId(); if( iProcessId == 0 ) { // 미기동 상태인 경우 // - 패치 및 설정 등의 작업으로 인해 미기동 상태일 수 있으므로...... // - 미기동 상태가 지정된 횟수 이상인 경우에만.. 기동 처리를 시도한다. ++iProcessNotActiveCount; if( iProcessNotActiveCount > TELEGRAF_NO_ACTIVE_COUNT_MAX ) { _LOG( LINF, "[TelegrafControl:%d] telegraf process not found. try starting.", getpid() ); // 지정 횟수 초과의 미기동 상태인 경우... 기동 처리 try... telegraf.ServiceStart(); // telegraf 기동을 시도했으므로... count 는 초기화 처리한다. iProcessNotActiveCount = 0; } else { _LOG( LINF, "[TelegrafControl:%d] telegraf process not found. count[%d]", getpid(), iProcessNotActiveCount ); } // telegraf 상태 처음부터 다시 check. continue; } // telegraf 기동 중인 상태인 경우 not active count 초기화 iProcessNotActiveCount = 0; // 2. process hang check // - hang 상황인 경우... 재기동 처리 if( telegraf.IsHang() == true ) { // telegraf hang 상황인 경우... ++iProcessHangCount; if( iProcessHangCount > TELEGRAF_HANG_COUNT_MAX ) { _LOG( LINF, "[TelegrafControl:%d] telegraf[%d] hang detected. try restarting.", getpid(), iProcessId ); // 지정 횟수 초과의 hang 상태인 경우... 재기동 처리 try... telegraf.ServiceQuit(); // telegraf 재기동을 시도했으므로... count 는 초기화 처리한다. iProcessHangCount = 0; // 관련 사항은 /var/log/message 상에 기록해 둔다. openlog( PROG_NAME, LOG_PID, LOG_USER ); syslog( LOG_WARNING, "telegraf[%d] hang detected. SIGQUIT send for telegraf restart.", iProcessId ); closelog(); } else { _LOG( LINF, "[TelegrafControl:%d] telegraf[%d] is hang. count[%d]", getpid(), iProcessId, iProcessHangCount ); } // telegraf 상태 처음부터 다시 check. continue; } // telegraf hang count 초기화 iProcessHangCount = 0; // 3. process 기동 후 지정된 시간 이상 되었는지 check // - 지정된 시간 초과시 재기동 처리 // - ps -o etimes= -p `pgrep telegraf` // - sec 단위 llProcessElapsedSec = telegraf.GetProcessElapsedSec(); if( llProcessElapsedSec > TELEGRAF_ELAPSED_TIME_MAX ) { _LOG( LINF, "[TelegrafControl:%d] telegraf[%d] elapsed time too long [%lld / %lld sec]. try restarting." , getpid(), iProcessId, llProcessElapsedSec, TELEGRAF_ELAPSED_TIME_MAX ); // 재기동 처리 시도 telegraf.ServiceRestart(); // telegraf 상태 처음부터 다시 check. continue; } // 4. 기타 } // 종료시 정리 작업 수행 ReadyToExitWorkerTelegrafControl(); return EXIT_SUCCESS; } // 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수. void ReadyToExitWorkerTelegrafControl( void ) { // Logger 객체 종료 처리 CLogger::Exit(); return; } // Worker TelegrafControl 프로세스에 대한 종료 처리 수신시 static void SignalWorkerTelegrafControlTerminate( int nSignalNumber ) { // Signal Number 에 따른 로깅처리. if( nSignalNumber == SIGTERM ) { _LOG( LINF, "[TelegrafControl:%d] Process exit by SIGTERM signal. Good Bye..", getpid() ); } else { _LOG( LWAR, "[TelegrafControl:%d] Process exit by abnormal signal[%d], Good Bye..", getpid(), nSignalNumber ); } ReadyToExitWorkerTelegrafControl(); // 종료전 잠시 대기 struct timespec sleep; sleep.tv_sec = 0; sleep.tv_nsec = 500000000; // 0.5 sec nanosleep( &sleep, NULL ); exit( EXIT_SUCCESS ); } // Worker::TelegrafControl Process 의 signal 처리기... void SetWorkerTelegrafControlSignalHandler( void ) { sigset_t set; struct sigaction act; memset( &act, 0x00, sizeof( act ) ); sigfillset( &set ); sigprocmask( SIG_SETMASK, &set, NULL ); sigfillset( &act.sa_mask ); // 무시 처리 signal act.sa_handler = SIG_IGN; sigaction( SIGPIPE, &act, NULL ); /* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */ sigaction( SIGHUP, &act, NULL ); /* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/ sigaction( SIGINT, &act, NULL ); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */ sigaction( SIGQUIT, &act, NULL ); /* 키보드에 의한 Abort 신호 처리 => ? */ // Worker 프로세스는 자식 프로세스가 존재하지 않으므로 그냥 무시처리함. act.sa_handler = SIG_IGN; sigaction( SIGCHLD, &act, NULL ); /* 각종 에러나 사용자의 종료 신호 처리 */ act.sa_handler = SignalWorkerTelegrafControlTerminate; sigaction( SIGTERM, &act, NULL ); /* kill -TERM 에 의한 프로세스 종료시 */ // 나머지 신호는 default 처리. sigemptyset( &set ); /* 신호 처리기 처리 설정 위한 블록 해제 */ sigprocmask( SIG_SETMASK, &set, NULL ); }