#include <time.h>
const char *failure_log_type_prefixes[LOG_TYPE_COUNT] = {
+ "Debug: ",
"Info: ",
"Warning: ",
"Error: ",
default_fatal_handler;
static failure_callback_t *error_handler = default_error_handler;
static failure_callback_t *info_handler = default_error_handler;
+static failure_callback_t *debug_handler = default_error_handler;
static void (*failure_exit_callback)(int *) = NULL;
-static int log_fd = STDERR_FILENO, log_info_fd = STDERR_FILENO;
+static int log_fd = STDERR_FILENO, log_info_fd = STDERR_FILENO,
+ log_debug_fd = STDERR_FILENO;
static char *log_prefix = NULL, *log_stamp_format = NULL;
static bool failure_ignore_errors = FALSE;
void default_error_handler(enum log_type type, const char *format, va_list args)
{
- int fd = type == LOG_TYPE_INFO ? log_info_fd : log_fd;
+ int fd;
+
+ switch (type) {
+ case LOG_TYPE_DEBUG:
+ fd = log_debug_fd;
+ break;
+ case LOG_TYPE_INFO:
+ fd = log_info_fd;
+ break;
+ default:
+ fd = log_fd;
+ }
if (default_handler(failure_log_type_prefixes[type],
fd, format, args) < 0) {
if (fd == log_fd)
failure_exit(FATAL_LOGWRITE);
- /* we failed to log to info log, try to log the write error
- to error log - maybe that'll work. */
- i_fatal_status(FATAL_LOGWRITE,
- "write() failed to info log: %m");
+ /* we failed to log to info/debug log, try to log the
+ write error to error log - maybe that'll work. */
+ i_fatal_status(FATAL_LOGWRITE, "write() failed to %s log: %m",
+ fd == log_info_fd ? "info" : "debug");
}
}
va_start(args, format);
- if (type == LOG_TYPE_INFO)
+ switch (type) {
+ case LOG_TYPE_DEBUG:
+ debug_handler(type, format, args);
+ break;
+ case LOG_TYPE_INFO:
info_handler(type, format, args);
- else
+ break;
+ default:
error_handler(type, format, args);
+ }
+
va_end(args);
}
errno = old_errno;
}
+void i_debug(const char *format, ...)
+{
+ int old_errno = errno;
+ va_list args;
+
+ va_start(args, format);
+ debug_handler(LOG_TYPE_DEBUG, format, args);
+ va_end(args);
+
+ errno = old_errno;
+}
+
void i_set_fatal_handler(fatal_failure_callback_t *callback ATTR_NORETURN)
{
if (callback == NULL)
info_handler = callback;
}
+void i_set_debug_handler(failure_callback_t *callback)
+{
+ if (callback == NULL)
+ callback = default_error_handler;
+ debug_handler = callback;
+}
+
void i_get_failure_handlers(fatal_failure_callback_t **fatal_callback_r,
failure_callback_t **error_callback_r,
- failure_callback_t **info_callback_r)
+ failure_callback_t **info_callback_r,
+ failure_callback_t **debug_callback_r)
{
*fatal_callback_r = fatal_handler;
*error_callback_r = error_handler;
*info_callback_r = info_handler;
+ *debug_callback_r = debug_handler;
}
static int ATTR_FORMAT(3, 0)
int level = LOG_ERR;
switch (type) {
+ case LOG_TYPE_DEBUG:
+ level = LOG_DEBUG;
+ break;
case LOG_TYPE_INFO:
level = LOG_INFO;
break;
i_set_fatal_handler(i_syslog_fatal_handler);
i_set_error_handler(i_syslog_error_handler);
i_set_info_handler(i_syslog_error_handler);
+ i_set_debug_handler(i_syslog_error_handler);
}
static void open_log_file(int *fd, const char *path)
i_error("close(%d) failed: %m", log_info_fd);
}
+ if (log_debug_fd != STDERR_FILENO && log_debug_fd != log_info_fd &&
+ log_debug_fd != log_fd) {
+ if (close(log_debug_fd) < 0)
+ i_error("close(%d) failed: %m", log_debug_fd);
+ }
+
open_log_file(&log_fd, path);
+ /* if info/debug logs are elsewhere, i_set_info/debug_file()
+ overrides these later. */
log_info_fd = log_fd;
+ log_debug_fd = log_fd;
i_set_fatal_handler(NULL);
i_set_error_handler(NULL);
i_set_info_handler(NULL);
+ i_set_debug_handler(NULL);
}
static void i_failure_send_option(const char *key, const char *value)
i_set_fatal_handler(i_internal_fatal_handler);
i_set_error_handler(i_internal_error_handler);
i_set_info_handler(i_internal_error_handler);
+ i_set_debug_handler(i_internal_error_handler);
}
void i_set_failure_ignore_errors(bool ignore)
open_log_file(&log_info_fd, path);
info_handler = default_error_handler;
+ /* write debug-level messages to the info_log_path,
+ until i_set_debug_file() was called */
+ log_debug_fd = log_info_fd;
+ i_set_debug_handler(NULL);
+}
+
+void i_set_debug_file(const char *path)
+{
+ if (log_debug_fd == log_fd || log_debug_fd == log_info_fd)
+ log_debug_fd = STDERR_FILENO;
+
+ open_log_file(&log_debug_fd, path);
+ debug_handler = default_error_handler;
}
void i_set_failure_timestamp_format(const char *fmt)
void failures_deinit(void)
{
+ if (log_debug_fd == log_info_fd || log_debug_fd == log_fd)
+ log_debug_fd = STDERR_FILENO;
+
if (log_info_fd == log_fd)
log_info_fd = STDERR_FILENO;
log_info_fd = STDERR_FILENO;
}
+ if (log_debug_fd != STDERR_FILENO) {
+ (void)close(log_debug_fd);
+ log_debug_fd = STDERR_FILENO;
+ }
+
i_free_and_null(log_prefix);
i_free_and_null(log_stamp_format);
}
};
enum log_type {
+ LOG_TYPE_DEBUG,
LOG_TYPE_INFO,
LOG_TYPE_WARNING,
LOG_TYPE_ERROR,
void i_error(const char *format, ...) ATTR_FORMAT(1, 2) ATTR_COLD;
void i_warning(const char *format, ...) ATTR_FORMAT(1, 2);
void i_info(const char *format, ...) ATTR_FORMAT(1, 2);
+void i_debug(const char *format, ...) ATTR_FORMAT(1, 2);
void i_fatal_status(int status, const char *format, ...)
ATTR_FORMAT(2, 3) ATTR_NORETURN ATTR_COLD;
#endif
void i_set_error_handler(failure_callback_t *callback);
void i_set_info_handler(failure_callback_t *callback);
+void i_set_debug_handler(failure_callback_t *callback);
void i_get_failure_handlers(fatal_failure_callback_t **fatal_callback_r,
failure_callback_t **error_callback_r,
- failure_callback_t **info_callback_r);
+ failure_callback_t **info_callback_r,
+ failure_callback_t **debug_callback_r);
/* Send failures to file. */
void default_fatal_handler(enum log_type type, int status,
void i_syslog_error_handler(enum log_type type, const char *fmt, va_list args)
ATTR_FORMAT(2, 0);
-/* Open syslog and set failure/info handlers to use it. */
+/* Open syslog and set failure/info/debug handlers to use it. */
void i_set_failure_syslog(const char *ident, int options, int facility);
/* Send failures to specified log file instead of stderr. */
functions modify the info file too, so call this function after them. */
void i_set_info_file(const char *path);
+/* Send debug-level message to the given log file. The i_set_info_file()
+ function modifies also the debug log file, so call this function after it. */
+void i_set_debug_file(const char *path);
+
/* Set the failure prefix. */
void i_set_failure_prefix(const char *prefix);
/* Prefix failures with a timestamp. fmt is in strftime() format. */
if (log_error) {
fprintf(stderr, "Writing to error logs and killing myself..\n");
+ i_debug("This is Dovecot's debug log");
i_info("This is Dovecot's info log");
i_warning("This is Dovecot's warning log");
i_error("This is Dovecot's error log");
struct master_settings *set;
unsigned int child_process_env_idx = 0;
const char *getopt_str, *error, *env_tz, *doveconf_arg = NULL;
- failure_callback_t *orig_info_callback;
+ failure_callback_t *orig_info_callback, *orig_debug_callback;
void **sets;
bool foreground = FALSE, ask_key_pass = FALSE, log_error = FALSE;
int c, send_signal = 0;
master_service_init_log(master_service, "master: ");
i_get_failure_handlers(&orig_fatal_callback, &orig_error_callback,
- &orig_info_callback);
+ &orig_info_callback, &orig_debug_callback);
i_set_fatal_handler(startup_fatal_handler);
i_set_error_handler(startup_error_handler);