/* ------------------------------------------------------------------------- make_log_entry has 1 main flaws: The message in its entirity, must fit into the tempbuffer. So it must be shorter than MAXLOGSIZE ------------------------------------------------------------------------- */ void make_log_entry(enum loglevels loglevel, enum logtypes logtype, const char *file, int line, char *message, ...) { /* fn is not reentrant but is used in signal handler * with LOGGER it's a little late source name and line number * are already changed. */ static int inlog = 0; int i, j; int fd, len; char temp_buffer[MAXLOGSIZE]; char log_details_buffer[MAXLOGSIZE]; va_list args; struct iovec iov[2]; if (inlog) return; inlog = 1; if (!log_config.inited) { log_init(); } if (type_configs[logtype].syslog) { if (type_configs[logtype].level >= loglevel) { /* Initialise the Messages and send it to syslog */ va_start(args, message); vsnprintf(temp_buffer, MAXLOGSIZE -1, message, args); va_end(args); temp_buffer[MAXLOGSIZE -1] = 0; make_syslog_entry(loglevel, logtype, temp_buffer); } inlog = 0; return; } /* logging to a file */ log_src_filename = file; log_src_linenumber = line; /* Check if requested logtype is setup */ if (type_configs[logtype].set) /* Yes */ fd = type_configs[logtype].fd; else /* No: use default */ fd = type_configs[logtype_default].fd; if (fd < 0) { /* no where to send the output, give up */ goto exit; } /* Initialise the Messages */ va_start(args, message); len = vsnprintf(temp_buffer, MAXLOGSIZE -1, message, args); va_end(args); /* Append \n */ if (len ==-1 || len >= MAXLOGSIZE -1) { /* vsnprintf hit the buffer size*/ temp_buffer[MAXLOGSIZE-2] = '\n'; temp_buffer[MAXLOGSIZE-1] = 0; } else { temp_buffer[len] = '\n'; temp_buffer[len+1] = 0; } if (type_configs[logtype].level >= log_debug) goto log; /* bypass flooding checks */ goto log; /* Prevent flooding: hash the message and check if we got the same one recently */ int hash = hash_message(temp_buffer) + log_src_linenumber; /* Search for the same message by hash */ for (i = log_flood_entries - 1; i >= 0; i--) { if (log_flood_array[i].hash == hash) { /* found same message */ log_flood_array[i].count++; /* Check if that message has reached LOG_FLOODING_MAXCOUNT */ if (log_flood_array[i].count >= LOG_FLOODING_MAXCOUNT) { /* yes, log it and remove from array */ /* reusing log_details_buffer */ sprintf(log_details_buffer, "message repeated %i times\n", LOG_FLOODING_MAXCOUNT - 1); write(fd, log_details_buffer, strlen(log_details_buffer)); if ((i + 1) == LOG_FLOODING_ARRAY_SIZE) { /* last array element, just decrement count */ log_flood_entries--; goto exit; } /* move array elements down */ for (j = i + 1; j != LOG_FLOODING_ARRAY_SIZE ; j++) log_flood_array[j-1] = log_flood_array[j]; log_flood_entries--; } if (log_flood_array[i].count < LOG_FLOODING_MINCOUNT) /* log it */ goto log; /* discard it */ goto exit; } /* if */ } /* for */ /* No matching message found, add this message to array*/ if (log_flood_entries == LOG_FLOODING_ARRAY_SIZE) { /* array is full, discard oldest entry printing "message repeated..." if count > 1 */ if (log_flood_array[0].count >= LOG_FLOODING_MINCOUNT) { /* reusing log_details_buffer */ sprintf(log_details_buffer, "message repeated %i times\n", log_flood_array[0].count - LOG_FLOODING_MINCOUNT + 1); write(fd, log_details_buffer, strlen(log_details_buffer)); } for (i = 1; i < LOG_FLOODING_ARRAY_SIZE; i++) { log_flood_array[i-1] = log_flood_array[i]; } log_flood_entries--; } log_flood_array[log_flood_entries].count = 1; log_flood_array[log_flood_entries].hash = hash; log_flood_entries++; log: if ( ! log_config.console) { generate_message_details(log_details_buffer, sizeof(log_details_buffer), type_configs[logtype].set ? type_configs[logtype].display_options : type_configs[logtype_default].display_options, loglevel, logtype); /* If default wasnt setup its fd is -1 */ iov[0].iov_base = log_details_buffer; iov[0].iov_len = strlen(log_details_buffer); iov[1].iov_base = temp_buffer; iov[1].iov_len = strlen(temp_buffer); writev( fd, iov, 2); } else { write(fd, temp_buffer, strlen(temp_buffer)); } exit: inlog = 0; }
/* ------------------------------------------------------------------------- make_log_entry has 1 main flaws: The message in its entirity, must fit into the tempbuffer. So it must be shorter than MAXLOGSIZE ------------------------------------------------------------------------- */ void make_log_entry(enum loglevels loglevel, enum logtypes logtype, const char *file, int line, char *message, ...) { /* fn is not reentrant but is used in signal handler * with LOGGER it's a little late source name and line number * are already changed. */ static int inlog = 0; int fd, len; char *user_message, *log_message; va_list args; if (inlog) return; inlog = 1; if (!log_config.inited) { log_init(); } if (type_configs[logtype].syslog) { if (type_configs[logtype].level >= loglevel) { /* Initialise the Messages and send it to syslog */ va_start(args, message); len = vasprintf(&user_message, message, args); va_end(args); if (len == -1) { return; } make_syslog_entry(loglevel, logtype, user_message); free(user_message); } inlog = 0; return; } /* logging to a file */ log_src_filename = file; log_src_linenumber = line; /* Check if requested logtype is setup */ if (type_configs[logtype].set) { /* Yes */ fd = type_configs[logtype].fd; } else { /* No: use default */ fd = type_configs[logtype_default].fd; } if (fd < 0) { /* no where to send the output, give up */ goto exit; } /* Initialise the Messages */ va_start(args, message); len = vasprintf(&user_message, message, args); if (len == -1) { goto exit; } va_end(args); len = generate_message(&log_message, user_message, type_configs[logtype].set ? type_configs[logtype].display_options : type_configs[logtype_default].display_options, loglevel, logtype); if (len == -1) { goto exit; } write(fd, log_message, len); free(log_message); free(user_message); exit: inlog = 0; }