Index: uspace/lib/c/generic/io/log.c
===================================================================
--- uspace/lib/c/generic/io/log.c	(revision e005f92d7dded2e30262e8f664552fc609b25432)
+++ uspace/lib/c/generic/io/log.c	(revision cba45affa1185205ef668562c3239439a610819d)
@@ -62,4 +62,6 @@
 #define MESSAGE_BUFFER_SIZE 4096
 
+static sysarg_t toplog_id;
+
 static int logger_register(async_sess_t *session, const char *prog_name)
 {
@@ -69,5 +71,6 @@
 	}
 
-	aid_t reg_msg = async_send_0(exchange, LOGGER_REGISTER, NULL);
+	ipc_call_t answer;
+	aid_t reg_msg = async_send_0(exchange, LOGGER_WRITER_CREATE_TOPLEVEL_LOG, &answer);
 	int rc = async_data_write_start(exchange, prog_name, str_size(prog_name));
 	sysarg_t reg_msg_rc;
@@ -80,5 +83,10 @@
 	}
 
-	return reg_msg_rc;
+	if (reg_msg_rc != EOK)
+		return reg_msg_rc;
+
+	toplog_id = IPC_GET_ARG1(answer);
+
+	return EOK;
 }
 
@@ -90,6 +98,6 @@
 	}
 
-	aid_t reg_msg = async_send_2(exchange, LOGGER_MESSAGE,
-	    ctx, level, NULL);
+	aid_t reg_msg = async_send_3(exchange, LOGGER_WRITER_MESSAGE,
+	    toplog_id, ctx, level, NULL);
 	int rc = async_data_write_start(exchange, message, str_size(message));
 	sysarg_t reg_msg_rc;
@@ -183,5 +191,5 @@
 
 	ipc_call_t answer;
-	aid_t reg_msg = async_send_0(exchange, LOGGER_CREATE_CONTEXT, &answer);
+	aid_t reg_msg = async_send_1(exchange, LOGGER_WRITER_CREATE_SUB_LOG, toplog_id, &answer);
 	int rc = async_data_write_start(exchange, name, str_size(name));
 	sysarg_t reg_msg_rc;
Index: uspace/lib/c/generic/io/logctl.c
===================================================================
--- uspace/lib/c/generic/io/logctl.c	(revision e005f92d7dded2e30262e8f664552fc609b25432)
+++ uspace/lib/c/generic/io/logctl.c	(revision cba45affa1185205ef668562c3239439a610819d)
@@ -90,5 +90,5 @@
 		return rc;
 
-	aid_t reg_msg = async_send_1(exchange, LOGGER_CTL_SET_NAMESPACE_LEVEL,
+	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));
@@ -112,5 +112,5 @@
 		return rc;
 
