ntopng/src/Trace.cpp
2020-01-28 17:17:26 +01:00

251 lines
6.1 KiB
C++

/*
*
* (C) 2013-20 - ntop.org
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include "ntop_includes.h"
/* ******************************* */
Trace::Trace() {
traceLevel = TRACE_LEVEL_NORMAL;
logFile = NULL;
logFd = NULL;
traceRedis = NULL;
open_log();
};
/* ******************************* */
Trace::~Trace() {
if(logFd) fclose(logFd);
if(logFile) free(logFile);
if(traceRedis) delete traceRedis;
};
/* ******************************* */
void Trace::rotate_logs(bool forceRotation) {
char buf1[MAX_PATH], buf2[MAX_PATH];
const int max_num_lines = TRACES_PER_LOG_FILE_HIGH_WATERMARK;
if(!logFd) return;
else if((!forceRotation) && (numLogLines < max_num_lines)) return;
fclose(logFd);
logFd = NULL;
for(int i = MAX_NUM_NTOPNG_LOG_FILES - 1; i >= 1; i--) {
snprintf(buf1, sizeof(buf1), "%s.%u", logFile, i);
snprintf(buf2, sizeof(buf2), "%s.%u", logFile, i + 1);
if(Utils::file_exists(buf1))
rename(buf1, buf2);
} /* for */
if(Utils::file_exists(logFile)) {
snprintf(buf1, sizeof(buf1), "%s.1", logFile);
rename(logFile, buf1);
}
open_log();
}
/* ******************************* */
void Trace::open_log() {
if(logFile) {
logFd = fopen(logFile, "a");
if(!logFd)
traceEvent(TRACE_ERROR, "Unable to create log %s", logFile);
else
chmod(logFile, CONST_DEFAULT_FILE_MODE);
numLogLines = 0;
}
}
/* ******************************* */
void Trace::set_log_file(const char* log_file) {
if(log_file && log_file[0] != '\0') {
rotate_logs(true);
if(logFile) free(logFile);
logFile = strndup(log_file, MAX_PATH);
open_log();
}
}
/* ******************************* */
void Trace::set_trace_level(u_int8_t id) {
if(id > MAX_TRACE_LEVEL) id = MAX_TRACE_LEVEL;
traceLevel = id;
}
/* ******************************* */
void Trace::initRedis(const char *redis_host, const char *redis_password,
u_int16_t redis_port, u_int8_t _redis_db_id) {
Utils::initRedis(&traceRedis, redis_host, redis_password,
redis_port, _redis_db_id, false);
}
/* ******************************* */
void Trace::traceEvent(int eventTraceLevel, const char* _file,
const int line, const char * format, ...) {
va_list va_ap;
#ifndef WIN32
struct tm result;
#endif
if((eventTraceLevel <= traceLevel) && (traceLevel > 0)) {
char buf[8100], out_buf[8192];
char theDate[32], *file = (char*)_file;
const char *extra_msg = "";
time_t theTime = time(NULL);
#ifndef WIN32
char *syslogMsg;
#endif
char filebuf[MAX_PATH];
const char *backslash = strrchr(_file,
#ifdef WIN32
'\\'
#else
'/'
#endif
);
if(backslash != NULL) {
snprintf(filebuf, sizeof(filebuf), "%s", &backslash[1]);
file = (char*)filebuf;
}
va_start (va_ap, format);
/* We have two paths - one if we're logging, one if we aren't
* Note that the no-log case is those systems which don't support it (WIN32),
* those without the headers !defined(USE_SYSLOG)
* those where it's parametrically off...
*/
memset(buf, 0, sizeof(buf));
strftime(theDate, 32, "%d/%b/%Y %H:%M:%S", localtime_r(&theTime, &result));
vsnprintf(buf, sizeof(buf)-1, format, va_ap);
if(eventTraceLevel == 0 /* TRACE_ERROR */)
extra_msg = "ERROR: ";
else if(eventTraceLevel == 1 /* TRACE_WARNING */)
extra_msg = "WARNING: ";
while(buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';
snprintf(out_buf, sizeof(out_buf), "%s [%s:%d] %s%s", theDate, file, line, extra_msg, buf);
if(logFd) {
rotate_mutex.lock(__FILE__, __LINE__); /* Need to lock as a rotation may be in progress */
numLogLines++;
fprintf(logFd, "%s\n", out_buf);
fflush(logFd);
rotate_logs(false);
rotate_mutex.unlock(__FILE__, __LINE__);
} else {
#ifdef WIN32
AddToMessageLog(out_buf);
#else
syslogMsg = &out_buf[strlen(theDate)+1];
if(eventTraceLevel == 0 /* TRACE_ERROR */)
syslog(LOG_ERR, "%s", syslogMsg);
else if(eventTraceLevel == 1 /* TRACE_WARNING */)
syslog(LOG_WARNING, "%s", syslogMsg);
#endif
}
printf("%s\n", out_buf);
fflush(stdout);
if(traceRedis && traceRedis->isOperational() && ntop->getRedis()->isOperational())
traceRedis->lpush(NTOPNG_TRACE, out_buf, MAX_NUM_NTOPNG_TRACES,
false /* Do not re-trace errors, re-tracing would yield a deadlock */);
va_end(va_ap);
}
}
/* ******************************* */
#ifdef WIN32
/* service_win32.cpp */
extern "C" {
extern short isWinNT();
extern BOOL bConsole;
};
/* ******************************* */
void Trace::AddToMessageLog(LPTSTR lpszMsg) {
HANDLE hEventSource;
TCHAR szMsg[4096];
#ifdef UNICODE
LPCWSTR lpszStrings[1];
#else
LPCSTR lpszStrings[1];
#endif
if(!isWinNT()) {
char *msg = (char*)lpszMsg;
printf("%s", msg);
if(msg[strlen(msg)-1] != '\n')
printf("\n");
return;
}
if(!szMsg) {
hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));
snprintf(szMsg, sizeof(szMsg), TEXT("%s: %s"), SZSERVICENAME, lpszMsg);
lpszStrings[0] = szMsg;
if (hEventSource != NULL) {
ReportEvent(hEventSource,
EVENTLOG_INFORMATION_TYPE,
0,
EVENT_GENERIC_INFORMATION,
NULL,
1,
0,
lpszStrings,
NULL);
DeregisterEventSource(hEventSource);
}
}
}
/* ******************************* */
#endif /* WIN32 */