error_log_limit_unlimited();
- info("Called: netdata_cleanup_and_exit()");
+ debug(D_EXIT, "Called: netdata_cleanup_and_exit()");
#ifdef NETDATA_INTERNAL_CHECKS
rrdset_free_all();
#else
}
if(tc_child_pid) {
- info("Killing tc-qos-helper procees");
+ debug(D_EXIT, "Killing tc-qos-helper procees");
if(killpid(tc_child_pid, SIGTERM) != -1)
waitid(P_PID, (id_t) tc_child_pid, &info, WEXITED);
}
Same as 'update every' config file option.", "seconds", "1"},
{'u', "System username to run as.", "username", "netdata"},
{'v', "Version of the program", NULL, NULL},
- {'W', "vendor options.", "stacksize=<size>|unittest|debug_flag", NULL},
+ {'W', "vendor options.", "stacksize=N|unittest|debug_flags=N", NULL},
};
void help(int exitcode) {
} while(argv[i][0] != '-' && opt_index >= *argc);
}
+static const char *verify_required_directory(const char *dir) {
+ if(chdir(dir) == -1)
+ fatal("Cannot cd to directory '%s'", dir);
+
+ DIR *d = opendir(dir);
+ if(!d)
+ fatal("Cannot examine the contents of directory '%s'", dir);
+ closedir(d);
+
+ return dir;
+}
int main(int argc, char **argv)
{
+ char *hostname = "localhost";
int i, check_config = 0;
int config_loaded = 0;
int dont_fork = 0;
size_t wanted_stacksize = 0, stacksize = 0;
pthread_attr_t attr;
- // global initialization
- get_HZ();
-
// set the name for logging
program_name = "netdata";
- // parse command line.
-
// parse depercated options
// TODO: Remove this block with the next major release.
{
break;
case 'v':
// TODO: Outsource version to makefile which can compute version from git.
- printf("netdata 1.2.1_master\n");
+ printf("netdata %s\n", VERSION);
return 0;
case 'W':
{
}
}
- if(!config_loaded) load_config(NULL, 0);
+ if(!config_loaded)
+ load_config(NULL, 0);
+
+ {
+ char *pmax = config_get("global", "glibc malloc arena max for plugins", "1");
+ if(pmax && *pmax)
+ setenv("MALLOC_ARENA_MAX", pmax, 1);
+
+#if defined(HAVE_C_MALLOPT)
+ int i = config_get_number("global", "glibc malloc arena max for netdata", 1);
+ if(i > 0)
+ mallopt(M_ARENA_MAX, 1);
+#endif
- // prepare configuration environment variables for the plugins
- setenv("NETDATA_CONFIG_DIR" , config_get("global", "config directory" , CONFIG_DIR) , 1);
- setenv("NETDATA_PLUGINS_DIR", config_get("global", "plugins directory" , PLUGINS_DIR), 1);
- setenv("NETDATA_WEB_DIR" , config_get("global", "web files directory", WEB_DIR) , 1);
- setenv("NETDATA_CACHE_DIR" , config_get("global", "cache directory" , CACHE_DIR) , 1);
- setenv("NETDATA_LIB_DIR" , config_get("global", "lib directory" , VARLIB_DIR) , 1);
- setenv("NETDATA_LOG_DIR" , config_get("global", "log directory" , LOG_DIR) , 1);
- setenv("NETDATA_HOST_PREFIX", config_get("global", "host access prefix" , "") , 1);
- setenv("HOME" , config_get("global", "home directory" , CACHE_DIR) , 1);
+ char *config_dir = config_get("global", "config directory", CONFIG_DIR);
- // disable buffering for python plugins
- setenv("PYTHONUNBUFFERED", "1", 1);
+ // prepare configuration environment variables for the plugins
+ setenv("NETDATA_CONFIG_DIR" , verify_required_directory(config_dir) , 1);
+ setenv("NETDATA_PLUGINS_DIR", verify_required_directory(config_get("global", "plugins directory" , PLUGINS_DIR)), 1);
+ setenv("NETDATA_WEB_DIR" , verify_required_directory(config_get("global", "web files directory", WEB_DIR)) , 1);
+ setenv("NETDATA_CACHE_DIR" , verify_required_directory(config_get("global", "cache directory" , CACHE_DIR)) , 1);
+ setenv("NETDATA_LIB_DIR" , verify_required_directory(config_get("global", "lib directory" , VARLIB_DIR)) , 1);
+ setenv("NETDATA_LOG_DIR" , verify_required_directory(config_get("global", "log directory" , LOG_DIR)) , 1);
- // avoid flood calls to stat(/etc/localtime)
- // http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux
- setenv("TZ", ":/etc/localtime", 0);
+ setenv("NETDATA_HOST_PREFIX", config_get("global", "host access prefix" , "") , 1);
+ setenv("HOME" , config_get("global", "home directory" , CACHE_DIR) , 1);
+
+ // disable buffering for python plugins
+ setenv("PYTHONUNBUFFERED", "1", 1);
+
+ // avoid flood calls to stat(/etc/localtime)
+ // http://stackoverflow.com/questions/4554271/how-to-avoid-excessive-stat-etc-localtime-calls-in-strftime-on-linux
+ setenv("TZ", ":/etc/localtime", 0);
+
+ // work while we are cd into config_dir
+ // to allow the plugins refer to their config
+ // files using relative filenames
+ if(chdir(config_dir) == -1)
+ fatal("Cannot cd to '%s'", config_dir);
- {
char path[1024 + 1], *p = getenv("PATH");
if(!p) p = "/bin:/usr/bin";
snprintfz(path, 1024, "%s:%s", p, "/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin");
setenv("PATH", config_get("plugins", "PATH environment variable", path), 1);
}
- // cd to /tmp to avoid any plugins writing files at random places
- if(chdir("/tmp")) error("netdata: ERROR: Cannot cd to /tmp");
-
char *user = NULL;
{
char *flags = config_get("global", "debug flags", "0x00000000");
if(debug_flags != 0) {
struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
if(setrlimit(RLIMIT_CORE, &rl) != 0)
- info("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
+ error("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
+
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
}
global_host_prefix = config_get("global", "host access prefix", "");
setenv("NETDATA_HOST_PREFIX", global_host_prefix, 1);
+ get_system_HZ();
+ get_system_cpus();
+ get_system_pid_max();
+
// --------------------------------------------------------------------
stdout_filename = config_get("global", "debug log", LOG_DIR "/debug.log");
stderr_filename = config_get("global", "error log", LOG_DIR "/error.log");
stdaccess_filename = config_get("global", "access log", LOG_DIR "/access.log");
- error_log_throttle_period = config_get_number("global", "errors flood protection period", error_log_throttle_period);
+ error_log_throttle_period_backup =
+ error_log_throttle_period = config_get_number("global", "errors flood protection period", error_log_throttle_period);
setenv("NETDATA_ERRORS_THROTTLE_PERIOD", config_get("global", "errors flood protection period" , ""), 1);
error_log_errors_per_period = (unsigned long)config_get_number("global", "errors to trigger flood protection", error_log_errors_per_period);
error_log_throttle_period = 0;
error_log_errors_per_period = 0;
}
+ error_log_limit_unlimited();
// --------------------------------------------------------------------
error("WARNING: Cannot get machine hostname.");
hostname = config_get("global", "hostname", hostnamebuf);
debug(D_OPTIONS, "hostname set to '%s'", hostname);
+ setenv("NETDATA_HOSTNAME", hostname, 1);
}
// --------------------------------------------------------------------
rrd_default_history_entries = (int) config_get_number("global", "history", RRD_DEFAULT_HISTORY_ENTRIES);
if(rrd_default_history_entries < 5 || rrd_default_history_entries > RRD_HISTORY_ENTRIES_MAX) {
- info("Invalid save lines %d given. Defaulting to %d.", rrd_default_history_entries, RRD_DEFAULT_HISTORY_ENTRIES);
+ error("Invalid history entries %d given. Defaulting to %d.", rrd_default_history_entries, RRD_DEFAULT_HISTORY_ENTRIES);
rrd_default_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
}
else {
rrd_update_every = (int) config_get_number("global", "update every", UPDATE_EVERY);
if(rrd_update_every < 1 || rrd_update_every > 600) {
- info("Invalid update timer %d given. Defaulting to %d.", rrd_update_every, UPDATE_EVERY_MAX);
+ error("Invalid data collection frequency (update every) %d given. Defaulting to %d.", rrd_update_every, UPDATE_EVERY_MAX);
rrd_update_every = UPDATE_EVERY;
}
else debug(D_OPTIONS, "update timer set to %d.", rrd_update_every);
// this causes the threads to block signals.
sigset_t sigset;
sigfillset(&sigset);
-
- if(pthread_sigmask(SIG_BLOCK, &sigset, NULL) == -1) {
+ if(pthread_sigmask(SIG_BLOCK, &sigset, NULL) == -1)
error("Could not block signals for threads");
- }
// Catch signals which we want to use
struct sigaction sa;
- sigemptyset(&sa.sa_mask);
- sigaddset(&sa.sa_mask, SIGINT);
- sigaddset(&sa.sa_mask, SIGTERM);
- sa.sa_handler = sig_handler_exit;
sa.sa_flags = 0;
- if(sigaction(SIGINT, &sa, NULL) == -1) {
+
+ // ingore all signals while we run in a signal handler
+ sigfillset(&sa.sa_mask);
+
+ // INFO: If we add signals here we have to unblock them
+ // at popen.c when running a external plugin.
+
+ // Ignore SIGPIPE completely.
+ sa.sa_handler = SIG_IGN;
+ if(sigaction(SIGPIPE, &sa, NULL) == -1)
+ error("Failed to change signal handler for SIGPIPE");
+
+ sa.sa_handler = sig_handler_exit;
+ if(sigaction(SIGINT, &sa, NULL) == -1)
error("Failed to change signal handler for SIGINT");
- }
- if(sigaction(SIGTERM, &sa, NULL) == -1) {
+
+ sa.sa_handler = sig_handler_exit;
+ if(sigaction(SIGTERM, &sa, NULL) == -1)
error("Failed to change signal handler for SIGTERM");
- }
- sigemptyset(&sa.sa_mask);
- sigaddset(&sa.sa_mask, SIGHUP);
sa.sa_handler = sig_handler_logrotate;
- sa.sa_flags = 0;
- if(sigaction(SIGHUP, &sa, NULL) == -1) {
+ if(sigaction(SIGHUP, &sa, NULL) == -1)
error("Failed to change signal handler for SIGHUP");
- }
// save database on SIGUSR1
- sigemptyset(&sa.sa_mask);
- sigaddset(&sa.sa_mask, SIGUSR1);
sa.sa_handler = sig_handler_save;
- if(sigaction(SIGUSR1, &sa, NULL) == -1) {
+ if(sigaction(SIGUSR1, &sa, NULL) == -1)
error("Failed to change signal handler for SIGUSR1");
- }
- // Ignore SIGPIPE completely.
- // INFO: If we add signals here we have to unblock them
- // at popen.c when running a external plugin.
- sigemptyset(&sa.sa_mask);
- sigaddset(&sa.sa_mask, SIGPIPE);
- sa.sa_handler = SIG_IGN;
- if(sigaction(SIGPIPE, &sa, NULL) == -1) {
- error("Failed to change signal handler for SIGPIPE");
- }
+ // reload health configuration on SIGUSR2
+ sa.sa_handler = sig_handler_reload_health;
+ if(sigaction(SIGUSR2, &sa, NULL) == -1)
+ error("Failed to change signal handler for SIGUSR2");
// --------------------------------------------------------------------
if(debug_flags != 0) {
struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
if(setrlimit(RLIMIT_CORE, &rl) != 0)
- info("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
+ error("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
}
#endif /* NETDATA_INTERNAL_CHECKS */
if(i != 0)
fatal("pthread_attr_setstacksize() to %zu bytes, failed with code %d.", wanted_stacksize, i);
else
- info("Successfully set pthread stacksize to %zu bytes", wanted_stacksize);
+ debug(D_SYSTEM, "Successfully set pthread stacksize to %zu bytes", wanted_stacksize);
}
+ // ------------------------------------------------------------------------
+ // initialize rrd host
+
+ rrdhost_init(hostname);
+
// ------------------------------------------------------------------------
// initialize the registry
if(check_config)
exit(1);
+ // ------------------------------------------------------------------------
+ // enable log flood protection
+
+ error_log_limit_reset();
+
// ------------------------------------------------------------------------
// spawn the threads
if(st->enabled) {
st->thread = mallocz(sizeof(pthread_t));
- info("Starting thread %s.", st->name);
+ debug(D_SYSTEM, "Starting thread %s.", st->name);
if(pthread_create(st->thread, &attr, st->start_routine, NULL))
error("failed to create new thread for %s.", st->name);
else if(pthread_detach(*st->thread))
error("Cannot request detach of newly created %s thread.", st->name);
}
- else info("Not starting thread %s.", st->name);
+ else debug(D_SYSTEM, "Not starting thread %s.", st->name);
}
// ------------------------------------------------------------------------
while(1) {
pause();
if(netdata_exit) {
- info("Exit main loop of netdata.");
+ debug(D_EXIT, "Exit main loop of netdata.");
netdata_cleanup_and_exit(0);
exit(0);
}