-	aid_t reg_msg = async_send_1(exchange, LOGGER_CTL_SET_CONTEXT_LEVEL,
+	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));
Index: uspace/lib/c/include/ipc/logger.h
===================================================================
--- uspace/lib/c/include/ipc/logger.h	(revision e005f92d7dded2e30262e8f664552fc609b25432)
+++ uspace/lib/c/include/ipc/logger.h	(revision cba45affa1185205ef668562c3239439a610819d)
@@ -37,15 +37,15 @@
 
 typedef enum {
-	LOGGER_CTL_GET_DEFAULT_LEVEL = IPC_FIRST_USER_METHOD,
-	LOGGER_CTL_SET_DEFAULT_LEVEL,
-	LOGGER_CTL_SET_NAMESPACE_LEVEL,
-	LOGGER_CTL_SET_CONTEXT_LEVEL
+	LOGGER_CTL_SET_DEFAULT_LEVEL = IPC_FIRST_USER_METHOD,
+	LOGGER_CTL_SET_TOP_LOG_LEVEL,
+	LOGGER_CTL_SET_LOG_LEVEL
 } logger_control_request_t;
 
 typedef enum {
-	LOGGER_REGISTER = IPC_FIRST_USER_METHOD,
-	LOGGER_CREATE_CONTEXT,
-	LOGGER_MESSAGE
-} logger_sink_request_t;
+	/** 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_MESSAGE
+} logger_writer_request_t;
 
 typedef enum {
Index: uspace/srv/logger/Makefile
===================================================================
--- uspace/srv/logger/Makefile	(revision e005f92d7dded2e30262e8f664552fc609b25432)
+++ uspace/srv/logger/Makefile	(revision cba45affa1185205ef668562c3239439a610819d)
@@ -34,6 +34,6 @@
 	ctl.c \
 	level.c \
+	logs.c \
 	main.c \
-	namespace.c \
 	writer.c
 
Index: uspace/srv/logger/ctl.c
===================================================================
--- uspace/srv/logger/ctl.c	(revision e005f92d7dded2e30262e8f664552fc609b25432)
+++ uspace/srv/logger/ctl.c	(revision cba45affa1185205ef668562c3239439a610819d)
@@ -43,46 +43,51 @@
 #include "logger.h"
 
-static int handle_namespace_level_change(sysarg_t new_level)
+static int handle_toplog_level_change(sysarg_t new_level)
 {
-	void *namespace_name;
-	int rc = async_data_write_accept(&namespace_name, true, 0, 0, 0, NULL);
+	void *top_name;
+	int rc = async_data_write_accept(&top_name, true, 0, 0, 0, NULL);
 	if (rc != EOK) {
 		return rc;
 	}
 
-	logging_namespace_t *namespace = namespace_writer_attach((const char *) namespace_name);
-	free(namespace_name);
-	if (namespace == NULL)
+	logger_toplevel_log_t *toplog = find_or_create_toplevel_log(top_name);
+	free(top_name);
+	if (toplog == NULL)
 		return ENOENT;
 
-	rc = namespace_change_level(namespace, (log_level_t) new_level);
-	namespace_writer_detach(namespace);
+	toplog->logged_level = new_level;
 
-	return rc;
+	return EOK;
 }
 
-static int handle_context_level_change(sysarg_t new_level)
+static int handle_log_level_change(sysarg_t new_level)
 {
-	void *namespace_name;
-	int rc = async_data_write_accept(&namespace_name, true, 0, 0, 0, NULL);
+	void *top_name;
+	int rc = async_data_write_accept(&top_name, true, 0, 0, 0, NULL);
 	if (rc != EOK) {
 		return rc;
 	}
 
-	logging_namespace_t *namespace = namespace_writer_attach((const char *) namespace_name);
-	free(namespace_name);
-	if (namespace == NULL)
+	logger_toplevel_log_t *toplog = find_or_create_toplevel_log(top_name);
+	free(top_name);
+	if (toplog == NULL)
 		return ENOENT;
 
-	void *context_name;
-	rc = async_data_write_accept(&context_name, true, 0, 0, 0, NULL);
-	if (rc != EOK) {
-		namespace_writer_detach(namespace);
+
+	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;
+		}
 	}
 
-	rc = namespace_change_context_level(namespace, context_name, new_level);
-	free(context_name);
-	namespace_writer_detach(namespace);
+	free(log_name);
 
 	return rc;
@@ -101,22 +106,20 @@
 			break;
 
-		int rc;
-
 		switch (IPC_GET_IMETHOD(call)) {
-		case LOGGER_CTL_GET_DEFAULT_LEVEL:
-			async_answer_1(callid, EOK, get_default_logging_level());
-			break;
-		case LOGGER_CTL_SET_DEFAULT_LEVEL:
-			rc = set_default_logging_level(IPC_GET_ARG1(call));
+		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_NAMESPACE_LEVEL:
-			rc = handle_namespace_level_change(IPC_GET_ARG1(call));
+		}
+		case LOGGER_CTL_SET_TOP_LOG_LEVEL: {
+			int rc = handle_toplog_level_change(IPC_GET_ARG1(call));
 			async_answer_0(callid, rc);
 			break;
-		case LOGGER_CTL_SET_CONTEXT_LEVEL:
-			rc = handle_context_level_change(IPC_GET_ARG1(call));
+		}
+		case LOGGER_CTL_SET_LOG_LEVEL: {
+			int rc = handle_log_level_change(IPC_GET_ARG1(call));
 			async_answer_0(callid, rc);
 			break;
+		}
 		default:
 			async_answer_0(callid, EINVAL);
Index: uspace/srv/logger/level.c
===================================================================
--- uspace/srv/logger/level.c	(revision e005f92d7dded2e30262e8f664552fc609b25432)
+++ uspace/srv/logger/level.c	(revision cba45affa1185205ef668562c3239439a610819d)
@@ -52,5 +52,5 @@
 {
 	if (new_level >= LVL_LIMIT)
-		return EINVAL;
+		return ERANGE;
 	fibril_mutex_lock(&default_logging_level_guard);
 	default_logging_level = new_level;
Index: uspace/srv/logger/logger.h
===================================================================
--- uspace/srv/logger/logger.h	(revision e005f92d7dded2e30262e8f664552fc609b25432)
+++ uspace/srv/logger/logger.h	(revision cba45affa1185205ef668562c3239439a610819d)
@@ -42,24 +42,30 @@
 #include <bool.h>
 #include <fibril_synch.h>
+#include <stdio.h>
 
 #define NAME "logger"
-#define MAX_NAMESPACE_LENGTH 256
+#define MAX_SUBLOGS 64
 #define LOG_LEVEL_USE_DEFAULT (LVL_LIMIT + 1)
 
-typedef struct logging_namespace logging_namespace_t;
+typedef struct {
+	const char *name;
+	log_level_t logged_level;
+} logger_sublog_t;
 
-logging_namespace_t *namespace_create(const char *);
-const char *namespace_get_name(logging_namespace_t *);
-void namespace_destroy(logging_namespace_t *);
-logging_namespace_t *namespace_writer_attach(const char *);
-void namespace_writer_detach(logging_namespace_t *);
+typedef struct {
+	const char *name;
+	FILE *logfile;
+	log_level_t logged_level;
+	size_t sublog_count;
+	logger_sublog_t sublogs[MAX_SUBLOGS];
 
-int namespace_change_level(logging_namespace_t *, log_level_t);
+	link_t link;
+} logger_toplevel_log_t;
 
-bool namespace_has_reader(logging_namespace_t *, sysarg_t, log_level_t);
-void namespace_add_message(logging_namespace_t *, const char *, sysarg_t, log_level_t);
 
-int namespace_create_context(logging_namespace_t *, const char *);
-int namespace_change_context_level(logging_namespace_t *, const char *, log_level_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 *);
 
 log_level_t get_default_logging_level(void);
Index: uspace/srv/logger/logs.c
===================================================================
--- uspace/srv/logger/logs.c	(revision cba45affa1185205ef668562c3239439a610819d)
+++ uspace/srv/logger/logs.c	(revision cba45affa1185205ef668562c3239439a610819d)
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2012 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup logger
+ * @{
+ */
+#include <assert.h>
+#include <malloc.h>
+#include <str.h>
+#include <stdio.h>
+#include <errno.h>
+#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)
+{
+	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)
+			return log;
+	}
+
+	return NULL;
+}
+
+bool shall_log_message(logger_toplevel_log_t *toplog, sysarg_t log, log_level_t level)
+{
+	if (log >= toplog->sublog_count)
+		return false;
+
+	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();
+	}
+
+
+	return level <= logged_level;
+}
+
+int add_sub_log(logger_toplevel_log_t *toplog, const char *name, sysarg_t *id)
+{
+	if (toplog->sublog_count >= MAX_SUBLOGS)
+		return ELIMIT;
+
+	logger_sublog_t *sublog =  &toplog->sublogs[toplog->sublog_count];
+	sublog->name = str_dup(name);
+	sublog->logged_level = toplog->logged_level;
+
+	*id = toplog->sublog_count;
+
+	toplog->sublog_count++;
+
+	return EOK;
+}
+
+
+/**
+ * @}
+ */
Index: pace/srv/logger/namespace.c
===================================================================
--- uspace/srv/logger/namespace.c	(revision e005f92d7dded2e30262e8f664552fc609b25432)
+++ 	(revision )
@@ -1,310 +1,0 @@
-/*
- * Copyright (c) 2012 Vojtech Horky
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup logger
- * @{
- */
-#include <assert.h>
-#include <malloc.h>
-#include <str.h>
-#include <stdio.h>
-#include <errno.h>
-#include "logger.h"
-
-/** @file
- * Logging namespaces.
- */
-
-#define CONTEXT_SIZE 16
-
-typedef struct {
-	const char *name;
-	log_level_t level;
-} logging_context_t;
-
-struct logging_namespace {
-	fibril_mutex_t guard;
-	size_t writers_count;
-	FILE *logfile;
-	log_level_t level;
-	const char *name;
-
-	// FIXME: make dynamic
-	size_t context_count;
-	logging_context_t context[CONTEXT_SIZE];
-
-	link_t link;
-};
-
-static FIBRIL_MUTEX_INITIALIZE(namespace_list_guard);
-static LIST_INITIALIZE(namespace_list);
-
-static log_level_t namespace_get_actual_log_level(logging_namespace_t *namespace, sysarg_t context)
-{
-	fibril_mutex_lock(&namespace->guard);
-	if (context >= namespace->context_count) {
-		fibril_mutex_unlock(&namespace->guard);
-		fprintf(stderr, "Invalid context!\n");
-		return LVL_FATAL;
-	}
-	log_level_t level = namespace->context[context].level;
-	fibril_mutex_unlock(&namespace->guard);
-
-	if (level == LOG_LEVEL_USE_DEFAULT)
-		level = get_default_logging_level();
-
-	return level;
-}
-
-static logging_namespace_t *namespace_find_no_lock(const char *name)
-{
-	list_foreach(namespace_list, it) {
-		logging_namespace_t *namespace = list_get_instance(it, logging_namespace_t, link);
-		if (str_cmp(namespace->name, name) == 0) {
-			return namespace;
-		}
-	}
-
-	return NULL;
-}
-
-static logging_namespace_t *namespace_create_no_lock(const char *name)
-{
-	logging_namespace_t *existing = namespace_find_no_lock(name);
-	if (existing != NULL) {
-		return NULL;
-	}
-
-	logging_namespace_t *namespace = malloc(sizeof(logging_namespace_t));
-	if (namespace == NULL) {
-		return NULL;
-	}
-
-	namespace->name = str_dup(name);
-	if (namespace->name == NULL) {
-		free(namespace);
-		return NULL;
-	}
-
-	char *logfilename;
-	int rc = asprintf(&logfilename, "/log/%s", name);
-	if (rc < 0) {
-		free(namespace->name);
-		free(namespace);
-		return NULL;
-	}
-	namespace->logfile = fopen(logfilename, "a");
-	free(logfilename);
-	if (namespace->logfile == NULL) {
-		free(namespace->name);
-		free(namespace);
-		return NULL;
-	}
-
-	namespace->level = LOG_LEVEL_USE_DEFAULT;
-
-	namespace->context_count = 1;
-	namespace->context[0].name = "";
-	namespace->context[0].level = LOG_LEVEL_USE_DEFAULT;
-
-	fibril_mutex_initialize(&namespace->guard);
-	namespace->writers_count = 0;
-	link_initialize(&namespace->link);
-
-	list_append(&namespace->link, &namespace_list);
-
-	return namespace;
-}
-
-
-logging_namespace_t *namespace_create(const char *name)
-{
-	fibril_mutex_lock(&namespace_list_guard);
-	logging_namespace_t *result = namespace_create_no_lock(name);
-	fibril_mutex_unlock(&namespace_list_guard);
-	return result;
-}
-
-const char *namespace_get_name(logging_namespace_t *namespace)
-{
-	assert(namespace);
-	return namespace->name;
-}
-
-static void namespace_destroy_careful(logging_namespace_t *namespace)
-{
-	assert(namespace);
-	fibril_mutex_lock(&namespace_list_guard);
-
-	fibril_mutex_lock(&namespace->guard);
-	if (namespace->writers_count > 0) {
-		fibril_mutex_unlock(&namespace->guard);
-		fibril_mutex_unlock(&namespace_list_guard);
-		return;
-	}
-
-	list_remove(&namespace->link);
-
-	fibril_mutex_unlock(&namespace->guard);
-	fibril_mutex_unlock(&namespace_list_guard);
-
-	// TODO - destroy pending messages
-	fclose(namespace->logfile);
-	free(namespace->name);
-	free(namespace);
-}
-
-void namespace_destroy(logging_namespace_t *namespace)
-{
-	namespace_destroy_careful(namespace);
-}
-
-logging_namespace_t *namespace_writer_attach(const char *name)
-{
-	logging_namespace_t *namespace = NULL;
-
-	fibril_mutex_lock(&namespace_list_guard);
-
-	namespace = namespace_find_no_lock(name);
-
-	if (namespace == NULL) {
-		namespace = namespace_create_no_lock(name);
-	}
-
-	fibril_mutex_lock(&namespace->guard);
-	namespace->writers_count++;
-	fibril_mutex_unlock(&namespace->guard);
-
-	fibril_mutex_unlock(&namespace_list_guard);
-
-	return namespace;
-}
-
-void namespace_writer_detach(logging_namespace_t *namespace)
-{
-	fibril_mutex_lock(&namespace->guard);
-	assert(namespace->writers_count > 0);
-	namespace->writers_count--;
-	fibril_mutex_unlock(&namespace->guard);
-
-	namespace_destroy_careful(namespace);
-}
-
-int namespace_change_level(logging_namespace_t *namespace, log_level_t level)
-{
-	if (level >= LVL_LIMIT)
-		return ERANGE;
-
-	fibril_mutex_lock(&namespace->guard);
-	namespace->level = level;
-	for (size_t i = 0; i < namespace->context_count; i++) {
-		namespace->context[i].level = level;
-	}
-	fibril_mutex_unlock(&namespace->guard);
-
-	return EOK;
-}
-
-
-bool namespace_has_reader(logging_namespace_t *namespace, sysarg_t context, log_level_t level)
-{
-	return level <= namespace_get_actual_log_level(namespace, context);
-}
-
-int namespace_create_context(logging_namespace_t *namespace, const char *name)
-{
-	int rc;
-	fibril_mutex_lock(&namespace->guard);
-	if (namespace->context_count >= CONTEXT_SIZE) {
-		rc = ELIMIT;
-		goto leave;
-	}
-
-	namespace->context[namespace->context_count].level
-	    = LOG_LEVEL_USE_DEFAULT;
-	namespace->context[namespace->context_count].name
-	    = str_dup(name);
-	if (namespace->context[namespace->context_count].name == NULL) {
-		rc = ENOMEM;
-		goto leave;
-	}
-	rc = (int) namespace->context_count;
-	namespace->context_count++;
-
-
-leave:
-	fibril_mutex_unlock(&namespace->guard);
-	return rc;
-}
-
-int namespace_change_context_level(logging_namespace_t *namespace, const char *context, log_level_t new_level)
-{
-	if (new_level >= LVL_LIMIT)
-		return ERANGE;
-
-	int rc;
-	fibril_mutex_lock(&namespace->guard);
-	for (size_t i = 0; i < namespace->context_count; i++) {
-		if (str_cmp(namespace->context[i].name, context) == 0) {
-			namespace->context[i].level = new_level;
-			rc = EOK;
-			goto leave;
-		}
-	}
-	rc =  ENOENT;
-
-leave:
-	fibril_mutex_unlock(&namespace->guard);
-	return rc;
-}
-
-void namespace_add_message(logging_namespace_t *namespace, const char *message, sysarg_t context, log_level_t level)
-{
-	if (level <= namespace_get_actual_log_level(namespace, context)) {
-		const char *level_name = log_level_str(level);
-		if (context == 0) {
-			printf("[%s %s]: %s\n",
-			    namespace->name, level_name, message);
-			fprintf(namespace->logfile, "%s: %s\n",
-			    level_name, message);
-		} else {
-			const char *context_name = namespace->context[context].name;
-			printf("[%s/%s %s]: %s\n",
-			    namespace->name, context_name, level_name, message);
-			fprintf(namespace->logfile, "[%s] %s: %s\n",
-			    context_name, level_name, message);
-		}
-		fflush(namespace->logfile);
-		fflush(stdout);
-	}
-}
-
-
-/**
- * @}
- */
Index: uspace/srv/logger/writer.c
===================================================================
--- uspace/srv/logger/writer.c	(revision e005f92d7dded2e30262e8f664552fc609b25432)
+++ uspace/srv/logger/writer.c	(revision cba45affa1185205ef668562c3239439a610819d)
@@ -49,51 +49,41 @@
 
 
-static logging_namespace_t *find_namespace_and_attach_writer(void)
+static logger_toplevel_log_t *handle_create_toplevel_log(void)
 {
-	ipc_call_t call;
-	ipc_callid_t callid = async_get_call(&call);
+	void *name;
+	int rc = async_data_write_accept(&name, true, 1, 0, 0, NULL);
+	if (rc != EOK)
+		return NULL;
 
-	if (IPC_GET_IMETHOD(call) != LOGGER_REGISTER) {
-		async_answer_0(callid, EINVAL);
-		return NULL;
-	}
-
-	void *name;
-	int rc = async_data_write_accept(&name, true, 1, MAX_NAMESPACE_LENGTH, 0, NULL);
-	async_answer_0(callid, rc);
-
-	if (rc != EOK) {
-		return NULL;
-	}
-
-	logging_namespace_t *result = namespace_writer_attach((const char *) name);
+	logger_toplevel_log_t *log = find_or_create_toplevel_log(name);
 
 	free(name);
 
-	return result;
+	return log;
 }
 
