// Background thread for logging static void log_thread_process(void *arg) { int rv; log_entry *entry; (void)(arg); // Signal the init function that the logger thread is ready pthread_cond_signal(&wait_log_thread); //printf("-- BACKGROUND THREAD STARTED\n"); for (;;) { if (log_lock()) { break; } if (log_qfirst != NULL) { rv = 0; } else { rv = pthread_cond_wait(&queue_data_present, &mutex); } if (!rv) { // Get the next item //printf("-- GET ITEM\n"); entry = log_entry_pop(); log_unlock(); while (entry != NULL) { //printf("-- PRINT ITEM\n"); // Log the type of the thing to log log_type(entry->level); // Log the timestamp log_time(&(entry->tv)); // Log thread ID: log_threadid(entry->thread); // Output formatted string putc(' ', *log_out); set_lvlcolor(entry->level); fputs(entry->msg, *log_out); // Log function, file and line number log_fileline(entry->func, entry->file, entry->line); // Log EOL log_lineend(); // Destroy the current instance log_entry_destroy(entry); // Get the next item (if present) entry = log_entry_pop(); } if (log_thread_quit) { //printf("-- EXIT REQUESTED\n"); break; } } else { //printf("-- SIGNAL FAILED\n"); log_unlock(); } } //printf("-- BACKGROUND THREAD EXIT\n"); pthread_exit(NULL); }
int log_set_file(const char *file) { FILE *f, *old; if (file) { f = fopen(file, "a"); if (!f) { log_err("cannot change log-file to %s (%d): %s", file, errno, strerror(errno)); return -EFAULT; } } else { f = NULL; file = "<default>"; } old = NULL; log_lock(); if (log__file != f) { log__format(LOG_DEFAULT, LOG_NOTICE, "set log-file to %s", file); old = log__file; log__file = f; f = NULL; } log_unlock(); if (f) fclose(f); if (old) fclose(old); return 0; }
int log_add_filter(const struct log_filter *filter, const struct log_config *config) { struct log_dynconf *dconf; int ret; if (!filter || !config) return -EINVAL; dconf = malloc(sizeof(*dconf)); if (!dconf) return -ENOMEM; memset(dconf, 0, sizeof(*dconf)); memcpy(&dconf->filter, filter, sizeof(*filter)); memcpy(&dconf->config, config, sizeof(*config)); log_lock(); if (log__dconfig) dconf->handle = log__dconfig->handle + 1; dconf->next = log__dconfig; log__dconfig = dconf; ret = dconf->handle; log_unlock(); return ret; }
static inline void init_log() { static int init = 0; if (init) return; init = 1; // Threading support pthread_mutexattr_init(&mutex_atr); //pthread_mutexattr_settype(&mutex_atr, PTHREAD_MUTEX_RECURSIVE); pthread_mutexattr_settype(&mutex_atr, PTHREAD_MUTEX_RECURSIVE_NP); pthread_mutex_init(&mutex, &mutex_atr); log_lock(); // Must be called before localtime_r tzset(); log_setoutput(NULL); #ifdef LOG_THREADED if (pthread_create(&log_thread, NULL, (void *(*)(void *))log_thread_process, NULL)) { fprintf(stderr, "LOGGER: ERROR CREATING BACKGROUND THREAD!\n"); exit(1); } else { atexit(log_wait_thread); logthread_ready(); } #endif log_unlock(); }
int vrtpprintf(TURN_LOG_LEVEL level, const char *format, va_list args) { /* Fix for Issue 24, raised by John Selbie: */ #define MAX_RTPPRINTF_BUFFER_SIZE (1024) char s[MAX_RTPPRINTF_BUFFER_SIZE+1]; #undef MAX_RTPPRINTF_BUFFER_SIZE size_t sz; snprintf(s, sizeof(s), "%lu: ",(unsigned long)log_time()); sz=strlen(s); vsnprintf(s+sz, sizeof(s)-1-sz, format, args); s[sizeof(s)-1]=0; if(to_syslog) { syslog(get_syslog_level(level),"%s",s); } else { log_lock(); set_rtpfile(); if(fprintf(_rtpfile,"%s",s)<0) { reset_rtpprintf(); } else if(fflush(_rtpfile)<0) { reset_rtpprintf(); } log_unlock(); } return 0; }
void log_set_config(const struct log_config *config) { if (!config) return; log_lock(); log__gconfig = *config; log_unlock(); }
void reset_rtpprintf(void) { log_lock(); if(_rtpfile) { if(_rtpfile != stdout) fclose(_rtpfile); _rtpfile = NULL; } log_unlock(); }
static void log_wait_thread() { //printf("Killing threads...\n"); log_lock(); log_thread_quit = 1; log_unlock(); pthread_cond_signal(&queue_data_present); pthread_join(log_thread, NULL); //printf("Threads finished\n"); }
void set_logfile(const char *fn) { if(fn) { log_lock(); if(strcmp(fn,log_fn_base)) { reset_rtpprintf(); STRCPY(log_fn_base,fn); } log_unlock(); } }
void log_clean_filters() { struct log_dynconf *dconf; log_lock(); while ((dconf = log__dconfig)) { log__dconfig = dconf->next; free(dconf); } log_unlock(); }
void log_setoutput(FILE *out) { log_lock(); if (out == NULL) { log_out = NULL; } else { log_out = &out; } if (log_out == NULL) { log_out = &stdout; } do_color = isatty(fileno(*log_out)); log_unlock(); }
void do_log(LOG_LEVEL log_level, char *file_name, char *function, int line, char *fmt, ...) { struct tm *log_now; time_t log_t; va_list arg; char tmp[1024]; char buf[4096]; assert(log_arg->log_level != LOG_NOLEVEL); if (log_level > log_arg->log_level) return ; va_start(arg, fmt); vsprintf(tmp, fmt, arg); va_end(arg); time(&log_t); log_now = localtime(&log_t); snprintf(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d -- %s:%s(%d): %s", log_now->tm_year + 1900, log_now->tm_mon + 1, log_now->tm_mday, log_now->tm_hour, log_now->tm_min, log_now->tm_sec, file_name, function, line, tmp); //sync(); log_lock(); if (check_log_size() == -1) { log_unlock(); return ; } fflush(log_arg->log_fp); fprintf(log_arg->log_fp, "%s", buf); log_unlock(); }
void log_submit(const char *file, int line, const char *func, const struct log_config *config, const char *subs, unsigned int sev, const char *format, va_list args) { int saved_errno = errno; log_lock(); log__submit(file, line, func, config, subs, sev, format, args); log_unlock(); errno = saved_errno; }
static void log_entry_push(log_entry *entry) { log_lock(); // Add to queue entry->next = NULL; if (log_qlast != NULL) { log_qlast->next = entry; } log_qlast = entry; if (log_qfirst == NULL) { log_qfirst = entry; } log_unlock(); pthread_cond_signal(&queue_data_present); }
void _logout(int lvl, const char *file, int line, const char *func, const char *format, ...) { va_list ap, ap_t; char *buf = NULL; int ret; struct timeval tv; //printf("UNTHREADED LOG\n"); if (lvl > log_level) return; // Get the time as soon as possible gettimeofday(&tv, NULL); // Init the log if needed init_log(); // Format output string va_start(ap, format); va_copy(ap_t, ap); ret = vsnprintf(buf, 0, format, ap_t); buf = malloc(ret+1); ret = vsnprintf(buf, ret+1, format, ap); va_end(ap); log_lock(); // TODO: Queue to background thread // Log the type of the thing to log log_type(lvl); // Log the timestamp log_time(&tv); // Output formatted string putc(' ', *log_out); set_lvlcolor(lvl); fputs(buf, *log_out); // Log function, file and line number log_fileline(func, file, line); // Log EOL log_lineend(); // Unlock the thread log_unlock(); // Free the buffer if (buf) free(buf); }
static log_entry *log_entry_pop() { log_entry *ret = NULL; log_lock(); ret = log_qfirst; if (ret != NULL) { log_qfirst = ret->next; ret->next = NULL; } else { ret = NULL; } if (log_qlast == ret) { log_qlast = NULL; } log_unlock(); return ret; }
void log_format(const char *file, int line, const char *func, const struct log_config *config, const char *subs, unsigned int sev, const char *format, ...) { va_list list; int saved_errno = errno; va_start(list, format); log_lock(); log__submit(file, line, func, config, subs, sev, format, list); log_unlock(); va_end(list); errno = saved_errno; }
void do_debug(LOG_LEVEL log_level, char *file_name, char *function, int line, char *fmt, ...) { va_list arg; char tmp[1024]; char buf[4096]; assert(log_arg->log_level != LOG_NOLEVEL); if (log_level > log_arg->log_level) return ; va_start(arg, fmt); vsprintf(tmp, fmt, arg); va_end(arg); snprintf(buf, sizeof(buf), "%s:%s(%d): %s", file_name, function, line, tmp); log_lock(); fprintf(stdout, "%s", buf); log_unlock(); }
void rollover_logfile(void) { if(to_syslog || !(log_fn[0])) return; { FILE *f = fopen(log_fn,"r"); if(!f) { fprintf(stderr, "log file is damaged\n"); reset_rtpprintf(); TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "log file reopened: %s\n", log_fn); return; } else { fclose(f); } } if(simple_log) return; log_lock(); if(_rtpfile && log_fn[0] && (_rtpfile != stdout)) { char logf[FILE_STR_LEN]; set_log_file_name(log_fn_base,logf); if(strcmp(log_fn,logf)) { fclose(_rtpfile); log_fn[0]=0; _rtpfile = fopen(logf, "w"); if(_rtpfile) { STRCPY(log_fn,logf); TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "log file opened: %s\n", log_fn); } else { _rtpfile = stdout; } } } log_unlock(); }
void log_rm_filter(int handle) { struct log_dynconf *dconf, *i; dconf = NULL; log_lock(); if (log__dconfig) { if (log__dconfig->handle == handle) { dconf = log__dconfig; log__dconfig = dconf->next; } else for (i = log__dconfig; i->next; i = i->next) { dconf = i->next; if (dconf->handle == handle) { i->next = dconf->next; break; } } } log_unlock(); free(dconf); }
void log_close(void) { log_lock(); fclose(log_arg->log_fp); log_unlock(); }
APIE process_fork(pid_t *pid) { sigset_t oldmask, newmask; struct sigaction action; int i; // block signals now, so that child process can safely disable caller's // signal handlers without a race sigfillset(&newmask); if (pthread_sigmask(SIG_SETMASK, &newmask, &oldmask) != 0) { log_error("Could not block signals: %s (%d)", get_errno_name(errno), errno); return API_E_INTERNAL_ERROR; } // ensure to hold the logging mutex, to protect child processes // from deadlocking on another thread's inherited mutex state log_lock(); *pid = fork(); // unlock for both parent and child process log_unlock(); if (*pid < 0) { // error pthread_sigmask(SIG_SETMASK, &oldmask, NULL); log_error("Could not fork child process: %s (%d)", get_errno_name(errno), errno); return API_E_INTERNAL_ERROR; } else if (*pid != 0) { // parent pthread_sigmask(SIG_SETMASK, &oldmask, NULL); return API_E_SUCCESS; } else { // child // reset all signal handlers from parent so nothing unexpected can // happen in the child once signals are unblocked action.sa_handler = SIG_DFL; action.sa_flags = 0; sigemptyset(&action.sa_mask); for (i = 1; i < NSIG; ++i) { sigaction(i, &action, NULL); } // unblock all signals in the child sigemptyset(&newmask); if (pthread_sigmask(SIG_SETMASK, &newmask, NULL) != 0) { log_error("Could not unblock signals: %s (%d)", get_errno_name(errno), errno); _exit(PROCESS_E_INTERNAL_ERROR); } return API_E_SUCCESS; } }
int log_init(char *log_path, int log_level, int log_size, int log_num) { char buff[1024]; char proc_name[64]; char pwd[1024]; if (log_level > LOG_NOLEVEL || log_size > MAX_LOG_SIZE || log_num > MAX_LOG_NUM) { printf("log argument error.\n"); return -1; } memset(proc_name, '\0', 64); if (get_process_name(proc_name) == -1) return -1; if (!getcwd(pwd, 1024)) return -1; log_arg = (LOG_ARG *)malloc(sizeof(LOG_ARG)); if (!log_arg) { fprintf(stderr, "Malloc failed.\n"); return -1; } log_arg->log_level = log_level; log_arg->log_file_num = log_num; log_arg->curr_log_num = 0; /* the kernel will write data into memory cache first, * using fstat to get the file size is not correctly, * To solove this case, it can wait the data until kernel * write them to the disk from memory cache, but in order to * improve the performance, we just raise the log_size:::-). */ log_arg->log_size = log_size * 1024 * 1024; snprintf(log_arg->log_path, 1024, "%s/%d", log_path, getpid()); pthread_mutex_init(&log_arg->log_lock, NULL); if (mkdir(log_arg->log_path, 0700) == -1) { perror("mkdir"); free(log_arg); return -1; } snprintf(buff, sizeof(buff), "%s/log.1", log_arg->log_path); strcpy(log_arg->curr_log, buff); log_lock(); log_arg->log_fp = fopen(buff, "w+"); if (!log_arg->log_fp) { perror("fopen"); log_unlock(); free(log_arg); return -1; } log_unlock(); return 0; }
void mqueue_start() { char message_buffer[MQUEUE_BUFFER_SIZE]; from_client = mq_open(MQUEUE_SERVER, O_RDONLY | O_EXCL | O_CREAT, S_IRUSR | S_IWUSR, NULL); to_client = mq_open(MQUEUE_CLIENT, O_WRONLY | O_EXCL | O_CREAT, S_IWUSR | S_IRUSR, NULL); if(from_client == -1 || to_client == -1) { log_error("Failed to open administration interface, mq_open failed"); master_stop(); } log_info("Apricot admin interface opened"); for(;;) { /* receive a message from the client administration interface */ if(mq_receive(from_client, message_buffer, MQUEUE_BUFFER_SIZE, NULL) == -1) { log_error("mq_receive failed : %s", strerror(errno)); continue; } /* process interface request */ if(!strcasecmp(message_buffer, MQUEUE_SEND_LOG)) { FILE * log_file = log_file = fopen(conf.log_file, "r"); if(!log_file) { strcpy(message_buffer, MQUEUE_FAIL); send(to_client, message_buffer); } else { while(fgets(message_buffer, MQUEUE_BUFFER_SIZE-1, log_file)) { send(to_client, message_buffer); } fclose(log_file); strcpy(message_buffer, MQUEUE_OK); send(to_client, message_buffer); } } else if(!strcasecmp(message_buffer, MQUEUE_TRUNCATE_LOG)) { /* to preserve log consistency */ log_lock(); truncate(conf.log_file, 0); log_unlock(); strcpy(message_buffer, MQUEUE_OK); send(to_client, message_buffer); } else if(!strcasecmp(message_buffer, MQUEUE_STOP_SERVER)) { log_info("Apricot stop asked by admin interface"); master_stop(); exit(EXIT_SUCCESS); } else if(!strcasecmp(message_buffer, MQUEUE_RESIZE_POOL)) { log_info("Pool resize asked by admin interface"); /* receive a message from the client administration interface */ if(mq_receive(from_client, message_buffer, MQUEUE_BUFFER_SIZE, NULL) == -1) { log_error("mq_receive failed to receive new pool size : %s", strerror(errno)); continue; } int new_size; if(sscanf(message_buffer, "%i", &new_size) != 1 || new_size <= 0) { log_error("invalid pool size %i received from admin interface", new_size); strcpy(message_buffer, MQUEUE_FAIL); send(to_client, message_buffer); continue; } pool_resize(new_size); strcpy(message_buffer, MQUEUE_OK); send(to_client, message_buffer); } else { strcpy(message_buffer, MQUEUE_FAIL); send(to_client, message_buffer); } } }