Index: uspace/app/logset/main.c
===================================================================
--- uspace/app/logset/main.c	(revision f72ae3b5d74ccbf6f8f546b2bbadc5a85f4fb81b)
+++ uspace/app/logset/main.c	(revision f039dbab175faa56569d0d741d9f6d9f2d76113d)
@@ -71,17 +71,7 @@
 	} else if (argc == 3) {
 		log_level_t new_level = parse_log_level_or_die(argv[2]);
-		const char *toplog = argv[1];
-		int rc = logctl_set_top_log_level(toplog, new_level);
+		const char *logname = argv[1];
+		int rc = logctl_set_log_level(logname, new_level);
 
-		if (rc != EOK) {
-			fprintf(stderr, "Failed to change logging level: %s.\n",
-			    str_error(rc));
-			return 2;
-		}
-	} else if (argc == 4) {
-		log_level_t new_level = parse_log_level_or_die(argv[3]);
-		const char *toplog = argv[1];
-		const char *log = argv[2];
-		int rc = logctl_set_log_level(toplog, log, new_level);
 		if (rc != EOK) {
 			fprintf(stderr, "Failed to change logging level: %s.\n",
Index: uspace/lib/c/generic/io/log.c
===================================================================
--- uspace/lib/c/generic/io/log.c	(revision f72ae3b5d74ccbf6f8f546b2bbadc5a85f4fb81b)
+++ uspace/lib/c/generic/io/log.c	(revision f039dbab175faa56569d0d741d9f6d9f2d76113d)
@@ -43,17 +43,5 @@
 #include <ns.h>
 
-typedef struct {
-	char *name;
-	sysarg_t top_log_id;
-	sysarg_t log_id;
-} log_info_t;
-
-static log_info_t default_log = {
-	.name = NULL,
-	.top_log_id = 0,
-	.log_id = 0
-};
-
-static sysarg_t default_top_log_id;
+static sysarg_t default_log_id;
 
 /** Log messages are printed under this name. */
@@ -85,5 +73,5 @@
 
 	ipc_call_t answer;
-	aid_t reg_msg = async_send_0(exchange, LOGGER_WRITER_CREATE_TOPLEVEL_LOG, &answer);
+	aid_t reg_msg = async_send_1(exchange, LOGGER_WRITER_CREATE_LOG, LOG_NO_PARENT, &answer);
 	int rc = async_data_write_start(exchange, prog_name, str_size(prog_name));
 	sysarg_t reg_msg_rc;
@@ -99,11 +87,10 @@
 		return reg_msg_rc;
 
-	default_top_log_id = IPC_GET_ARG1(answer);
-	default_log.top_log_id = default_top_log_id;
+	default_log_id = IPC_GET_ARG1(answer);
 
 	return EOK;
 }
 
-static int logger_message(async_sess_t *session, log_t ctx, log_level_t level, const char *message)
+static int logger_message(async_sess_t *session, log_t log, log_level_t level, const char *message)
 {
 	async_exch_t *exchange = async_exchange_begin(session);
@@ -111,8 +98,9 @@
 		return ENOMEM;
 	}
-	log_info_t *log_info = ctx != 0 ? (log_info_t *) ctx : &default_log;
-
-	aid_t reg_msg = async_send_3(exchange, LOGGER_WRITER_MESSAGE,
-	    log_info->top_log_id, log_info->log_id, level, NULL);
+	if (log == LOG_DEFAULT)
+		log = default_log_id;
+
+	aid_t reg_msg = async_send_2(exchange, LOGGER_WRITER_MESSAGE,
+	    log, level, NULL);
 	int rc = async_data_write_start(exchange, message, str_size(message));
 	sysarg_t reg_msg_rc;
@@ -206,31 +194,15 @@
 log_t log_create(const char *name, log_t parent)
 {
-	log_info_t *info = malloc(sizeof(log_info_t));
-	if (info == NULL)
-		return LOG_DEFAULT;
-	info->name = NULL;
-
-	if (parent == LOG_DEFAULT) {
-		info->name = str_dup(name);
-		if (info->name == NULL)
-			goto error;
-		info->top_log_id = default_top_log_id;
-	} else {
-		log_info_t *parent_info = (log_info_t *) parent;
-		int rc = asprintf(&info->name, "%s/%s",
-		    parent_info->name, name);
-		if (rc < 0)
-			goto error;
-		info->top_log_id = parent_info->top_log_id;
-	}
-
 	async_exch_t *exchange = async_exchange_begin(logger_session);
 	if (exchange == NULL)
-		goto error;
+		return parent;
+
+	if (parent == LOG_DEFAULT)
+		parent = default_log_id;
 
 	ipc_call_t answer;
-	aid_t reg_msg = async_send_1(exchange, LOGGER_WRITER_CREATE_SUB_LOG,
-	    info->top_log_id, &answer);
-	int rc = async_data_write_start(exchange, info->name, str_size(info->name));
+	aid_t reg_msg = async_send_1(exchange, LOGGER_WRITER_CREATE_LOG,
+	    parent, &answer);
+	int rc = async_data_write_start(exchange, name, str_size(name));
 	sysarg_t reg_msg_rc;
 	async_wait_for(reg_msg, &reg_msg_rc);
@@ -239,13 +211,7 @@
 
 	if ((rc != EOK) || (reg_msg_rc != EOK))
-		goto error;
-
-	info->log_id = IPC_GET_ARG1(answer);
-	return (sysarg_t) info;
-
-error:
-	free(info->name);
-	free(info);
-	return parent;
+		return parent;
+
+	return IPC_GET_ARG1(answer);
 }
 
Index: uspace/lib/c/generic/io/logctl.c
===================================================================
--- uspace/lib/c/generic/io/logctl.c	(revision f72ae3b5d74ccbf6f8f546b2bbadc5a85f4fb81b)
+++ uspace/lib/c/generic/io/logctl.c	(revision f039dbab175faa56569d0d741d9f6d9f2d76113d)
@@ -81,27 +81,5 @@
 }
 
-int logctl_set_top_log_level(const char *namespace, log_level_t new_level)
-{
-	async_exch_t *exchange = NULL;
-	int rc = start_logger_exchange(&exchange);
-	if (rc != EOK)
-		return rc;
-
-	aid_t reg_msg = async_send_1(exchange, LOGGER_CTL_SET_TOP_LOG_LEVEL,
-	    new_level, NULL);
-	rc = async_data_write_start(exchange, namespace, str_size(namespace));
-	sysarg_t reg_msg_rc;
-	async_wait_for(reg_msg, &reg_msg_rc);
-
-	async_exchange_end(exchange);
-
-	if (rc != EOK) {
-		return rc;
-	}
-
-	return (int) reg_msg_rc;
-}
-
-int logctl_set_log_level(const char *namespace, const char *context, log_level_t new_level)
+int logctl_set_log_level(const char *logname, log_level_t new_level)
 {
 	async_exch_t *exchange = NULL;
@@ -112,6 +90,5 @@
 	aid_t reg_msg = async_send_1(exchange, LOGGER_CTL_SET_LOG_LEVEL,
 	    new_level, NULL);
-	rc = async_data_write_start(exchange, namespace, str_size(namespace));
-	int rc2 = async_data_write_start(exchange, context, str_size(context));
+	rc = async_data_write_start(exchange, logname, str_size(logname));
 	sysarg_t reg_msg_rc;
 	async_wait_for(reg_msg, &reg_msg_rc);
@@ -122,7 +99,4 @@
 		return rc;
 
-	if (rc2 != EOK)
-		return rc2;
-
 	return (int) reg_msg_rc;
 }
Index: uspace/lib/c/include/io/log.h
===================================================================
--- uspace/lib/c/include/io/log.h	(revision f72ae3b5d74ccbf6f8f546b2bbadc5a85f4fb81b)
+++ uspace/lib/c/include/io/log.h	(revision f039dbab175faa56569d0d741d9f6d9f2d76113d)
@@ -53,5 +53,6 @@
 typedef sysarg_t log_t;
 #define PRIlogctx PRIxn
-#define LOG_DEFAULT 0
+#define LOG_DEFAULT ((log_t) -1)
+#define LOG_NO_PARENT ((log_t) 0)
 
 extern const char *log_level_str(log_level_t);
Index: uspace/lib/c/include/io/logctl.h
===================================================================
--- uspace/lib/c/include/io/logctl.h	(revision f72ae3b5d74ccbf6f8f546b2bbadc5a85f4fb81b)
+++ uspace/lib/c/include/io/logctl.h	(revision f039dbab175faa56569d0d741d9f6d9f2d76113d)
@@ -37,6 +37,5 @@
 
 extern int logctl_set_default_level(log_level_t);
-extern int logctl_set_top_log_level(const char *, log_level_t);
-extern int logctl_set_log_level(const char *, const char *, log_level_t);
+extern int logctl_set_log_level(const char *, log_level_t);
 
 #endif
Index: uspace/lib/c/include/ipc/logger.h
===================================================================
--- uspace/lib/c/include/ipc/logger.h	(revision f72ae3b5d74ccbf6f8f546b2bbadc5a85f4fb81b)
+++ uspace/lib/c/include/ipc/logger.h	(revision f039dbab175faa56569d0d741d9f6d9f2d76113d)
@@ -38,5 +38,4 @@
 typedef enum {
 	LOGGER_CTL_SET_DEFAULT_LEVEL = IPC_FIRST_USER_METHOD,
-	LOGGER_CTL_SET_TOP_LOG_LEVEL,
 	LOGGER_CTL_SET_LOG_LEVEL
 } logger_control_request_t;
@@ -44,6 +43,5 @@
 typedef enum {
 	/** Followed by STRING, returns ID to be used for CREATE_SUB_LOG */
-	LOGGER_WRITER_CREATE_TOPLEVEL_LOG = IPC_FIRST_USER_METHOD,
-	LOGGER_WRITER_CREATE_SUB_LOG,
+	LOGGER_WRITER_CREATE_LOG = IPC_FIRST_USER_METHOD,
 	LOGGER_WRITER_MESSAGE
 } logger_writer_request_t;
Index: uspace/srv/logger/ctl.c
===================================================================
--- uspace/srv/logger/ctl.c	(revision f72ae3b5d74ccbf6f8f546b2bbadc5a85f4fb81b)
+++ uspace/srv/logger/ctl.c	(revision f039dbab175faa56569d0d741d9f6d9f2d76113d)
@@ -43,53 +43,20 @@
 #include "logger.h"
 
-static int handle_toplog_level_change(sysarg_t new_level)
+static int handle_log_level_change(sysarg_t new_level)
 {
-	void *top_name;
-	int rc = async_data_write_accept(&top_name, true, 0, 0, 0, NULL);
+	void *full_name;
+	int rc = async_data_write_accept(&full_name, true, 0, 0, 0, NULL);
 	if (rc != EOK) {
 		return rc;
 	}
 
-	logger_toplevel_log_t *toplog = find_or_create_toplevel_log(top_name);
-	free(top_name);
-	if (toplog == NULL)
+	logger_log_t *log = find_log_by_name(full_name);
+	free(full_name);
+	if (log == NULL)
 		return ENOENT;
 
-	toplog->logged_level = new_level;
+	log->logged_level = new_level;
 
 	return EOK;
-}
-
-static int handle_log_level_change(sysarg_t new_level)
-{
-	void *top_name;
-	int rc = async_data_write_accept(&top_name, true, 0, 0, 0, NULL);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	logger_toplevel_log_t *toplog = find_or_create_toplevel_log(top_name);
-	free(top_name);
-	if (toplog == NULL)
-		return ENOENT;
-
-
-	void *log_name;
-	rc = async_data_write_accept(&log_name, true, 0, 0, 0, NULL);
-	if (rc != EOK)
-		return rc;
-
-	rc = ENOENT;
-	for (size_t i = 0; i < toplog->sublog_count; i++) {
-		if (str_cmp(toplog->sublogs[i].name, (const char *) log_name) == 0) {
-			toplog->sublogs[i].logged_level = new_level;
-			rc = EOK;
-			break;
-		}
-	}
-
-	free(log_name);
-
-	return rc;
 }
 
@@ -109,9 +76,4 @@
 		case LOGGER_CTL_SET_DEFAULT_LEVEL: {
 			int rc = set_default_logging_level(IPC_GET_ARG1(call));
-			async_answer_0(callid, rc);
-			break;
-		}
-		case LOGGER_CTL_SET_TOP_LOG_LEVEL: {
-			int rc = handle_toplog_level_change(IPC_GET_ARG1(call));
 			async_answer_0(callid, rc);
 			break;
Index: uspace/srv/logger/initlvl.c
===================================================================
--- uspace/srv/logger/initlvl.c	(revision f72ae3b5d74ccbf6f8f546b2bbadc5a85f4fb81b)
+++ uspace/srv/logger/initlvl.c	(revision f039dbab175faa56569d0d741d9f6d9f2d76113d)
@@ -61,5 +61,5 @@
 		return;
 
-	logger_toplevel_log_t *log = find_or_create_toplevel_log(key);
+	logger_log_t *log = find_or_create_log(key, 0);
 	if (log == NULL)
 		return;
Index: uspace/srv/logger/logger.h
===================================================================
--- uspace/srv/logger/logger.h	(revision f72ae3b5d74ccbf6f8f546b2bbadc5a85f4fb81b)
+++ uspace/srv/logger/logger.h	(revision f039dbab175faa56569d0d741d9f6d9f2d76113d)
@@ -48,24 +48,24 @@
 #define LOG_LEVEL_USE_DEFAULT (LVL_LIMIT + 1)
 
-typedef struct {
-	const char *name;
-	log_level_t logged_level;
-} logger_sublog_t;
+typedef struct logger_log logger_log_t;
 
 typedef struct {
-	const char *name;
 	FILE *logfile;
+} logger_dest_t;
+
+struct logger_log {
+	link_t link;
+
+	char *name;
+	char *full_name;
+	logger_log_t *parent;
 	log_level_t logged_level;
-	size_t sublog_count;
-	logger_sublog_t sublogs[MAX_SUBLOGS];
+	logger_dest_t *dest;
+};
 
-	link_t link;
-} logger_toplevel_log_t;
-
-
-logger_toplevel_log_t *find_or_create_toplevel_log(const char *);
-logger_toplevel_log_t *find_toplevel_log(sysarg_t);
-bool shall_log_message(logger_toplevel_log_t *, sysarg_t, log_level_t);
-int add_sub_log(logger_toplevel_log_t *, const char *, sysarg_t *);
+logger_log_t *find_log_by_name(const char *name);
+logger_log_t *find_or_create_log(const char *name, sysarg_t parent);
+logger_log_t *find_log_by_id(sysarg_t);
+bool shall_log_message(logger_log_t *, log_level_t);
 
 log_level_t get_default_logging_level(void);
Index: uspace/srv/logger/logs.c
===================================================================
--- uspace/srv/logger/logs.c	(revision f72ae3b5d74ccbf6f8f546b2bbadc5a85f4fb81b)
+++ uspace/srv/logger/logs.c	(revision f039dbab175faa56569d0d741d9f6d9f2d76113d)
@@ -37,57 +37,14 @@
 #include "logger.h"
 
-static FIBRIL_MUTEX_INITIALIZE(toplog_list_guard);
-static LIST_INITIALIZE(toplog_list);
 
-static logger_toplevel_log_t *find_log_by_name_no_lock(const char *name)
+static FIBRIL_MUTEX_INITIALIZE(log_list_guard);
+static LIST_INITIALIZE(log_list);
+
+
+static logger_log_t *find_log_by_name_and_parent_no_lock(const char *name, logger_log_t *parent)
 {
-	list_foreach(toplog_list, it) {
-		logger_toplevel_log_t *log = list_get_instance(it, logger_toplevel_log_t, link);
-		if (str_cmp(log->name, name) == 0) {
-			return log;
-		}
-	}
-
-	return NULL;
-}
-
-logger_toplevel_log_t *find_or_create_toplevel_log(const char *name)
-{
-	logger_toplevel_log_t *result = NULL;
-
-	fibril_mutex_lock(&toplog_list_guard);
-
-	result = find_log_by_name_no_lock(name);
-	if (result != NULL)
-		goto leave;
-
-	result = malloc(sizeof(logger_toplevel_log_t));
-	if (result == NULL)
-		goto leave;
-
-	char *logfilename;
-	asprintf(&logfilename, "/log/%s", name);
-	result->logfile = fopen(logfilename, "a");
-	result->logged_level = LOG_LEVEL_USE_DEFAULT;
-	result->name = str_dup(name);
-	result->sublog_count = 1;
-	result->sublogs[0].name = "";
-	result->sublogs[0].logged_level = LOG_LEVEL_USE_DEFAULT;
-
-	link_initialize(&result->link);
-
-	list_append(&result->link, &toplog_list);
-
-leave:
-	fibril_mutex_unlock(&toplog_list_guard);
-
-	return result;
-}
-
-logger_toplevel_log_t *find_toplevel_log(sysarg_t id)
-{
-	list_foreach(toplog_list, it) {
-		logger_toplevel_log_t *log = list_get_instance(it, logger_toplevel_log_t, link);
-		if ((sysarg_t) log == id)
+	list_foreach(log_list, it) {
+		logger_log_t *log = list_get_instance(it, logger_log_t, link);
+		if ((parent == log->parent) && (str_cmp(log->name, name) == 0))
 			return log;
 	}
@@ -96,36 +53,100 @@
 }
 
-bool shall_log_message(logger_toplevel_log_t *toplog, sysarg_t log, log_level_t level)
+static logger_dest_t *create_dest(const char *name)
 {
-	if (log >= toplog->sublog_count)
-		return false;
+	logger_dest_t *result = malloc(sizeof(logger_dest_t));
+	char *logfilename;
+	asprintf(&logfilename, "/log/%s", name);
+	result->logfile = fopen(logfilename, "a");
+	return result;
+}
 
-	log_level_t logged_level = toplog->sublogs[log].logged_level;
-	if (logged_level == LOG_LEVEL_USE_DEFAULT) {
-		logged_level = toplog->logged_level;
-		if (logged_level == LOG_LEVEL_USE_DEFAULT)
-			logged_level = get_default_logging_level();
-	}
+logger_log_t *find_or_create_log(const char *name, sysarg_t parent_id)
+{
+	logger_log_t *result = NULL;
+	logger_log_t *parent = (logger_log_t *) parent_id;
+
+	fibril_mutex_lock(&log_list_guard);
+
+	result = find_log_by_name_and_parent_no_lock(name, parent);
+	if (result != NULL)
+		goto leave;
+
+	result = malloc(sizeof(logger_log_t));
+	if (result == NULL)
+		goto leave;
 
 
-	return level <= logged_level;
+	result->logged_level = LOG_LEVEL_USE_DEFAULT;
+	result->name = str_dup(name);
+	if (parent == NULL) {
+		result->full_name = str_dup(name);
+		result->dest = create_dest(name);
+	} else {
+		asprintf(&result->full_name, "%s/%s", parent->full_name, name);
+		result->dest = parent->dest;
+	}
+	result->parent = parent;
+
+	link_initialize(&result->link);
+
+	list_append(&result->link, &log_list);
+
+leave:
+	fibril_mutex_unlock(&log_list_guard);
+
+	return result;
 }
 
-int add_sub_log(logger_toplevel_log_t *toplog, const char *name, sysarg_t *id)
+logger_log_t *find_log_by_name(const char *name)
 {
-	if (toplog->sublog_count >= MAX_SUBLOGS)
-		return ELIMIT;
+	logger_log_t *result = NULL;
 
-	logger_sublog_t *sublog =  &toplog->sublogs[toplog->sublog_count];
-	sublog->name = str_dup(name);
-	sublog->logged_level = toplog->logged_level;
+	fibril_mutex_lock(&log_list_guard);
+	list_foreach(log_list, it) {
+		logger_log_t *log = list_get_instance(it, logger_log_t, link);
+		if (str_cmp(log->full_name, name) == 0) {
+			result = log;
+			break;
+		}
+	}
+	fibril_mutex_unlock(&log_list_guard);
 
-	*id = toplog->sublog_count;
-
-	toplog->sublog_count++;
-
-	return EOK;
+	return result;
 }
 
+logger_log_t *find_log_by_id(sysarg_t id)
+{
+	logger_log_t *result = NULL;
+
+	fibril_mutex_lock(&log_list_guard);
+	list_foreach(log_list, it) {
+		logger_log_t *log = list_get_instance(it, logger_log_t, link);
+		if ((sysarg_t) log == id) {
+			result = log;
+			break;
+		}
+	}
+	fibril_mutex_unlock(&log_list_guard);
+
+	return result;
+}
+
+static log_level_t get_actual_log_level(logger_log_t *log)
+{
+	/* Find recursively proper log level. */
+	if (log->logged_level == LOG_LEVEL_USE_DEFAULT) {
+		if (log->parent == NULL)
+			return get_default_logging_level();
+		else
+			return get_actual_log_level(log->parent);
+	}
+	return log->logged_level;
+}
+
+bool shall_log_message(logger_log_t *log, log_level_t level)
+{
+	return level <= get_actual_log_level(log);
+}
 
 /**
Index: uspace/srv/logger/writer.c
===================================================================
--- uspace/srv/logger/writer.c	(revision f72ae3b5d74ccbf6f8f546b2bbadc5a85f4fb81b)
+++ uspace/srv/logger/writer.c	(revision f039dbab175faa56569d0d741d9f6d9f2d76113d)
@@ -49,5 +49,5 @@
 
 
-static logger_toplevel_log_t *handle_create_toplevel_log(void)
+static logger_log_t *handle_create_log(sysarg_t parent)
 {
 	void *name;
@@ -56,5 +56,5 @@
 		return NULL;
 
-	logger_toplevel_log_t *log = find_or_create_toplevel_log(name);
+	logger_log_t *log = find_or_create_log(name, parent);
 
 	free(name);
@@ -63,11 +63,8 @@
 }
 
-static int handle_receive_message(sysarg_t toplevel_log_id, sysarg_t log_id, sysarg_t level)
+static int handle_receive_message(sysarg_t log_id, sysarg_t level)
 {
-	logger_toplevel_log_t *log = find_toplevel_log(toplevel_log_id);
+	logger_log_t *log = find_log_by_id(log_id);
 	if (log == NULL)
-		return ENOENT;
-
-	if (log_id > log->sublog_count)
 		return ENOENT;
 
@@ -77,12 +74,11 @@
 		return rc;
 
-	if (!shall_log_message(log, log_id, level)) {
+	if (!shall_log_message(log, level)) {
 		free(message);
 		return EOK;
 	}
 
-	printf("[%s/%s] %s: %s\n",
-	    log->name, log->sublogs[log_id].name,
-	    log_level_str(level),
+	printf("[%s] %s: %s\n",
+	    log->full_name, log_level_str(level),
 	    (const char *) message);
 
@@ -90,22 +86,4 @@
 
 	return EOK;
-}
-
-static int handle_create_sub_log(sysarg_t toplevel_log_id, sysarg_t *log_id)
-{
-	logger_toplevel_log_t *log = find_toplevel_log(toplevel_log_id);
-	if (log == NULL)
-		return ENOENT;
-
-	void *name;
-	int rc = async_data_write_accept(&name, true, 0, 0, 0, NULL);
-	if (rc != EOK)
-		return rc;
-
-	rc = add_sub_log(log, name, log_id);
-
-	free(name);
-
-	return rc;
 }
 
@@ -125,6 +103,6 @@
 
 		switch (IPC_GET_IMETHOD(call)) {
-		case LOGGER_WRITER_CREATE_TOPLEVEL_LOG: {
-			logger_toplevel_log_t *log = handle_create_toplevel_log();
+		case LOGGER_WRITER_CREATE_LOG: {
+			logger_log_t *log = handle_create_log(IPC_GET_ARG1(call));
 			if (log == NULL) {
 				async_answer_0(callid, ENOMEM);
@@ -136,12 +114,6 @@
 		case LOGGER_WRITER_MESSAGE: {
 			int rc = handle_receive_message(IPC_GET_ARG1(call),
-			    IPC_GET_ARG2(call), IPC_GET_ARG3(call));
+			    IPC_GET_ARG2(call));
 			async_answer_0(callid, rc);
-			break;
-		}
-		case LOGGER_WRITER_CREATE_SUB_LOG: {
-			sysarg_t log_id;
-			int rc = handle_create_sub_log(IPC_GET_ARG1(call), &log_id);
-			async_answer_1(callid, rc, log_id);
 			break;
 		}