-static int handle_receive_message(logging_namespace_t *namespace, sysarg_t context, int level)
+static int handle_receive_message(sysarg_t toplevel_log_id, sysarg_t log_id, sysarg_t level)
 {
-	bool skip_message = !namespace_has_reader(namespace, context, level);
-	if (skip_message) {
-		/* Abort the actual message buffer transfer. */
-		ipc_callid_t callid;
-		size_t size;
-		int rc = ENAK;
-		if (!async_data_write_receive(&callid, &size))
-			rc = EINVAL;
+	logger_toplevel_log_t *log = find_toplevel_log(toplevel_log_id);
+	if (log == NULL)
+		return ENOENT;
 
-		async_answer_0(callid, rc);
+	if (log_id > log->sublog_count)
+		return ENOENT;
+
+	void *message;
+	int rc = async_data_write_accept(&message, true, 1, 0, 0, NULL);
+	if (rc != EOK)
 		return rc;
+
+	if (!shall_log_message(log, log_id, level)) {
+		free(message);
+		return EOK;
 	}
 
-	void *message;
-	int rc = async_data_write_accept(&message, true, 0, 0, 0, NULL);
-	if (rc != EOK) {
-		return rc;
-	}
-
-	namespace_add_message(namespace, message, context, level);
+	printf("[%s/%s] %s: %s\n",
+	    log->name, log->sublogs[log_id].name,
+	    log_level_str(level),
+	    (const char *) message);
 
 	free(message);
@@ -102,34 +92,28 @@
 }
 
-static int handle_create_context(logging_namespace_t *namespace, sysarg_t *idx)
+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) {
+	if (rc != EOK)
 		return rc;
-	}
 
