#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;
}
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;
+ 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);
}
}
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;
+ }
+}