mirror of
https://github.com/netdata/netdata.git
synced 2025-04-06 22:38:55 +00:00

* rrdset - in progress * rrdset optimal constructor; rrdset conflict * rrdset final touches * re-organization of rrdset object members * prevent use-after-free * dictionary dfe supports also counting of iterations * rrddim managed by dictionary * rrd.h cleanup * DICTIONARY_ITEM now is referencing actual dictionary items in the code * removed rrdset linked list * Revert "removed rrdset linked list" This reverts commit 690d6a588b4b99619c2c5e10f84e8f868ae6def5. * removed rrdset linked list * added comments * Switch chart uuid to static allocation in rrdset Remove unused functions * rrdset_archive() and friends... * always create rrdfamily * enable ml_free_dimension * rrddim_foreach done with dfe * most custom rrddim loops replaced with rrddim_foreach * removed accesses to rrddim->dimensions * removed locks that are no longer needed * rrdsetvar is now managed by the dictionary * set rrdset is rrdsetvar, fixes https://github.com/netdata/netdata/pull/13646#issuecomment-1242574853 * conflict callback of rrdsetvar now properly checks if it has to reset the variable * dictionary registered callbacks accept as first parameter the DICTIONARY_ITEM * dictionary dfe now uses internal counter to report; avoided excess variables defined with dfe * dictionary walkthrough callbacks get dictionary acquired items * dictionary reference counters that can be dupped from zero * added advanced functions for get and del * rrdvar managed by dictionaries * thread safety for rrdsetvar * faster rrdvar initialization * rrdvar string lengths should match in all add, del, get functions * rrdvar internals hidden from the rest of the world * rrdvar is now acquired throughout netdata * hide the internal structures of rrdsetvar * rrdsetvar is now acquired through out netdata * rrddimvar managed by dictionary; rrddimvar linked list removed; rrddimvar structures hidden from the rest of netdata * better error handling * dont create variables if not initialized for health * dont create variables if not initialized for health again * rrdfamily is now managed by dictionaries; references of it are acquired dictionary items * type checking on acquired objects * rrdcalc renaming of functions * type checking for rrdfamily_acquired * rrdcalc managed by dictionaries * rrdcalc double free fix * host rrdvars is always needed * attempt to fix deadlock 1 * attempt to fix deadlock 2 * Remove unused variable * attempt to fix deadlock 3 * snprintfz * rrdcalc index in rrdset fix * Stop storing active charts and computing chart hashes * Remove store active chart function * Remove compute chart hash function * Remove sql_store_chart_hash function * Remove store_active_dimension function * dictionary delayed destruction * formatting and cleanup * zero dictionary base on rrdsetvar * added internal error to log delayed destructions of dictionaries * typo in rrddimvar * added debugging info to dictionary * debug info * fix for rrdcalc keys being empty * remove forgotten unlock * remove deadlock * Switch to metadata version 5 and drop chart_hash chart_hash_map chart_active dimension_active v_chart_hash * SQL cosmetic changes * do not busy wait while destroying a referenced dictionary * remove deadlock * code cleanup; re-organization; * fast cleanup and flushing of dictionaries * number formatting fixes * do not delete configured alerts when archiving a chart * rrddim obsolete linked list management outside dictionaries * removed duplicate contexts call * fix crash when rrdfamily is not initialized * dont keep rrddimvar referenced * properly cleanup rrdvar * removed some locks * Do not attempt to cleanup chart_hash / chart_hash_map * rrdcalctemplate managed by dictionary * register callbacks on the right dictionary * removed some more locks * rrdcalc secondary index replaced with linked-list; rrdcalc labels updates are now executed by health thread * when looking up for an alarm look using both chart id and chart name * host initialization a bit more modular * init rrdlabels on host update * preparation for dictionary views * improved comment * unused variables without internal checks * service threads isolation and worker info * more worker info in service thread * thread cancelability debugging with internal checks * strings data races addressed; fixes https://github.com/netdata/netdata/issues/13647 * dictionary modularization * Remove unused SQL statement definition * unit-tested thread safety of dictionaries; removed data race conditions on dictionaries and strings; dictionaries now can detect if the caller is holds a write lock and automatically all the calls become their unsafe versions; all direct calls to unsafe version is eliminated * remove worker_is_idle() from the exit of service functions, because we lose the lock time between loops * rewritten dictionary to have 2 separate locks, one for indexing and another for traversal * Update collectors/cgroups.plugin/sys_fs_cgroup.c Co-authored-by: Vladimir Kobal <vlad@prokk.net> * Update collectors/cgroups.plugin/sys_fs_cgroup.c Co-authored-by: Vladimir Kobal <vlad@prokk.net> * Update collectors/proc.plugin/proc_net_dev.c Co-authored-by: Vladimir Kobal <vlad@prokk.net> * fix memory leak in rrdset cache_dir * minor dictionary changes * dont use index locks in single threaded * obsolete dict option * rrddim options and flags separation; rrdset_done() optimization to keep array of reference pointers to rrddim; * fix jump on uninitialized value in dictionary; remove double free of cache_dir * addressed codacy findings * removed debugging code * use the private refcount on dictionaries * make dictionary item desctructors work on dictionary destruction; strictier control on dictionary API; proper cleanup sequence on rrddim; * more dictionary statistics * global statistics about dictionary operations, memory, items, callbacks * dictionary support for views - missing the public API * removed warning about unused parameter * chart and context name for cloud * chart and context name for cloud, again * dictionary statistics fixed; first implementation of dictionary views - not currently used * only the master can globally delete an item * context needs netdata prefix * fix context and chart it of spins * fix for host variables when health is not enabled * run garbage collector on item insert too * Fix info message; remove extra "using" * update dict unittest for new placement of garbage collector * we need RRDHOST->rrdvars for maintaining custom host variables * Health initialization needs the host->host_uuid * split STRING to its own files; no code changes other than that * initialize health unconditionally * unit tests do not pollute the global scope with their variables * Skip initialization when creating archived hosts on startup. When a child connects it will initialize properly Co-authored-by: Stelios Fragkakis <52996999+stelfrag@users.noreply.github.com> Co-authored-by: Vladimir Kobal <vlad@prokk.net>
963 lines
24 KiB
C
963 lines
24 KiB
C
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#include <daemon/main.h>
|
|
#include "../libnetdata.h"
|
|
|
|
int web_server_is_multithreaded = 1;
|
|
|
|
const char *program_name = "";
|
|
uint64_t debug_flags = 0;
|
|
|
|
int access_log_syslog = 1;
|
|
int error_log_syslog = 1;
|
|
int output_log_syslog = 1; // debug log
|
|
|
|
int stdaccess_fd = -1;
|
|
FILE *stdaccess = NULL;
|
|
|
|
const char *stdaccess_filename = NULL;
|
|
const char *stderr_filename = NULL;
|
|
const char *stdout_filename = NULL;
|
|
const char *facility_log = NULL;
|
|
|
|
#ifdef ENABLE_ACLK
|
|
const char *aclklog_filename = NULL;
|
|
int aclklog_fd = -1;
|
|
FILE *aclklog = NULL;
|
|
int aclklog_syslog = 1;
|
|
int aclklog_enabled = 0;
|
|
#endif
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Log facility(https://tools.ietf.org/html/rfc5424)
|
|
//
|
|
// The facilities accepted in the Netdata are in according with the following
|
|
// header files for their respective operating system:
|
|
// sys/syslog.h (Linux )
|
|
// sys/sys/syslog.h (FreeBSD)
|
|
// bsd/sys/syslog.h (darwin-xnu)
|
|
|
|
#define LOG_AUTH_KEY "auth"
|
|
#define LOG_AUTHPRIV_KEY "authpriv"
|
|
#ifdef __FreeBSD__
|
|
# define LOG_CONSOLE_KEY "console"
|
|
#endif
|
|
#define LOG_CRON_KEY "cron"
|
|
#define LOG_DAEMON_KEY "daemon"
|
|
#define LOG_FTP_KEY "ftp"
|
|
#ifdef __APPLE__
|
|
# define LOG_INSTALL_KEY "install"
|
|
#endif
|
|
#define LOG_KERN_KEY "kern"
|
|
#define LOG_LPR_KEY "lpr"
|
|
#define LOG_MAIL_KEY "mail"
|
|
//#define LOG_INTERNAL_MARK_KEY "mark"
|
|
#ifdef __APPLE__
|
|
# define LOG_NETINFO_KEY "netinfo"
|
|
# define LOG_RAS_KEY "ras"
|
|
# define LOG_REMOTEAUTH_KEY "remoteauth"
|
|
#endif
|
|
#define LOG_NEWS_KEY "news"
|
|
#ifdef __FreeBSD__
|
|
# define LOG_NTP_KEY "ntp"
|
|
#endif
|
|
#define LOG_SECURITY_KEY "security"
|
|
#define LOG_SYSLOG_KEY "syslog"
|
|
#define LOG_USER_KEY "user"
|
|
#define LOG_UUCP_KEY "uucp"
|
|
#ifdef __APPLE__
|
|
# define LOG_LAUNCHD_KEY "launchd"
|
|
#endif
|
|
#define LOG_LOCAL0_KEY "local0"
|
|
#define LOG_LOCAL1_KEY "local1"
|
|
#define LOG_LOCAL2_KEY "local2"
|
|
#define LOG_LOCAL3_KEY "local3"
|
|
#define LOG_LOCAL4_KEY "local4"
|
|
#define LOG_LOCAL5_KEY "local5"
|
|
#define LOG_LOCAL6_KEY "local6"
|
|
#define LOG_LOCAL7_KEY "local7"
|
|
|
|
static int log_facility_id(const char *facility_name)
|
|
{
|
|
static int
|
|
hash_auth = 0,
|
|
hash_authpriv = 0,
|
|
#ifdef __FreeBSD__
|
|
hash_console = 0,
|
|
#endif
|
|
hash_cron = 0,
|
|
hash_daemon = 0,
|
|
hash_ftp = 0,
|
|
#ifdef __APPLE__
|
|
hash_install = 0,
|
|
#endif
|
|
hash_kern = 0,
|
|
hash_lpr = 0,
|
|
hash_mail = 0,
|
|
// hash_mark = 0,
|
|
#ifdef __APPLE__
|
|
hash_netinfo = 0,
|
|
hash_ras = 0,
|
|
hash_remoteauth = 0,
|
|
#endif
|
|
hash_news = 0,
|
|
#ifdef __FreeBSD__
|
|
hash_ntp = 0,
|
|
#endif
|
|
hash_security = 0,
|
|
hash_syslog = 0,
|
|
hash_user = 0,
|
|
hash_uucp = 0,
|
|
#ifdef __APPLE__
|
|
hash_launchd = 0,
|
|
#endif
|
|
hash_local0 = 0,
|
|
hash_local1 = 0,
|
|
hash_local2 = 0,
|
|
hash_local3 = 0,
|
|
hash_local4 = 0,
|
|
hash_local5 = 0,
|
|
hash_local6 = 0,
|
|
hash_local7 = 0;
|
|
|
|
if(unlikely(!hash_auth))
|
|
{
|
|
hash_auth = simple_hash(LOG_AUTH_KEY);
|
|
hash_authpriv = simple_hash(LOG_AUTHPRIV_KEY);
|
|
#ifdef __FreeBSD__
|
|
hash_console = simple_hash(LOG_CONSOLE_KEY);
|
|
#endif
|
|
hash_cron = simple_hash(LOG_CRON_KEY);
|
|
hash_daemon = simple_hash(LOG_DAEMON_KEY);
|
|
hash_ftp = simple_hash(LOG_FTP_KEY);
|
|
#ifdef __APPLE__
|
|
hash_install = simple_hash(LOG_INSTALL_KEY);
|
|
#endif
|
|
hash_kern = simple_hash(LOG_KERN_KEY);
|
|
hash_lpr = simple_hash(LOG_LPR_KEY);
|
|
hash_mail = simple_hash(LOG_MAIL_KEY);
|
|
// hash_mark = simple_uhash();
|
|
#ifdef __APPLE__
|
|
hash_netinfo = simple_hash(LOG_NETINFO_KEY);
|
|
hash_ras = simple_hash(LOG_RAS_KEY);
|
|
hash_remoteauth = simple_hash(LOG_REMOTEAUTH_KEY);
|
|
#endif
|
|
hash_news = simple_hash(LOG_NEWS_KEY);
|
|
#ifdef __FreeBSD__
|
|
hash_ntp = simple_hash(LOG_NTP_KEY);
|
|
#endif
|
|
hash_security = simple_hash(LOG_SECURITY_KEY);
|
|
hash_syslog = simple_hash(LOG_SYSLOG_KEY);
|
|
hash_user = simple_hash(LOG_USER_KEY);
|
|
hash_uucp = simple_hash(LOG_UUCP_KEY);
|
|
#ifdef __APPLE__
|
|
hash_launchd = simple_hash(LOG_LAUNCHD_KEY);
|
|
#endif
|
|
hash_local0 = simple_hash(LOG_LOCAL0_KEY);
|
|
hash_local1 = simple_hash(LOG_LOCAL1_KEY);
|
|
hash_local2 = simple_hash(LOG_LOCAL2_KEY);
|
|
hash_local3 = simple_hash(LOG_LOCAL3_KEY);
|
|
hash_local4 = simple_hash(LOG_LOCAL4_KEY);
|
|
hash_local5 = simple_hash(LOG_LOCAL5_KEY);
|
|
hash_local6 = simple_hash(LOG_LOCAL6_KEY);
|
|
hash_local7 = simple_hash(LOG_LOCAL7_KEY);
|
|
}
|
|
|
|
int hash = simple_hash(facility_name);
|
|
if ( hash == hash_auth )
|
|
{
|
|
return LOG_AUTH;
|
|
}
|
|
else if ( hash == hash_authpriv )
|
|
{
|
|
return LOG_AUTHPRIV;
|
|
}
|
|
#ifdef __FreeBSD__
|
|
else if ( hash == hash_console )
|
|
{
|
|
return LOG_CONSOLE;
|
|
}
|
|
#endif
|
|
else if ( hash == hash_cron )
|
|
{
|
|
return LOG_CRON;
|
|
}
|
|
else if ( hash == hash_daemon )
|
|
{
|
|
return LOG_DAEMON;
|
|
}
|
|
else if ( hash == hash_ftp )
|
|
{
|
|
return LOG_FTP;
|
|
}
|
|
#ifdef __APPLE__
|
|
else if ( hash == hash_install )
|
|
{
|
|
return LOG_INSTALL;
|
|
}
|
|
#endif
|
|
else if ( hash == hash_kern )
|
|
{
|
|
return LOG_KERN;
|
|
}
|
|
else if ( hash == hash_lpr )
|
|
{
|
|
return LOG_LPR;
|
|
}
|
|
else if ( hash == hash_mail )
|
|
{
|
|
return LOG_MAIL;
|
|
}
|
|
/*
|
|
else if ( hash == hash_mark )
|
|
{
|
|
//this is internal for all OS
|
|
return INTERNAL_MARK;
|
|
}
|
|
*/
|
|
#ifdef __APPLE__
|
|
else if ( hash == hash_netinfo )
|
|
{
|
|
return LOG_NETINFO;
|
|
}
|
|
else if ( hash == hash_ras )
|
|
{
|
|
return LOG_RAS;
|
|
}
|
|
else if ( hash == hash_remoteauth )
|
|
{
|
|
return LOG_REMOTEAUTH;
|
|
}
|
|
#endif
|
|
else if ( hash == hash_news )
|
|
{
|
|
return LOG_NEWS;
|
|
}
|
|
#ifdef __FreeBSD__
|
|
else if ( hash == hash_ntp )
|
|
{
|
|
return LOG_NTP;
|
|
}
|
|
#endif
|
|
else if ( hash == hash_security )
|
|
{
|
|
//FreeBSD is the unique that does not consider
|
|
//this facility deprecated. We are keeping
|
|
//it for other OS while they are kept in their headers.
|
|
#ifdef __FreeBSD__
|
|
return LOG_SECURITY;
|
|
#else
|
|
return LOG_AUTH;
|
|
#endif
|
|
}
|
|
else if ( hash == hash_syslog )
|
|
{
|
|
return LOG_SYSLOG;
|
|
}
|
|
else if ( hash == hash_user )
|
|
{
|
|
return LOG_USER;
|
|
}
|
|
else if ( hash == hash_uucp )
|
|
{
|
|
return LOG_UUCP;
|
|
}
|
|
else if ( hash == hash_local0 )
|
|
{
|
|
return LOG_LOCAL0;
|
|
}
|
|
else if ( hash == hash_local1 )
|
|
{
|
|
return LOG_LOCAL1;
|
|
}
|
|
else if ( hash == hash_local2 )
|
|
{
|
|
return LOG_LOCAL2;
|
|
}
|
|
else if ( hash == hash_local3 )
|
|
{
|
|
return LOG_LOCAL3;
|
|
}
|
|
else if ( hash == hash_local4 )
|
|
{
|
|
return LOG_LOCAL4;
|
|
}
|
|
else if ( hash == hash_local5 )
|
|
{
|
|
return LOG_LOCAL5;
|
|
}
|
|
else if ( hash == hash_local6 )
|
|
{
|
|
return LOG_LOCAL6;
|
|
}
|
|
else if ( hash == hash_local7 )
|
|
{
|
|
return LOG_LOCAL7;
|
|
}
|
|
#ifdef __APPLE__
|
|
else if ( hash == hash_launchd )
|
|
{
|
|
return LOG_LAUNCHD;
|
|
}
|
|
#endif
|
|
|
|
return LOG_DAEMON;
|
|
}
|
|
|
|
//we do not need to use this now, but I already created this function to be
|
|
//used case necessary.
|
|
/*
|
|
char *log_facility_name(int code)
|
|
{
|
|
char *defvalue = { "daemon" };
|
|
switch(code)
|
|
{
|
|
case LOG_AUTH:
|
|
{
|
|
return "auth";
|
|
}
|
|
case LOG_AUTHPRIV:
|
|
{
|
|
return "authpriv";
|
|
}
|
|
#ifdef __FreeBSD__
|
|
case LOG_CONSOLE:
|
|
{
|
|
return "console";
|
|
}
|
|
#endif
|
|
case LOG_CRON:
|
|
{
|
|
return "cron";
|
|
}
|
|
case LOG_DAEMON:
|
|
{
|
|
return defvalue;
|
|
}
|
|
case LOG_FTP:
|
|
{
|
|
return "ftp";
|
|
}
|
|
#ifdef __APPLE__
|
|
case LOG_INSTALL:
|
|
{
|
|
return "install";
|
|
}
|
|
#endif
|
|
case LOG_KERN:
|
|
{
|
|
return "kern";
|
|
}
|
|
case LOG_LPR:
|
|
{
|
|
return "lpr";
|
|
}
|
|
case LOG_MAIL:
|
|
{
|
|
return "mail";
|
|
}
|
|
#ifdef __APPLE__
|
|
case LOG_NETINFO:
|
|
{
|
|
return "netinfo" ;
|
|
}
|
|
case LOG_RAS:
|
|
{
|
|
return "ras";
|
|
}
|
|
case LOG_REMOTEAUTH:
|
|
{
|
|
return "remoteauth";
|
|
}
|
|
#endif
|
|
case LOG_NEWS:
|
|
{
|
|
return "news";
|
|
}
|
|
#ifdef __FreeBSD__
|
|
case LOG_NTP:
|
|
{
|
|
return "ntp" ;
|
|
}
|
|
case LOG_SECURITY:
|
|
{
|
|
return "security";
|
|
}
|
|
#endif
|
|
case LOG_SYSLOG:
|
|
{
|
|
return "syslog";
|
|
}
|
|
case LOG_USER:
|
|
{
|
|
return "user";
|
|
}
|
|
case LOG_UUCP:
|
|
{
|
|
return "uucp";
|
|
}
|
|
case LOG_LOCAL0:
|
|
{
|
|
return "local0";
|
|
}
|
|
case LOG_LOCAL1:
|
|
{
|
|
return "local1";
|
|
}
|
|
case LOG_LOCAL2:
|
|
{
|
|
return "local2";
|
|
}
|
|
case LOG_LOCAL3:
|
|
{
|
|
return "local3";
|
|
}
|
|
case LOG_LOCAL4:
|
|
{
|
|
return "local4" ;
|
|
}
|
|
case LOG_LOCAL5:
|
|
{
|
|
return "local5";
|
|
}
|
|
case LOG_LOCAL6:
|
|
{
|
|
return "local6";
|
|
}
|
|
case LOG_LOCAL7:
|
|
{
|
|
return "local7" ;
|
|
}
|
|
#ifdef __APPLE__
|
|
case LOG_LAUNCHD:
|
|
{
|
|
return "launchd";
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return defvalue;
|
|
}
|
|
*/
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void syslog_init() {
|
|
static int i = 0;
|
|
|
|
if(!i) {
|
|
openlog(program_name, LOG_PID,log_facility_id(facility_log));
|
|
i = 1;
|
|
}
|
|
}
|
|
|
|
#define LOG_DATE_LENGTH 26
|
|
|
|
static inline void log_date(char *buffer, size_t len) {
|
|
if(unlikely(!buffer || !len))
|
|
return;
|
|
|
|
time_t t;
|
|
struct tm *tmp, tmbuf;
|
|
|
|
t = now_realtime_sec();
|
|
tmp = localtime_r(&t, &tmbuf);
|
|
|
|
if (tmp == NULL) {
|
|
buffer[0] = '\0';
|
|
return;
|
|
}
|
|
|
|
if (unlikely(strftime(buffer, len, "%Y-%m-%d %H:%M:%S", tmp) == 0))
|
|
buffer[0] = '\0';
|
|
|
|
buffer[len - 1] = '\0';
|
|
}
|
|
|
|
static netdata_mutex_t log_mutex = NETDATA_MUTEX_INITIALIZER;
|
|
static inline void log_lock() {
|
|
netdata_mutex_lock(&log_mutex);
|
|
}
|
|
static inline void log_unlock() {
|
|
netdata_mutex_unlock(&log_mutex);
|
|
}
|
|
|
|
static FILE *open_log_file(int fd, FILE *fp, const char *filename, int *enabled_syslog, int is_stdaccess, int *fd_ptr) {
|
|
int f, devnull = 0;
|
|
|
|
if(!filename || !*filename || !strcmp(filename, "none") || !strcmp(filename, "/dev/null")) {
|
|
filename = "/dev/null";
|
|
devnull = 1;
|
|
}
|
|
|
|
if(!strcmp(filename, "syslog")) {
|
|
filename = "/dev/null";
|
|
devnull = 1;
|
|
|
|
syslog_init();
|
|
if(enabled_syslog) *enabled_syslog = 1;
|
|
}
|
|
else if(enabled_syslog) *enabled_syslog = 0;
|
|
|
|
// don't do anything if the user is willing
|
|
// to have the standard one
|
|
if(!strcmp(filename, "system")) {
|
|
if(fd != -1 && !is_stdaccess) {
|
|
if(fd_ptr) *fd_ptr = fd;
|
|
return fp;
|
|
}
|
|
|
|
filename = "stderr";
|
|
}
|
|
|
|
if(!strcmp(filename, "stdout"))
|
|
f = STDOUT_FILENO;
|
|
|
|
else if(!strcmp(filename, "stderr"))
|
|
f = STDERR_FILENO;
|
|
|
|
else {
|
|
f = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0664);
|
|
if(f == -1) {
|
|
error("Cannot open file '%s'. Leaving %d to its default.", filename, fd);
|
|
if(fd_ptr) *fd_ptr = fd;
|
|
return fp;
|
|
}
|
|
}
|
|
|
|
// if there is a level-2 file pointer
|
|
// flush it before switching the level-1 fds
|
|
if(fp)
|
|
fflush(fp);
|
|
|
|
if(devnull && is_stdaccess) {
|
|
fd = -1;
|
|
fp = NULL;
|
|
}
|
|
|
|
if(fd != f && fd != -1) {
|
|
// it automatically closes
|
|
int t = dup2(f, fd);
|
|
if (t == -1) {
|
|
error("Cannot dup2() new fd %d to old fd %d for '%s'", f, fd, filename);
|
|
close(f);
|
|
if(fd_ptr) *fd_ptr = fd;
|
|
return fp;
|
|
}
|
|
// info("dup2() new fd %d to old fd %d for '%s'", f, fd, filename);
|
|
close(f);
|
|
}
|
|
else fd = f;
|
|
|
|
if(!fp) {
|
|
fp = fdopen(fd, "a");
|
|
if (!fp)
|
|
error("Cannot fdopen() fd %d ('%s')", fd, filename);
|
|
else {
|
|
if (setvbuf(fp, NULL, _IOLBF, 0) != 0)
|
|
error("Cannot set line buffering on fd %d ('%s')", fd, filename);
|
|
}
|
|
}
|
|
|
|
if(fd_ptr) *fd_ptr = fd;
|
|
return fp;
|
|
}
|
|
|
|
void reopen_all_log_files() {
|
|
if(stdout_filename)
|
|
open_log_file(STDOUT_FILENO, stdout, stdout_filename, &output_log_syslog, 0, NULL);
|
|
|
|
if(stderr_filename)
|
|
open_log_file(STDERR_FILENO, stderr, stderr_filename, &error_log_syslog, 0, NULL);
|
|
|
|
#ifdef ENABLE_ACLK
|
|
if (aclklog_enabled)
|
|
aclklog = open_log_file(aclklog_fd, aclklog, aclklog_filename, NULL, 0, &aclklog_fd);
|
|
#endif
|
|
|
|
if(stdaccess_filename)
|
|
stdaccess = open_log_file(stdaccess_fd, stdaccess, stdaccess_filename, &access_log_syslog, 1, &stdaccess_fd);
|
|
}
|
|
|
|
void open_all_log_files() {
|
|
// disable stdin
|
|
open_log_file(STDIN_FILENO, stdin, "/dev/null", NULL, 0, NULL);
|
|
|
|
open_log_file(STDOUT_FILENO, stdout, stdout_filename, &output_log_syslog, 0, NULL);
|
|
open_log_file(STDERR_FILENO, stderr, stderr_filename, &error_log_syslog, 0, NULL);
|
|
|
|
#ifdef ENABLE_ACLK
|
|
if(aclklog_enabled)
|
|
aclklog = open_log_file(aclklog_fd, aclklog, aclklog_filename, NULL, 0, &aclklog_fd);
|
|
#endif
|
|
|
|
stdaccess = open_log_file(stdaccess_fd, stdaccess, stdaccess_filename, &access_log_syslog, 1, &stdaccess_fd);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// error log throttling
|
|
|
|
time_t error_log_throttle_period = 1200;
|
|
unsigned long error_log_errors_per_period = 200;
|
|
unsigned long error_log_errors_per_period_backup = 0;
|
|
|
|
int error_log_limit(int reset) {
|
|
static time_t start = 0;
|
|
static unsigned long counter = 0, prevented = 0;
|
|
|
|
// fprintf(stderr, "FLOOD: counter=%lu, allowed=%lu, backup=%lu, period=%llu\n", counter, error_log_errors_per_period, error_log_errors_per_period_backup, (unsigned long long)error_log_throttle_period);
|
|
|
|
// do not throttle if the period is 0
|
|
if(error_log_throttle_period == 0)
|
|
return 0;
|
|
|
|
// prevent all logs if the errors per period is 0
|
|
if(error_log_errors_per_period == 0)
|
|
#ifdef NETDATA_INTERNAL_CHECKS
|
|
return 0;
|
|
#else
|
|
return 1;
|
|
#endif
|
|
|
|
time_t now = now_monotonic_sec();
|
|
if(!start) start = now;
|
|
|
|
if(reset) {
|
|
if(prevented) {
|
|
char date[LOG_DATE_LENGTH];
|
|
log_date(date, LOG_DATE_LENGTH);
|
|
fprintf(
|
|
stderr,
|
|
"%s: %s LOG FLOOD PROTECTION reset for process '%s' "
|
|
"(prevented %lu logs in the last %"PRId64" seconds).\n",
|
|
date,
|
|
program_name,
|
|
program_name,
|
|
prevented,
|
|
(int64_t)(now - start));
|
|
}
|
|
|
|
start = now;
|
|
counter = 0;
|
|
prevented = 0;
|
|
}
|
|
|
|
// detect if we log too much
|
|
counter++;
|
|
|
|
if(now - start > error_log_throttle_period) {
|
|
if(prevented) {
|
|
char date[LOG_DATE_LENGTH];
|
|
log_date(date, LOG_DATE_LENGTH);
|
|
fprintf(
|
|
stderr,
|
|
"%s: %s LOG FLOOD PROTECTION resuming logging from process '%s' "
|
|
"(prevented %lu logs in the last %"PRId64" seconds).\n",
|
|
date,
|
|
program_name,
|
|
program_name,
|
|
prevented,
|
|
(int64_t)error_log_throttle_period);
|
|
}
|
|
|
|
// restart the period accounting
|
|
start = now;
|
|
counter = 1;
|
|
prevented = 0;
|
|
|
|
// log this error
|
|
return 0;
|
|
}
|
|
|
|
if(counter > error_log_errors_per_period) {
|
|
if(!prevented) {
|
|
char date[LOG_DATE_LENGTH];
|
|
log_date(date, LOG_DATE_LENGTH);
|
|
fprintf(
|
|
stderr,
|
|
"%s: %s LOG FLOOD PROTECTION too many logs (%lu logs in %"PRId64" seconds, threshold is set to %lu logs "
|
|
"in %"PRId64" seconds). Preventing more logs from process '%s' for %"PRId64" seconds.\n",
|
|
date,
|
|
program_name,
|
|
counter,
|
|
(int64_t)(now - start),
|
|
error_log_errors_per_period,
|
|
(int64_t)error_log_throttle_period,
|
|
program_name,
|
|
(int64_t)(start + error_log_throttle_period - now));
|
|
}
|
|
|
|
prevented++;
|
|
|
|
// prevent logging this error
|
|
#ifdef NETDATA_INTERNAL_CHECKS
|
|
return 0;
|
|
#else
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void error_log_limit_reset(void) {
|
|
log_lock();
|
|
|
|
error_log_errors_per_period = error_log_errors_per_period_backup;
|
|
error_log_limit(1);
|
|
|
|
log_unlock();
|
|
}
|
|
|
|
void error_log_limit_unlimited(void) {
|
|
log_lock();
|
|
|
|
error_log_errors_per_period = error_log_errors_per_period_backup;
|
|
error_log_limit(1);
|
|
|
|
error_log_errors_per_period = ((error_log_errors_per_period_backup * 10) < 10000) ? 10000 : (error_log_errors_per_period_backup * 10);
|
|
|
|
log_unlock();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// debug log
|
|
|
|
void debug_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... ) {
|
|
va_list args;
|
|
|
|
char date[LOG_DATE_LENGTH];
|
|
log_date(date, LOG_DATE_LENGTH);
|
|
|
|
va_start( args, fmt );
|
|
printf("%s: %s DEBUG : %s : (%04lu@%-20.20s:%-15.15s): ", date, program_name, netdata_thread_tag(), line, file, function);
|
|
vprintf(fmt, args);
|
|
va_end( args );
|
|
putchar('\n');
|
|
|
|
if(output_log_syslog) {
|
|
va_start( args, fmt );
|
|
vsyslog(LOG_ERR, fmt, args );
|
|
va_end( args );
|
|
}
|
|
|
|
fflush(stdout);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// info log
|
|
|
|
void info_int( const char *file __maybe_unused, const char *function __maybe_unused, const unsigned long line __maybe_unused, const char *fmt, ... )
|
|
{
|
|
va_list args;
|
|
|
|
log_lock();
|
|
|
|
// prevent logging too much
|
|
if (error_log_limit(0)) {
|
|
log_unlock();
|
|
return;
|
|
}
|
|
|
|
if(error_log_syslog) {
|
|
va_start( args, fmt );
|
|
vsyslog(LOG_INFO, fmt, args );
|
|
va_end( args );
|
|
}
|
|
|
|
char date[LOG_DATE_LENGTH];
|
|
log_date(date, LOG_DATE_LENGTH);
|
|
|
|
va_start( args, fmt );
|
|
#ifdef NETDATA_INTERNAL_CHECKS
|
|
fprintf(stderr, "%s: %s INFO : %s : (%04lu@%-20.20s:%-15.15s): ", date, program_name, netdata_thread_tag(), line, file, function);
|
|
#else
|
|
fprintf(stderr, "%s: %s INFO : %s : ", date, program_name, netdata_thread_tag());
|
|
#endif
|
|
vfprintf( stderr, fmt, args );
|
|
va_end( args );
|
|
|
|
fputc('\n', stderr);
|
|
|
|
log_unlock();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// error log
|
|
|
|
#if defined(STRERROR_R_CHAR_P)
|
|
// GLIBC version of strerror_r
|
|
static const char *strerror_result(const char *a, const char *b) { (void)b; return a; }
|
|
#elif defined(HAVE_STRERROR_R)
|
|
// POSIX version of strerror_r
|
|
static const char *strerror_result(int a, const char *b) { (void)a; return b; }
|
|
#elif defined(HAVE_C__GENERIC)
|
|
|
|
// what a trick!
|
|
// http://stackoverflow.com/questions/479207/function-overloading-in-c
|
|
static const char *strerror_result_int(int a, const char *b) { (void)a; return b; }
|
|
static const char *strerror_result_string(const char *a, const char *b) { (void)b; return a; }
|
|
|
|
#define strerror_result(a, b) _Generic((a), \
|
|
int: strerror_result_int, \
|
|
char *: strerror_result_string \
|
|
)(a, b)
|
|
|
|
#else
|
|
#error "cannot detect the format of function strerror_r()"
|
|
#endif
|
|
|
|
void error_int( const char *prefix, const char *file __maybe_unused, const char *function __maybe_unused, const unsigned long line __maybe_unused, const char *fmt, ... ) {
|
|
// save a copy of errno - just in case this function generates a new error
|
|
int __errno = errno;
|
|
|
|
va_list args;
|
|
|
|
log_lock();
|
|
|
|
// prevent logging too much
|
|
if (error_log_limit(0)) {
|
|
log_unlock();
|
|
return;
|
|
}
|
|
|
|
if(error_log_syslog) {
|
|
va_start( args, fmt );
|
|
vsyslog(LOG_ERR, fmt, args );
|
|
va_end( args );
|
|
}
|
|
|
|
char date[LOG_DATE_LENGTH];
|
|
log_date(date, LOG_DATE_LENGTH);
|
|
|
|
va_start( args, fmt );
|
|
#ifdef NETDATA_INTERNAL_CHECKS
|
|
fprintf(stderr, "%s: %s %-5.5s : %s : (%04lu@%-20.20s:%-15.15s): ", date, program_name, prefix, netdata_thread_tag(), line, file, function);
|
|
#else
|
|
fprintf(stderr, "%s: %s %-5.5s : %s : ", date, program_name, prefix, netdata_thread_tag());
|
|
#endif
|
|
vfprintf( stderr, fmt, args );
|
|
va_end( args );
|
|
|
|
if(__errno) {
|
|
char buf[1024];
|
|
fprintf(stderr, " (errno %d, %s)\n", __errno, strerror_result(strerror_r(__errno, buf, 1023), buf));
|
|
errno = 0;
|
|
}
|
|
else
|
|
fputc('\n', stderr);
|
|
|
|
log_unlock();
|
|
}
|
|
|
|
#ifdef NETDATA_INTERNAL_CHECKS
|
|
static void crash_netdata(void) {
|
|
// make Netdata core dump
|
|
abort();
|
|
}
|
|
#endif
|
|
|
|
void fatal_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... ) {
|
|
// save a copy of errno - just in case this function generates a new error
|
|
int __errno = errno;
|
|
va_list args;
|
|
const char *thread_tag;
|
|
char os_threadname[NETDATA_THREAD_NAME_MAX + 1];
|
|
|
|
if(error_log_syslog) {
|
|
va_start( args, fmt );
|
|
vsyslog(LOG_CRIT, fmt, args );
|
|
va_end( args );
|
|
}
|
|
|
|
thread_tag = netdata_thread_tag();
|
|
if (!netdata_thread_tag_exists()) {
|
|
os_thread_get_current_name_np(os_threadname);
|
|
if ('\0' != os_threadname[0]) { /* If it is not an empty string replace "MAIN" thread_tag */
|
|
thread_tag = os_threadname;
|
|
}
|
|
}
|
|
|
|
char date[LOG_DATE_LENGTH];
|
|
log_date(date, LOG_DATE_LENGTH);
|
|
|
|
log_lock();
|
|
|
|
va_start( args, fmt );
|
|
#ifdef NETDATA_INTERNAL_CHECKS
|
|
fprintf(stderr, "%s: %s FATAL : %s : (%04lu@%-20.20s:%-15.15s): ", date, program_name, thread_tag, line, file, function);
|
|
#else
|
|
fprintf(stderr, "%s: %s FATAL : %s : ", date, program_name, thread_tag);
|
|
#endif
|
|
vfprintf( stderr, fmt, args );
|
|
va_end( args );
|
|
|
|
perror(" # ");
|
|
fputc('\n', stderr);
|
|
|
|
log_unlock();
|
|
|
|
char action_data[70+1];
|
|
snprintfz(action_data, 70, "%04lu@%-10.10s:%-15.15s/%d", line, file, function, __errno);
|
|
char action_result[60+1];
|
|
|
|
snprintfz(action_result, 60, "%s:%s", program_name, strncmp(thread_tag, "STREAM_RECEIVER", strlen("STREAM_RECEIVER")) ? thread_tag : "[x]");
|
|
send_statistics("FATAL", action_result, action_data);
|
|
|
|
#ifdef NETDATA_INTERNAL_CHECKS
|
|
crash_netdata();
|
|
#endif
|
|
|
|
netdata_cleanup_and_exit(1);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// access log
|
|
|
|
void log_access( const char *fmt, ... ) {
|
|
va_list args;
|
|
|
|
if(access_log_syslog) {
|
|
va_start( args, fmt );
|
|
vsyslog(LOG_INFO, fmt, args );
|
|
va_end( args );
|
|
}
|
|
|
|
if(stdaccess) {
|
|
static netdata_mutex_t access_mutex = NETDATA_MUTEX_INITIALIZER;
|
|
|
|
if(web_server_is_multithreaded)
|
|
netdata_mutex_lock(&access_mutex);
|
|
|
|
char date[LOG_DATE_LENGTH];
|
|
log_date(date, LOG_DATE_LENGTH);
|
|
fprintf(stdaccess, "%s: ", date);
|
|
|
|
va_start( args, fmt );
|
|
vfprintf( stdaccess, fmt, args );
|
|
va_end( args );
|
|
fputc('\n', stdaccess);
|
|
|
|
if(web_server_is_multithreaded)
|
|
netdata_mutex_unlock(&access_mutex);
|
|
}
|
|
}
|
|
|
|
#ifdef ENABLE_ACLK
|
|
void log_aclk_message_bin( const char *data, const size_t data_len, int tx, const char *mqtt_topic, const char *message_name) {
|
|
if (aclklog) {
|
|
static netdata_mutex_t aclklog_mutex = NETDATA_MUTEX_INITIALIZER;
|
|
netdata_mutex_lock(&aclklog_mutex);
|
|
|
|
char date[LOG_DATE_LENGTH];
|
|
log_date(date, LOG_DATE_LENGTH);
|
|
fprintf(aclklog, "%s: %s Msg:\"%s\", MQTT-topic:\"%s\": ", date, tx ? "OUTGOING" : "INCOMING", message_name, mqtt_topic);
|
|
|
|
fwrite(data, data_len, 1, aclklog);
|
|
|
|
fputc('\n', aclklog);
|
|
|
|
netdata_mutex_unlock(&aclklog_mutex);
|
|
}
|
|
}
|
|
#endif
|