-	rc = namespace_create_context(namespace, name);
+	rc = add_sub_log(log, name, log_id);
 
 	free(name);
 
-	if (rc < 0)
-		return rc;
-
-	*idx = (sysarg_t) rc;
-	return EOK;
+	return rc;
 }
 
 void logger_connection_handler_writer(ipc_callid_t callid)
 {
-	/* First call has to be the registration. */
+	/* Acknowledge the connection. */
 	async_answer_0(callid, EOK);
-	logging_namespace_t *namespace = find_namespace_and_attach_writer();
-	if (namespace == NULL) {
-		fprintf(stderr, NAME ": failed to register namespace.\n");
-		return;
-	}
 
-	printf(NAME "/writer: new client %s.\n", namespace_get_name(namespace));
+	printf(NAME "/writer: new client.\n");
 
 	while (true) {
@@ -140,16 +124,26 @@
 			break;
 
-		int rc;
-		sysarg_t arg = 0;
-
 		switch (IPC_GET_IMETHOD(call)) {
-		case LOGGER_CREATE_CONTEXT:
-			rc = handle_create_context(namespace, &arg);
-			async_answer_1(callid, rc, arg);
+		case LOGGER_WRITER_CREATE_TOPLEVEL_LOG: {
+			logger_toplevel_log_t *log = handle_create_toplevel_log();
+			if (log == NULL) {
+				async_answer_0(callid, ENOMEM);
+				break;
+			}
+			async_answer_1(callid, EOK, (sysarg_t) log);
 			break;
-		case LOGGER_MESSAGE:
-			rc = handle_receive_message(namespace, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
+		}
+		case LOGGER_WRITER_MESSAGE: {
+			int rc = handle_receive_message(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call), IPC_GET_ARG3(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;
+		}
 		default:
 			async_answer_0(callid, EINVAL);
@@ -158,6 +152,5 @@
 	}
 
-	printf(NAME "/sink: client %s terminated.\n", namespace_get_name(namespace));
-	namespace_writer_detach(namespace);
+	// FIXME: destroy created logs
 }
 
