#include <syslog.h>
#include <time.h>
#include "dynamic-string.h"
+#include "sat-math.h"
#include "timeval.h"
#include "util.h"
/* Name for each logging level. */
static const char *level_names[VLL_N_LEVELS] = {
- [VLL_EMER] = "EMER",
- [VLL_ERR] = "ERR",
- [VLL_WARN] = "WARN",
- [VLL_DBG] = "DBG",
+#define VLOG_LEVEL(NAME) #NAME,
+ VLOG_LEVELS
+#undef VLOG_LEVEL
};
/* Name for each logging facility. */
static const char *facility_names[VLF_N_FACILITIES] = {
- [VLF_CONSOLE] = "console",
- [VLF_SYSLOG] = "syslog",
+#define VLOG_FACILITY(NAME) #NAME,
+ VLOG_FACILITIES
+#undef VLOG_FACILITY
};
/* Name for each logging module */
static const char *module_names[VLM_N_MODULES] = {
#define VLOG_MODULE(NAME) #NAME,
- VLOG_MODULES
-#undef VLOG_MODULES
+#include "vlog-modules.def"
};
static int levels[VLM_N_MODULES][VLF_N_FACILITIES];
if (arg) {
char *msg = vlog_set_levels_from_string(arg);
if (msg) {
- fatal(0, "processing \"%s\": %s", arg, msg);
+ ofp_fatal(0, "processing \"%s\": %s", arg, msg);
}
} else {
vlog_set_levels(VLM_ANY_MODULE, VLF_ANY_FACILITY, VLL_DBG);
*
* Guaranteed to preserve errno. */
void
-vlog(enum vlog_module module, enum vlog_level level, const char *message, ...)
+vlog_valist(enum vlog_module module, enum vlog_level level,
+ const char *message, va_list args)
{
bool log_console = levels[module][VLF_CONSOLE] >= level;
bool log_syslog = levels[module][VLF_SYSLOG] >= level;
const char *level_name = vlog_get_level_name(level);
time_t now;
struct tm tm;
- va_list args;
- char s[1024];
- size_t len, time_len;
+ size_t time_len;
+ struct ds s;
now = time_now();
localtime_r(&now, &tm);
- len = time_len = strftime(s, sizeof s, "%b %d %H:%M:%S|", &tm);
- len += sprintf(s + len, "%05d|%s|%s:",
- ++msg_num, module_name, level_name);
- va_start(args, message);
- len += vsnprintf(s + len, sizeof s - len, message, args);
- va_end(args);
- if (len >= sizeof s) {
- len = sizeof s;
- }
- if (s[len - 1] == '\n') {
- s[len - 1] = '\0';
- }
+ /* Compose log message. */
+ ds_init(&s);
+ ds_reserve(&s, 1024);
+ ds_put_strftime(&s, "%b %d %H:%M:%S|", &tm);
+ time_len = s.length;
+ ds_put_format(&s, "%05d|%s|%s:", ++msg_num, module_name, level_name);
+ ds_put_format_valist(&s, message, args);
+ ds_chomp(&s, '\n');
if (log_console) {
- fprintf(stderr, "%s\n", s);
+ fprintf(stderr, "%s\n", s.string);
}
if (log_syslog) {
- static const int syslog_levels[VLL_N_LEVELS] = {
- [VLL_EMER] = LOG_ALERT,
- [VLL_ERR] = LOG_ERR,
- [VLL_WARN] = LOG_WARNING,
- [VLL_DBG] = LOG_DEBUG,
- };
+ int syslog_level = LOG_ALERT;
char *save_ptr = NULL;
char *line;
- for (line = strtok_r(s + time_len, "\n", &save_ptr); line != NULL;
+ switch (level) {
+ case VLL_EMER: syslog_level = LOG_ALERT; break;
+ case VLL_ERR: syslog_level = LOG_ERR; break;
+ case VLL_WARN: syslog_level = LOG_WARNING; break;
+ case VLL_DBG: syslog_level = LOG_DEBUG; break;
+ case VLL_N_LEVELS: NOT_REACHED();
+ }
+ for (line = strtok_r(&s.string[time_len], "\n", &save_ptr); line;
line = strtok_r(NULL, "\n", &save_ptr)) {
- syslog(syslog_levels[level], "%s", line);
+ syslog(syslog_level, "%s", line);
}
}
+
+ ds_destroy(&s);
errno = save_errno;
}
}
+
+void
+vlog(enum vlog_module module, enum vlog_level level, const char *message, ...)
+{
+ va_list args;
+
+ va_start(args, message);
+ vlog_valist(module, level, message, args);
+ va_end(args);
+}
+
+void
+vlog_rate_limit(enum vlog_module module, enum vlog_level level,
+ struct vlog_rate_limit *rl, const char *message, ...)
+{
+ va_list args;
+
+ if (!vlog_is_enabled(module, level)) {
+ return;
+ }
+
+ if (rl->tokens < VLOG_MSG_TOKENS) {
+ time_t now = time_now();
+ if (rl->last_fill > now) {
+ /* Last filled in the future? Time must have gone backward, or
+ * 'rl' has not been used before. */
+ rl->tokens = rl->burst;
+ } else if (rl->last_fill < now) {
+ unsigned int add = sat_mul(rl->rate, now - rl->last_fill);
+ unsigned int tokens = sat_add(rl->tokens, add);
+ rl->tokens = MIN(tokens, rl->burst);
+ rl->last_fill = now;
+ }
+ if (rl->tokens < VLOG_MSG_TOKENS) {
+ if (!rl->n_dropped) {
+ rl->first_dropped = now;
+ }
+ rl->n_dropped++;
+ return;
+ }
+ }
+ rl->tokens -= VLOG_MSG_TOKENS;
+
+ va_start(args, message);
+ vlog_valist(module, level, message, args);
+ va_end(args);
+
+ if (rl->n_dropped) {
+ vlog(module, level,
+ "Dropped %u messages in last %u seconds due to excessive rate",
+ rl->n_dropped, (unsigned int) (time_now() - rl->first_dropped));
+ rl->n_dropped = 0;
+ }
+}