{
/* set up default stdout file_logger */
file_logger = file_logger_create(stdout, NULL, FALSE);
- charon->bus->add_logger(charon->bus, &file_logger->logger);
charon->file_loggers->insert_last(charon->file_loggers, file_logger);
/* set up default daemon sys_logger */
sys_logger = sys_logger_create(LOG_DAEMON, FALSE);
- charon->bus->add_logger(charon->bus, &sys_logger->logger);
charon->sys_loggers->insert_last(charon->sys_loggers, sys_logger);
for (group = 0; group < DBG_MAX; group++)
{
file_logger->set_level(file_logger, group, levels[group]);
}
}
+ charon->bus->add_logger(charon->bus, &file_logger->logger);
+ charon->bus->add_logger(charon->bus, &sys_logger->logger);
/* set up default auth sys_logger */
sys_logger = sys_logger_create(LOG_AUTHPRIV, FALSE);
- charon->bus->add_logger(charon->bus, &sys_logger->logger);
- charon->sys_loggers->insert_last(charon->sys_loggers, sys_logger);
sys_logger->set_level(sys_logger, DBG_ANY, LEVEL_AUDIT);
+ charon->sys_loggers->insert_last(charon->sys_loggers, sys_logger);
+ charon->bus->add_logger(charon->bus, &sys_logger->logger);
}
}
linked_list_t *listeners;
/**
- * List of registered loggers.
+ * List of registered loggers for each log group as log_entry_t.
+ * Loggers are ordered by descending log level.
+ * The extra list stores all loggers so we can properly unregister them.
*/
- linked_list_t *loggers;
+ linked_list_t *loggers[DBG_MAX + 1];
+
+ /**
+ * Maximum log level of any registered logger for each log group.
+ * This allows to check quickly if a log message has to be logged at all.
+ */
+ level_t max_level[DBG_MAX + 1];
/**
* Mutex for the list of listeners, recursively.
};
+typedef struct log_entry_t log_entry_t;
+
+/**
+ * a logger entry
+ */
+struct log_entry_t {
+
+ /**
+ * registered logger interface
+ */
+ logger_t *logger;
+
+ /**
+ * registered log levels per group
+ */
+ level_t levels[DBG_MAX];
+
+};
+
METHOD(bus_t, add_listener, void,
private_bus_t *this, listener_t *listener)
{
this->mutex->unlock(this->mutex);
}
+/**
+ * Register a logger on the given log group according to the requested level
+ */
+static inline void register_logger(private_bus_t *this, debug_t group,
+ log_entry_t *entry)
+{
+ enumerator_t *enumerator;
+ linked_list_t *loggers;
+ log_entry_t *current;
+ level_t level;
+
+ loggers = this->loggers[group];
+ level = entry->levels[group];
+
+ enumerator = loggers->create_enumerator(loggers);
+ while (enumerator->enumerate(enumerator, (void**)¤t))
+ {
+ if (current->levels[group] <= level)
+ {
+ break;
+ }
+ }
+ loggers->insert_before(loggers, enumerator, entry);
+ enumerator->destroy(enumerator);
+
+ this->max_level[group] = max(this->max_level[group], level);
+}
+
+/**
+ * Unregister a logger from all log groups (destroys the log_entry_t)
+ */
+static inline void unregister_logger(private_bus_t *this, logger_t *logger)
+{
+ enumerator_t *enumerator;
+ linked_list_t *loggers;
+ log_entry_t *entry, *found = NULL;
+
+ loggers = this->loggers[DBG_MAX];
+ enumerator = loggers->create_enumerator(loggers);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->logger == logger)
+ {
+ loggers->remove_at(loggers, enumerator);
+ found = entry;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (found)
+ {
+ debug_t group;
+ for (group = 0; group < DBG_MAX; group++)
+ {
+ if (found->levels[group] > LEVEL_SILENT)
+ {
+ loggers = this->loggers[group];
+ loggers->remove(loggers, found, NULL);
+
+ this->max_level[group] = LEVEL_SILENT;
+ if (loggers->get_first(loggers, (void**)&entry) == SUCCESS)
+ {
+ this->max_level[group] = entry->levels[group];
+ }
+ }
+ }
+ free(found);
+ }
+}
+
METHOD(bus_t, add_logger, void,
private_bus_t *this, logger_t *logger)
{
+ log_entry_t *entry;
+ debug_t group;
+
+ INIT(entry,
+ .logger = logger,
+ );
+
this->log_lock->write_lock(this->log_lock);
- this->loggers->insert_last(this->loggers, logger);
+ unregister_logger(this, logger);
+ for (group = 0; group < DBG_MAX; group++)
+ {
+ entry->levels[group] = logger->get_level(logger, group);
+ if (entry->levels[group] > LEVEL_SILENT)
+ {
+ register_logger(this, group, entry);
+ }
+ }
+ this->loggers[DBG_MAX]->insert_last(this->loggers[DBG_MAX], entry);
this->log_lock->unlock(this->log_lock);
}
private_bus_t *this, logger_t *logger)
{
this->log_lock->write_lock(this->log_lock);
- this->loggers->remove(this->loggers, logger, NULL);
+ unregister_logger(this, logger);
this->log_lock->unlock(this->log_lock);
}
debug_t group;
/** debug level */
level_t level;
- /** format string */
- char *format;
- /** argument list */
- va_list args;
+ /** message */
+ char message[8192];
} log_data_t;
/**
* logger->log() invocation as a invoke_function callback
*/
-static void log_cb(logger_t *logger, log_data_t *data)
+static void log_cb(log_entry_t *entry, log_data_t *data)
{
- va_list args;
-
- va_copy(args, data->args);
- logger->log(logger, data->group, data->level, data->thread, data->ike_sa,
- data->format, args);
- va_end(args);
+ if (entry->levels[data->group] < data->level)
+ {
+ return;
+ }
+ entry->logger->log(entry->logger, data->group, data->level,
+ data->thread, data->ike_sa, data->message);
}
METHOD(bus_t, vlog, void,
private_bus_t *this, debug_t group, level_t level,
char* format, va_list args)
{
- log_data_t data;
-
- data.ike_sa = this->thread_sa->get(this->thread_sa);
- data.thread = thread_current_id();
- data.group = group;
- data.level = level;
- data.format = format;
- va_copy(data.args, args);
-
this->log_lock->read_lock(this->log_lock);
- this->loggers->invoke_function(this->loggers, (void*)log_cb, &data);
+ if (this->max_level[group] >= level)
+ {
+ linked_list_t *loggers = this->loggers[group];
+ log_data_t data;
+
+ data.ike_sa = this->thread_sa->get(this->thread_sa);
+ data.thread = thread_current_id();
+ data.group = group;
+ data.level = level;
+ vsnprintf(data.message, sizeof(data.message), format, args);
+ loggers->invoke_function(loggers, (linked_list_invoke_t)log_cb, &data);
+ }
this->log_lock->unlock(this->log_lock);
-
- va_end(data.args);
}
METHOD(bus_t, log_, void,
METHOD(bus_t, destroy, void,
private_bus_t *this)
{
+ debug_t group;
+ for (group = 0; group < DBG_MAX; group++)
+ {
+ this->loggers[group]->destroy(this->loggers[group]);
+ }
+ this->loggers[DBG_MAX]->destroy_function(this->loggers[DBG_MAX],
+ (void*)free);
this->listeners->destroy_function(this->listeners, (void*)free);
- this->loggers->destroy(this->loggers);
this->thread_sa->destroy(this->thread_sa);
this->log_lock->destroy(this->log_lock);
this->mutex->destroy(this->mutex);
bus_t *bus_create()
{
private_bus_t *this;
+ debug_t group;
INIT(this,
.public = {
.destroy = _destroy,
},
.listeners = linked_list_create(),
- .loggers = linked_list_create(),
.mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
.log_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
.thread_sa = thread_value_create(NULL),
);
+ for (group = 0; group <= DBG_MAX; group++)
+ {
+ this->loggers[group] = linked_list_create();
+ this->max_level[group] = LEVEL_SILENT;
+ }
+
return &this->public;
}
* by multiple threads. Recursive calls are not prevented, so logger that
* may cause recursive calls are responsible to avoid infinite loops.
*
+ * During registration get_level() is called for all log groups and the
+ * logger is registered to receive log messages for groups for which
+ * the requested log level is > LEVEL_SILENT and whose level is lower
+ * or equal than the requested level.
+ *
+ * To update the registered log levels call add_logger again with the
+ * same logger and return the new levels from get_level().
+ *
* @param logger logger to register.
*/
void (*add_logger) (bus_t *this, logger_t *logger);
METHOD(logger_t, log_, void,
private_file_logger_t *this, debug_t group, level_t level, int thread,
- ike_sa_t* ike_sa, char *format, va_list args)
+ ike_sa_t* ike_sa, char *message)
{
- if (level <= this->levels[group])
- {
- char buffer[8192], timestr[128], namestr[128] = "";
- char *current = buffer, *next;
- struct tm tm;
- time_t t;
+ char timestr[128], namestr[128] = "";
+ char *current = message, *next;
+ struct tm tm;
+ time_t t;
- if (this->time_format)
- {
- t = time(NULL);
- localtime_r(&t, &tm);
- strftime(timestr, sizeof(timestr), this->time_format, &tm);
- }
- if (this->ike_name && ike_sa)
+ if (this->time_format)
+ {
+ t = time(NULL);
+ localtime_r(&t, &tm);
+ strftime(timestr, sizeof(timestr), this->time_format, &tm);
+ }
+ if (this->ike_name && ike_sa)
+ {
+ if (ike_sa->get_peer_cfg(ike_sa))
{
- if (ike_sa->get_peer_cfg(ike_sa))
- {
- snprintf(namestr, sizeof(namestr), " <%s|%d>",
- ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
- }
- else
- {
- snprintf(namestr, sizeof(namestr), " <%d>",
- ike_sa->get_unique_id(ike_sa));
- }
+ snprintf(namestr, sizeof(namestr), " <%s|%d>",
+ ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
}
else
{
- namestr[0] = '\0';
+ snprintf(namestr, sizeof(namestr), " <%d>",
+ ike_sa->get_unique_id(ike_sa));
}
+ }
+ else
+ {
+ namestr[0] = '\0';
+ }
- /* write in memory buffer first */
- vsnprintf(buffer, sizeof(buffer), format, args);
-
- /* prepend a prefix in front of every line */
- this->mutex->lock(this->mutex);
- while (current)
+ /* prepend a prefix in front of every line */
+ this->mutex->lock(this->mutex);
+ while (current)
+ {
+ next = strchr(current, '\n');
+ if (next)
+ {
+ *(next++) = '\0';
+ }
+ if (this->time_format)
{
- next = strchr(current, '\n');
- if (next)
- {
- *(next++) = '\0';
- }
- if (this->time_format)
- {
- fprintf(this->out, "%s %.2d[%N]%s %s\n",
- timestr, thread, debug_names, group, namestr, current);
- }
- else
- {
- fprintf(this->out, "%.2d[%N]%s %s\n",
- thread, debug_names, group, namestr, current);
- }
- current = next;
+ fprintf(this->out, "%s %.2d[%N]%s %s\n",
+ timestr, thread, debug_names, group, namestr, current);
}
- this->mutex->unlock(this->mutex);
+ else
+ {
+ fprintf(this->out, "%.2d[%N]%s %s\n",
+ thread, debug_names, group, namestr, current);
+ }
+ current = next;
}
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(logger_t, get_level, level_t,
+ private_file_logger_t *this, debug_t group)
+{
+ return this->levels[group];
}
METHOD(file_logger_t, set_level, void,
.public = {
.logger = {
.log = _log_,
+ .get_level = _get_level,
},
.set_level = _set_level,
.destroy = _destroy,
/**
* Log a debugging message.
*
- * @note Calls to bus_t.log() are handled seperately from calls to
- * other functions. This callback may be called concurrently by
- * multiple threads. Also recurisve calls are not prevented, logger that
- * may cause recursive calls are responsible to avoid infinite loops.
+ * @note Calls to bus_t.log() are handled separately from calls to
+ * other functions. This callback may be called concurrently by
+ * multiple threads. Also recursive calls are not prevented, loggers that
+ * may cause recursive log messages are responsible to avoid infinite loops.
*
* @param group kind of the signal (up, down, rekeyed, ...)
* @param level verbosity level of the signal
* @param thread ID of the thread raised this signal
* @param ike_sa IKE_SA associated to the event
- * @param format printf() style format string
- * @param args vprintf() style argument list
+ * @param message log message
*/
void (*log)(logger_t *this, debug_t group, level_t level, int thread,
- ike_sa_t *ike_sa, char* format, va_list args);
+ ike_sa_t *ike_sa, char* message);
+ /**
+ * Get the desired log level for a debug group. This is called during
+ * registration.
+ *
+ * If the desired log levels have changed, re-register the logger with
+ * the bus.
+ *
+ * @param group debug group
+ * @return max level to log (0..4) or -1 for none (see debug.h)
+ */
+ level_t (*get_level)(logger_t *this, debug_t group);
};
#endif /** LOGGER_H_ @}*/
METHOD(logger_t, log_, void,
private_sys_logger_t *this, debug_t group, level_t level, int thread,
- ike_sa_t* ike_sa, char *format, va_list args)
+ ike_sa_t* ike_sa, char *message)
{
- if (level <= this->levels[group])
- {
- char buffer[8192], groupstr[4], namestr[128] = "";
- char *current = buffer, *next;
+ char groupstr[4], namestr[128] = "";
+ char *current = message, *next;
- /* write in memory buffer first */
- vsnprintf(buffer, sizeof(buffer), format, args);
- /* cache group name and optional name string */
- snprintf(groupstr, sizeof(groupstr), "%N", debug_names, group);
+ /* cache group name and optional name string */
+ snprintf(groupstr, sizeof(groupstr), "%N", debug_names, group);
- if (this->ike_name && ike_sa)
+ if (this->ike_name && ike_sa)
+ {
+ if (ike_sa->get_peer_cfg(ike_sa))
{
- if (ike_sa->get_peer_cfg(ike_sa))
- {
- snprintf(namestr, sizeof(namestr), " <%s|%d>",
- ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
- }
- else
- {
- snprintf(namestr, sizeof(namestr), " <%d>",
- ike_sa->get_unique_id(ike_sa));
- }
+ snprintf(namestr, sizeof(namestr), " <%s|%d>",
+ ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
}
+ else
+ {
+ snprintf(namestr, sizeof(namestr), " <%d>",
+ ike_sa->get_unique_id(ike_sa));
+ }
+ }
- /* do a syslog for every line */
- this->mutex->lock(this->mutex);
- while (current)
+ /* do a syslog for every line */
+ this->mutex->lock(this->mutex);
+ while (current)
+ {
+ next = strchr(current, '\n');
+ if (next)
{
- next = strchr(current, '\n');
- if (next)
- {
- *(next++) = '\0';
- }
- syslog(this->facility|LOG_INFO, "%.2d[%s]%s %s\n",
- thread, groupstr, namestr, current);
- current = next;
+ *(next++) = '\0';
}
- this->mutex->unlock(this->mutex);
+ syslog(this->facility|LOG_INFO, "%.2d[%s]%s %s\n",
+ thread, groupstr, namestr, current);
+ current = next;
}
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(logger_t, get_level, level_t,
+ private_sys_logger_t *this, debug_t group)
+{
+ return this->levels[group];
}
METHOD(sys_logger_t, set_level, void,
.public = {
.logger = {
.log = _log_,
+ .get_level = _get_level,
},
.set_level = _set_level,
.destroy = _destroy,
/*
- * Copyright (C) 2011 Tobias Brunner
+ * Copyright (C) 2011-2012 Tobias Brunner
* Copyright (C) 2007-2011 Martin Willi
* Copyright (C) 2011 revosec AG
* Hochschule fuer Technik Rapperswil
METHOD(logger_t, listener_log, void,
interface_logger_t *this, debug_t group, level_t level, int thread,
- ike_sa_t *ike_sa, char* format, va_list args)
+ ike_sa_t *ike_sa, char* message)
{
if (this->listener->ike_sa == ike_sa)
{
- if (!this->callback(this->param, group, level, ike_sa, format, args))
+ if (!this->callback(this->param, group, level, ike_sa, message))
{
this->listener->status = NEED_MORE;
listener_done(this->listener);
}
}
+METHOD(logger_t, listener_get_level, level_t,
+ interface_logger_t *this, debug_t group)
+{
+ /* in order to allow callback listeners to decide what they want to log
+ * we request any log message, but only if we actually want logging */
+ return this->callback == controller_cb_empty ? LEVEL_SILENT : LEVEL_PRIVATE;
+}
+
METHOD(job_t, get_priority_medium, job_priority_t,
job_t *this)
{
.logger = {
.public = {
.log = _listener_log,
+ .get_level = _listener_get_level,
},
.callback = callback,
.param = param,
.logger = {
.public = {
.log = _listener_log,
+ .get_level = _listener_get_level,
},
.callback = callback,
.param = param,
.logger = {
.public = {
.log = _listener_log,
+ .get_level = _listener_get_level,
},
.callback = callback,
.param = param,
* See header
*/
bool controller_cb_empty(void *param, debug_t group, level_t level,
- ike_sa_t *ike_sa, char *format, va_list args)
+ ike_sa_t *ike_sa, char *message)
{
return TRUE;
}
#include <bus/bus.h>
/**
- * callback to log things triggered by controller.
+ * Callback to log things triggered by controller.
*
- * @param param echoed parameter supplied when function invoked
+ * @param param parameter supplied when controller method was called
* @param group debugging group
- * @param level verbosity level if log
+ * @param level verbosity level
* @param ike_sa associated IKE_SA, if any
- * @param format printf like format string
- * @param args list of arguments to use for format
- * @return FALSE to return from invoked function
+ * @param message log message
+ * @return FALSE to return from called controller method
*/
typedef bool (*controller_cb_t)(void* param, debug_t group, level_t level,
- ike_sa_t* ike_sa, char* format, va_list args);
+ ike_sa_t* ike_sa, char* message);
/**
- * Empty callback function for controller_t functions.
+ * Empty callback function for controller_t methods.
*
* If you want to do a synchronous call, but don't need a callback, pass
- * this function to the controllers methods.
+ * this function to the controller methods.
*/
bool controller_cb_empty(void *param, debug_t group, level_t level,
- ike_sa_t *ike_sa, char *format, va_list args);
+ ike_sa_t *ike_sa, char *message);
typedef struct controller_t controller_t;
METHOD(logger_t, log_, void,
- private_android_logger_t *this, debug_t group, level_t level,
- int thread, ike_sa_t* ike_sa, char *format, va_list args)
+ private_android_logger_t *this, debug_t group, level_t level,
+ int thread, ike_sa_t* ike_sa, char *message)
{
- if (level <= this->level)
- {
- int prio = level > 1 ? ANDROID_LOG_DEBUG : ANDROID_LOG_INFO;
- char sgroup[16], buffer[8192];
- char *current = buffer, *next;
- snprintf(sgroup, sizeof(sgroup), "%N", debug_names, group);
- vsnprintf(buffer, sizeof(buffer), format, args);
- this->mutex->lock(this->mutex);
- while (current)
- { /* log each line separately */
- next = strchr(current, '\n');
- if (next)
- {
- *(next++) = '\0';
- }
- __android_log_print(prio, "charon", "%.2d[%s] %s\n",
- thread, sgroup, current);
- current = next;
+ int prio = level > 1 ? ANDROID_LOG_DEBUG : ANDROID_LOG_INFO;
+ char sgroup[16];
+ char *current = message, *next;
+ snprintf(sgroup, sizeof(sgroup), "%N", debug_names, group);
+ this->mutex->lock(this->mutex);
+ while (current)
+ { /* log each line separately */
+ next = strchr(current, '\n');
+ if (next)
+ {
+ *(next++) = '\0';
}
- this->mutex->unlock(this->mutex);
+ __android_log_print(prio, "charon", "%.2d[%s] %s\n",
+ thread, sgroup, current);
+ current = next;
}
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(logger_t, get_level, level_t,
+ private_android_logger_t *this, debug_t group)
+{
+ return this->level;
}
METHOD(android_logger_t, destroy, void,
- private_android_logger_t *this)
+ private_android_logger_t *this)
{
this->mutex->destroy(this->mutex);
free(this);
.public = {
.logger = {
.log = _log_,
+ .get_level = _get_level,
},
.destroy = _destroy,
},
* callback which logs to a XML writer
*/
static bool xml_callback(xmlTextWriterPtr writer, debug_t group, level_t level,
- ike_sa_t* ike_sa, char* format, va_list args)
+ ike_sa_t* ike_sa, char* message)
{
if (level <= 1)
{
xmlTextWriterWriteFormatAttribute(writer, "level", "%d", level);
xmlTextWriterWriteFormatAttribute(writer, "source", "%N", debug_names, group);
xmlTextWriterWriteFormatAttribute(writer, "thread", "%u", thread_current_id());
- xmlTextWriterWriteVFormatString(writer, format, args);
+ xmlTextWriterWriteString(writer, message);
xmlTextWriterEndElement(writer);
/* </item> */
}
METHOD(logger_t, log_, void,
private_sql_logger_t *this, debug_t group, level_t level, int thread,
- ike_sa_t* ike_sa, char *format, va_list args)
+ ike_sa_t* ike_sa, char *message)
{
if (this->recursive->get(this->recursive))
{
}
this->recursive->set(this->recursive, this->recursive);
- if (ike_sa && level <= this->level)
+ if (ike_sa)
{
- char buffer[8192];
chunk_t local_spi, remote_spi;
host_t *local_host, *remote_host;
identification_t *local_id, *remote_id;
local_host = ike_sa->get_my_host(ike_sa);
remote_host = ike_sa->get_other_host(ike_sa);
- vsnprintf(buffer, sizeof(buffer), format, args);
-
this->db->execute(this->db, NULL, "REPLACE INTO ike_sas ("
"local_spi, remote_spi, id, initiator, "
"local_id_type, local_id_data, "
this->db->execute(this->db, NULL, "INSERT INTO logs ("
"local_spi, signal, level, msg) VALUES (?, ?, ?, ?)",
DB_BLOB, local_spi, DB_INT, group, DB_INT, level,
- DB_TEXT, buffer);
+ DB_TEXT, message);
}
+
this->recursive->set(this->recursive, NULL);
}
+METHOD(logger_t, get_level, level_t,
+ private_sql_logger_t *this, debug_t group)
+{
+ return this->level;
+}
+
METHOD(sql_logger_t, destroy, void,
private_sql_logger_t *this)
{
.public = {
.logger = {
.log = _log_,
+ .get_level = _get_level,
},
.destroy = _destroy,
},
* logging to the stroke interface
*/
static bool stroke_log(stroke_log_info_t *info, debug_t group, level_t level,
- ike_sa_t *ike_sa, char *format, va_list args)
+ ike_sa_t *ike_sa, char *message)
{
if (level <= info->level)
{
- if (vfprintf(info->out, format, args) < 0 ||
+ if (fprintf(info->out, message) < 0 ||
fprintf(info->out, "\n") < 0 ||
fflush(info->out) != 0)
{
while (enumerator->enumerate(enumerator, &sys_logger))
{
sys_logger->set_level(sys_logger, group, msg->loglevel.level);
+ charon->bus->add_logger(charon->bus, &sys_logger->logger);
}
enumerator->destroy(enumerator);
enumerator = charon->file_loggers->create_enumerator(charon->file_loggers);
while (enumerator->enumerate(enumerator, &file_logger))
{
file_logger->set_level(file_logger, group, msg->loglevel.level);
+ charon->bus->add_logger(charon->bus, &file_logger->logger);
}
enumerator->destroy(enumerator);
}
*/
static bool initiate_callback(private_initiate_mediation_job_t *this,
debug_t group, level_t level, ike_sa_t *ike_sa,
- char *format, va_list args)
+ char *message)
{
if (ike_sa && !this->mediation_sa_id)
{