Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision ad780544d441f9ddecd38ab48b2e79bcea7123cb)
+++ boot/Makefile.common	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -74,5 +74,6 @@
 	$(USPACE_PATH)/srv/locsrv/locsrv \
 	$(USPACE_PATH)/srv/bd/rd/rd \
-	$(USPACE_PATH)/srv/vfs/vfs
+	$(USPACE_PATH)/srv/vfs/vfs \
+	$(USPACE_PATH)/srv/logger/logger
 
 ifeq ($(RDFMT),tmpfs)
@@ -169,4 +170,5 @@
 	$(USPACE_PATH)/app/killall/killall \
 	$(USPACE_PATH)/app/loc/loc \
+	$(USPACE_PATH)/app/logset/logset \
 	$(USPACE_PATH)/app/mkfat/mkfat \
 	$(USPACE_PATH)/app/mkexfat/mkexfat \
Index: kernel/genarch/include/multiboot/multiboot.h
===================================================================
--- kernel/genarch/include/multiboot/multiboot.h	(revision ad780544d441f9ddecd38ab48b2e79bcea7123cb)
+++ kernel/genarch/include/multiboot/multiboot.h	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -99,4 +99,5 @@
 
 extern void multiboot_extract_command(char *, size_t, const char *);
+extern void multiboot_extract_argument(char *, size_t, const char *);
 extern void multiboot_info_parse(uint32_t, const multiboot_info_t *);
 
Index: kernel/genarch/src/multiboot/multiboot.c
===================================================================
--- kernel/genarch/src/multiboot/multiboot.c	(revision ad780544d441f9ddecd38ab48b2e79bcea7123cb)
+++ kernel/genarch/src/multiboot/multiboot.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -71,4 +71,33 @@
 }
 
+/** Extract arguments from the multiboot module command line.
+ *
+ * @param buf      Destination buffer (will be always NULL-terminated).
+ * @param size     Size of destination buffer (in bytes).
+ * @param cmd_line Input string (the command line).
+ *
+ */
+void multiboot_extract_argument(char *buf, size_t size, const char *cmd_line)
+{
+	/* Start after first space. */
+	const char *start = str_chr(cmd_line, ' ');
+	if (start == NULL) {
+		str_cpy(buf, size, "");
+		return;
+	}
+
+	const char *end = cmd_line + str_size(cmd_line);
+
+	/* Skip the space(s). */
+	while (start != end) {
+		if (start[0] == ' ')
+			start++;
+		else
+			break;
+	}
+
+	str_ncpy(buf, size, start, (size_t) (end - start));
+}
+
 static void multiboot_modules(uint32_t count, multiboot_module_t *mods)
 {
@@ -84,6 +113,10 @@
 			multiboot_extract_command(init.tasks[init.cnt].name,
 			    CONFIG_TASK_NAME_BUFLEN, MULTIBOOT_PTR(mods[i].string));
-		} else
+			multiboot_extract_argument(init.tasks[init.cnt].arguments,
+			    CONFIG_TASK_ARGUMENTS_BUFLEN, MULTIBOOT_PTR(mods[i].string));
+		} else {
 			init.tasks[init.cnt].name[0] = 0;
+			init.tasks[init.cnt].arguments[0] = 0;
+		}
 		
 		init.cnt++;
Index: kernel/genarch/src/multiboot/multiboot2.c
===================================================================
--- kernel/genarch/src/multiboot/multiboot2.c	(revision ad780544d441f9ddecd38ab48b2e79bcea7123cb)
+++ kernel/genarch/src/multiboot/multiboot2.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -49,4 +49,6 @@
 		multiboot_extract_command(init.tasks[init.cnt].name,
 		    CONFIG_TASK_NAME_BUFLEN, module->string);
+		multiboot_extract_argument(init.tasks[init.cnt].arguments,
+		    CONFIG_TASK_ARGUMENTS_BUFLEN, module->string);
 		
 		init.cnt++;
Index: kernel/generic/include/config.h
===================================================================
--- kernel/generic/include/config.h	(revision ad780544d441f9ddecd38ab48b2e79bcea7123cb)
+++ kernel/generic/include/config.h	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -47,4 +47,5 @@
 #define CONFIG_INIT_TASKS        32
 #define CONFIG_TASK_NAME_BUFLEN  32
+#define CONFIG_TASK_ARGUMENTS_BUFLEN 64
 
 #ifndef __ASM__
@@ -56,4 +57,5 @@
 	size_t size;
 	char name[CONFIG_TASK_NAME_BUFLEN];
+	char arguments[CONFIG_TASK_ARGUMENTS_BUFLEN];
 } init_task_t;
 
Index: kernel/generic/src/main/kinit.c
===================================================================
--- kernel/generic/src/main/kinit.c	(revision ad780544d441f9ddecd38ab48b2e79bcea7123cb)
+++ kernel/generic/src/main/kinit.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -69,4 +69,5 @@
 #include <str.h>
 #include <sysinfo/stats.h>
+#include <sysinfo/sysinfo.h>
 #include <align.h>
 
@@ -179,4 +180,26 @@
 	program_t programs[CONFIG_INIT_TASKS];
 	
+	// FIXME: do not propagate arguments through sysinfo
+	// but pass them directly to the tasks
+	for (i = 0; i < init.cnt; i++) {
+		const char *arguments = init.tasks[i].arguments;
+		if (str_length(arguments) == 0)
+			continue;
+		if (str_length(init.tasks[i].name) == 0)
+			continue;
+		size_t arguments_size = str_size(arguments);
+
+		void *arguments_copy = malloc(arguments_size, 0);
+		if (arguments_copy == NULL)
+			continue;
+		memcpy(arguments_copy, arguments, arguments_size);
+
+		char item_name[CONFIG_TASK_NAME_BUFLEN + 15];
+		snprintf(item_name, CONFIG_TASK_NAME_BUFLEN + 15,
+		    "init_args.%s", init.tasks[i].name);
+
+		sysinfo_set_item_data(item_name, NULL, arguments_copy, arguments_size);
+	}
+
 	for (i = 0; i < init.cnt; i++) {
 		if (init.tasks[i].paddr % FRAME_SIZE) {
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision ad780544d441f9ddecd38ab48b2e79bcea7123cb)
+++ uspace/Makefile	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -47,4 +47,5 @@
 	app/klog \
 	app/loc \
+	app/logset \
 	app/mkfat \
 	app/mkexfat \
@@ -77,4 +78,5 @@
 	srv/clipboard \
 	srv/locsrv \
+	srv/logger \
 	srv/devman \
 	srv/loader \
Index: uspace/app/logset/Makefile
===================================================================
--- uspace/app/logset/Makefile	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/app/logset/Makefile	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+BINARY = logset
+
+SOURCES = \
+	main.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/logset/main.c
===================================================================
--- uspace/app/logset/main.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/app/logset/main.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,90 @@
+/*
+ * 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 logset
+ * @{
+ */
+/** @file Change logger behavior.
+ */
+#include <stdio.h>
+#include <async.h>
+#include <errno.h>
+#include <str_error.h>
+#include <io/logctl.h>
+
+static log_level_t parse_log_level_or_die(const char *log_level)
+{
+	log_level_t result;
+	int rc = log_level_from_str(log_level, &result);
+	if (rc != EOK) {
+		fprintf(stderr, "Unrecognised log level '%s': %s.\n",
+		    log_level, str_error(rc));
+		exit(2);
+	}
+	return result;
+}
+
+static void usage(const char *progname)
+{
+	fprintf(stderr, "Usage:\n");
+	fprintf(stderr, "  %s <default-logging-level>\n", progname);
+	fprintf(stderr, "  %s <namespace> <logging-level>\n", progname);
+	fprintf(stderr, "  %s <namespace> <context> <logging-level>\n", progname);
+}
+
+int main(int argc, char *argv[])
+{
+	if (argc == 2) {
+		log_level_t new_default_level = parse_log_level_or_die(argv[1]);
+		int rc = logctl_set_default_level(new_default_level);
+
+		if (rc != EOK) {
+			fprintf(stderr, "Failed to change default logging level: %s.\n",
+			    str_error(rc));
+			return 2;
+		}
+	} else if (argc == 3) {
+		log_level_t new_level = parse_log_level_or_die(argv[2]);
+		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 {
+		usage(argv[0]);
+		return 1;
+	}
+
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/app/tester/Makefile
===================================================================
--- uspace/app/tester/Makefile	(revision ad780544d441f9ddecd38ab48b2e79bcea7123cb)
+++ uspace/app/tester/Makefile	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -45,4 +45,6 @@
 	stdio/stdio1.c \
 	stdio/stdio2.c \
+	stdio/logger1.c \
+	stdio/logger2.c \
 	fault/fault1.c \
 	fault/fault2.c \
Index: uspace/app/tester/stdio/logger1.c
===================================================================
--- uspace/app/tester/stdio/logger1.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/app/tester/stdio/logger1.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <io/log.h>
+#include "../tester.h"
+
+const char *test_logger1(void)
+{
+	for (log_level_t level = 0; level < LVL_LIMIT; level++) {
+		log_msg(level, "Testing logger, level %d.", (int) level);
+	}
+
+	return NULL;
+}
Index: uspace/app/tester/stdio/logger1.def
===================================================================
--- uspace/app/tester/stdio/logger1.def	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/app/tester/stdio/logger1.def	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,6 @@
+{
+	"logger1",
+	"Logger printing test",
+	&test_logger1,
+	true
+},
Index: uspace/app/tester/stdio/logger2.c
===================================================================
--- uspace/app/tester/stdio/logger2.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/app/tester/stdio/logger2.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <io/log.h>
+#include <async.h>
+#include "../tester.h"
+
+const char *test_logger2(void)
+{
+	log_t log_alpha = log_create("alpha", LOG_DEFAULT);
+	log_t log_bravo = log_create("bravo", log_alpha);
+
+	TPRINTF("Alpha is %" PRIlogctx ".\n", log_alpha);
+	TPRINTF("Bravo is %" PRIlogctx ".\n", log_bravo);
+
+	while (true) {
+		/*
+		 * Intentionally skipping FATAL to allow muting
+		 * the output completely by setting visible level to FATAL.
+		 */
+		for (log_level_t level = LVL_ERROR; level < LVL_LIMIT; level++) {
+			log_msg(level, "Printing level %d (%s).",
+			    (int) level, log_level_str(level));
+			log_log_msg(log_alpha, level,
+			    "Printing level %d (%s) into alpha log.",
+			    (int) level, log_level_str(level));
+			log_log_msg(log_bravo, level,
+			    "Printing level %d (%s) into bravo sub-log.",
+			    (int) level, log_level_str(level));
+			async_usleep(1000 * 100);
+		}
+	}
+
+	return NULL;
+}
Index: uspace/app/tester/stdio/logger2.def
===================================================================
--- uspace/app/tester/stdio/logger2.def	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/app/tester/stdio/logger2.def	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,6 @@
+{
+	"logger2",
+	"Logger endless test",
+	&test_logger2,
+	false
+},
Index: uspace/app/tester/tester.c
===================================================================
--- uspace/app/tester/tester.c	(revision ad780544d441f9ddecd38ab48b2e79bcea7123cb)
+++ uspace/app/tester/tester.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -39,4 +39,5 @@
 #include <stdio.h>
 #include <str.h>
+#include <io/log.h>
 #include "tester.h"
 
@@ -55,4 +56,6 @@
 #include "stdio/stdio1.def"
 #include "stdio/stdio2.def"
+#include "stdio/logger1.def"
+#include "stdio/logger2.def"
 #include "fault/fault1.def"
 #include "fault/fault2.def"
@@ -138,4 +141,6 @@
 	}
 	
+	log_init("tester", LVL_NOTE);
+
 	test_quiet = false;
 	test_argc = argc - 2;
Index: uspace/app/tester/tester.h
===================================================================
--- uspace/app/tester/tester.h	(revision ad780544d441f9ddecd38ab48b2e79bcea7123cb)
+++ uspace/app/tester/tester.h	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -88,4 +88,6 @@
 extern const char *test_stdio1(void);
 extern const char *test_stdio2(void);
+extern const char *test_logger1(void);
+extern const char *test_logger2(void);
 extern const char *test_fault1(void);
 extern const char *test_fault2(void);
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision ad780544d441f9ddecd38ab48b2e79bcea7123cb)
+++ uspace/lib/c/Makefile	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -100,4 +100,5 @@
 	generic/io/printf.c \
 	generic/io/log.c \
+	generic/io/logctl.c \
 	generic/io/klog.c \
 	generic/io/snprintf.c \
Index: uspace/lib/c/generic/io/log.c
===================================================================
--- uspace/lib/c/generic/io/log.c	(revision ad780544d441f9ddecd38ab48b2e79bcea7123cb)
+++ uspace/lib/c/generic/io/log.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -38,26 +38,97 @@
 #include <stdlib.h>
 #include <stdio.h>
-
+#include <async.h>
 #include <io/log.h>
-
-/** Serialization mutex for logging functions. */
-static FIBRIL_MUTEX_INITIALIZE(log_serializer);
-
-/** Current log level. */
-static log_level_t log_level;
-
-static FILE *log_stream;
-
+#include <ipc/logger.h>
+#include <ns.h>
+
+static sysarg_t default_log_id;
+
+/** Log messages are printed under this name. */
 static const char *log_prog_name;
 
-/** Prefixes for individual logging levels. */
 static const char *log_level_names[] = {
-	[LVL_FATAL] = "Fatal error",
-	[LVL_ERROR] = "Error",
-	[LVL_WARN] = "Warning",
-	[LVL_NOTE] = "Note",
-	[LVL_DEBUG] = "Debug",
-	[LVL_DEBUG2] = "Debug2"
+	"fatal",
+	"error",
+	"warn",
+	"note",
+	"debug",
+	"debug2",
+	NULL
 };
+
+/** IPC session with the logger service. */
+static async_sess_t *logger_session;
+
+/** Maximum length of a single log message (in bytes). */
+#define MESSAGE_BUFFER_SIZE 4096
+
+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);
+	if (exchange == NULL) {
+		return ENOMEM;
+	}
+	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;
+	async_wait_for(reg_msg, &reg_msg_rc);
+
+	async_exchange_end(exchange);
+
+	/*
+	 * Getting ENAK means no-one wants our message. That is not an
+	 * error at all.
+	 */
+	if (rc == ENAK)
+		rc = EOK;
+
+	if (rc != EOK) {
+		return rc;
+	}
+
+	return reg_msg_rc;
+}
+
+const char *log_level_str(log_level_t level)
+{
+	if (level >= LVL_LIMIT)
+		return "unknown";
+	else
+		return log_level_names[level];
+}
+
+int log_level_from_str(const char *name, log_level_t *level_out)
+{
+	log_level_t level = LVL_FATAL;
+
+	while (log_level_names[level] != NULL) {
+		if (str_cmp(name, log_level_names[level]) == 0) {
+			if (level_out != NULL)
+				*level_out = level;
+			return EOK;
+		}
+		level++;
+	}
+
+	/* Maybe user specified number directly. */
+	char *end_ptr;
+	int level_int = strtol(name, &end_ptr, 0);
+	if ((end_ptr == name) || (str_length(end_ptr) != 0))
+		return EINVAL;
+	if (level_int < 0)
+		return ERANGE;
+	if (level_int >= (int) LVL_LIMIT)
+		return ERANGE;
+
+	if (level_out != NULL)
+		*level_out = (log_level_t) level_int;
+
+	return EOK;
+}
 
 /** Initialize the logging system.
@@ -69,12 +140,50 @@
 {
 	assert(level < LVL_LIMIT);
-	log_level = level;
-
-	log_stream = stdout;
+
 	log_prog_name = str_dup(prog_name);
 	if (log_prog_name == NULL)
 		return ENOMEM;
 
+	logger_session = service_connect_blocking(EXCHANGE_SERIALIZE, SERVICE_LOGGER, LOGGER_INTERFACE_WRITER, 0);
+	if (logger_session == NULL) {
+		return ENOMEM;
+	}
+
+	default_log_id = log_create(prog_name, LOG_NO_PARENT);
+
 	return EOK;
+}
+
+/** Create a new (sub-) log.
+ *
+ * This function always returns a valid log_t. In case of errors,
+ * @c parent is returned and errors are silently ignored.
+ *
+ * @param name Log name under which message will be reported (appended to parents name).
+ * @param parent Parent log.
+ * @return Opaque identifier of the newly created log.
+ */
+log_t log_create(const char *name, log_t parent)
+{
+	async_exch_t *exchange = async_exchange_begin(logger_session);
+	if (exchange == NULL)
+		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_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);
+
+	async_exchange_end(exchange);
+
+	if ((rc != EOK) || (reg_msg_rc != EOK))
+		return parent;
+
+	return IPC_GET_ARG1(answer);
 }
 
@@ -86,10 +195,10 @@
  * @param fmt		Format string (no traling newline).
  */
-void log_msg(log_level_t level, const char *fmt, ...)
+void log_log_msg(log_t ctx, log_level_t level, const char *fmt, ...)
 {
 	va_list args;
 
 	va_start(args, fmt);
-	log_msgv(level, fmt, args);
+	log_log_msgv(ctx, level, fmt, args);
 	va_end(args);
 }
@@ -102,20 +211,15 @@
  * @param fmt		Format string (no trailing newline)
  */
-void log_msgv(log_level_t level, const char *fmt, va_list args)
+void log_log_msgv(log_t ctx, log_level_t level, const char *fmt, va_list args)
 {
 	assert(level < LVL_LIMIT);
 
-	/* Higher number means higher verbosity. */
-	if (level <= log_level) {
-		fibril_mutex_lock(&log_serializer);
-
-		fprintf(log_stream, "%s: %s: ", log_prog_name,
-		    log_level_names[level]);
-		vfprintf(log_stream, fmt, args);
-		fputc('\n', log_stream);
-		fflush(log_stream);
-
-		fibril_mutex_unlock(&log_serializer);
-	}
+	char *message_buffer = malloc(MESSAGE_BUFFER_SIZE);
+	if (message_buffer == NULL) {
+		return;
+	}
+
+	vsnprintf(message_buffer, MESSAGE_BUFFER_SIZE, fmt, args);
+	logger_message(logger_session, ctx, level, message_buffer);
 }
 
Index: uspace/lib/c/generic/io/logctl.c
===================================================================
--- uspace/lib/c/generic/io/logctl.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/lib/c/generic/io/logctl.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,105 @@
+/*
+ * 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 libc
+ * @{
+ */
+
+#include <assert.h>
+#include <unistd.h>
+#include <errno.h>
+#include <io/logctl.h>
+#include <ipc/logger.h>
+#include <sysinfo.h>
+#include <ns.h>
+#include <str.h>
+
+/** IPC session with the logger service. */
+static async_sess_t *logger_session = NULL;
+
+static int start_logger_exchange(async_exch_t **exchange_out)
+{
+	assert(exchange_out != NULL);
+
+	if (logger_session == NULL) {
+		logger_session = service_connect_blocking(EXCHANGE_SERIALIZE,
+		    SERVICE_LOGGER, LOGGER_INTERFACE_CONTROL, 0);
+		if (logger_session == NULL)
+			return ENOMEM;
+	}
+
+	assert(logger_session != NULL);
+
+	async_exch_t *exchange = async_exchange_begin(logger_session);
+	if (exchange == NULL)
+		return ENOMEM;
+
+	*exchange_out = exchange;
+
+	return EOK;
+}
+
+
+int logctl_set_default_level(log_level_t new_level)
+{
+	async_exch_t *exchange = NULL;
+	int rc = start_logger_exchange(&exchange);
+	if (rc != EOK)
+		return rc;
+
+	rc = (int) async_req_1_0(exchange,
+	    LOGGER_CONTROL_SET_DEFAULT_LEVEL, new_level);
+
+	async_exchange_end(exchange);
+
+	return rc;
+}
+
+int logctl_set_log_level(const char *logname, 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_CONTROL_SET_LOG_LEVEL,
+	    new_level, NULL);
+	rc = async_data_write_start(exchange, logname, str_size(logname));
+	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;
+}
+
+/** @}
+ */
Index: uspace/lib/c/include/io/log.h
===================================================================
--- uspace/lib/c/include/io/log.h	(revision ad780544d441f9ddecd38ab48b2e79bcea7123cb)
+++ uspace/lib/c/include/io/log.h	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -36,4 +36,6 @@
 
 #include <stdarg.h>
+#include <inttypes.h>
+#include <bool.h>
 
 typedef enum {
@@ -49,7 +51,22 @@
 } log_level_t;
 
+typedef sysarg_t log_t;
+#define PRIlogctx PRIxn
+#define LOG_DEFAULT ((log_t) -1)
+#define LOG_NO_PARENT ((log_t) 0)
+
+extern const char *log_level_str(log_level_t);
+extern int log_level_from_str(const char *, log_level_t *);
+
 extern int log_init(const char *, log_level_t);
-extern void log_msg(log_level_t, const char *, ...);
-extern void log_msgv(log_level_t, const char *, va_list);
+extern log_t log_create(const char *, log_t);
+
+#define log_msg(level, format, ...) \
+	log_log_msg(LOG_DEFAULT, (level), (format), ##__VA_ARGS__)
+#define log_msgv(level, format, args) \
+	log_log_msgv(LOG_DEFAULT, (level), (format), (args))
+
+extern void log_log_msg(log_t, log_level_t, const char *, ...);
+extern void log_log_msgv(log_t, log_level_t, const char *, va_list);
 
 #endif
Index: uspace/lib/c/include/io/logctl.h
===================================================================
--- uspace/lib/c/include/io/logctl.h	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/lib/c/include/io/logctl.h	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2011-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 libc
+ * @{
+ */
+
+#ifndef LIBC_IO_LOGCTL_H_
+#define LIBC_IO_LOGCTL_H_
+
+#include <io/log.h>
+
+extern int logctl_set_default_level(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 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/lib/c/include/ipc/logger.h	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,81 @@
+/*
+ * 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 libc
+ * @{
+ */
+
+#ifndef LIBC_IPC_LOGGER_H_
+#define LIBC_IPC_LOGGER_H_
+
+#include <ipc/common.h>
+
+typedef enum {
+	/** Set (global) default displayed logging level.
+	 *
+	 * Arguments: new log level.
+	 * Returns: error code
+	 */
+	LOGGER_CONTROL_SET_DEFAULT_LEVEL = IPC_FIRST_USER_METHOD,
+	/** Set displayed level for given log.
+	 *
+	 * Arguments: new log level.
+	 * Returns: error code
+	 * Followed by: string with full log name.
+	 */
+	LOGGER_CONTROL_SET_LOG_LEVEL
+} logger_control_request_t;
+
+typedef enum {
+	/** Create new log.
+	 *
+	 * Arguments: parent log id (0 for top-level log).
+	 * Returns: error code, log id
+	 * Followed by: string with log name.
+	 */
+	LOGGER_WRITER_CREATE_LOG = IPC_FIRST_USER_METHOD,
+	/** Write a message to a given log.
+	 *
+	 * Arguments: log id, message severity level (log_level_t)
+	 * Returns: error code
+	 * Followed by: string with the message.
+	 */
+	LOGGER_WRITER_MESSAGE
+} logger_writer_request_t;
+
+typedef enum {
+	/** Interface for controlling logger behavior. */
+	LOGGER_INTERFACE_CONTROL,
+	/** Interface for servers writing to the log. */
+	LOGGER_INTERFACE_WRITER
+} logger_interface_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/ipc/services.h
===================================================================
--- uspace/lib/c/include/ipc/services.h	(revision ad780544d441f9ddecd38ab48b2e79bcea7123cb)
+++ uspace/lib/c/include/ipc/services.h	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -45,4 +45,5 @@
 	SERVICE_VFS        = FOURCC('v', 'f', 's', ' '),
 	SERVICE_LOC        = FOURCC('l', 'o', 'c', ' '),
+	SERVICE_LOGGER     = FOURCC('l', 'o', 'g', 'g'),
 	SERVICE_DEVMAN     = FOURCC('d', 'e', 'v', 'n'),
 	SERVICE_IRC        = FOURCC('i', 'r', 'c', ' '),
Index: uspace/lib/usb/src/debug.c
===================================================================
--- uspace/lib/usb/src/debug.c	(revision ad780544d441f9ddecd38ab48b2e79bcea7123cb)
+++ uspace/lib/usb/src/debug.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -74,4 +74,5 @@
 		}
 	}
+	log_init(message_prefix, LVL_DEBUG);
 }
 
@@ -148,4 +149,8 @@
 	}
 
+	va_start(args, format);
+	log_msgv(level, format, args);
+	va_end(args);
+
 	fibril_mutex_unlock(&log_serializer);
 }
Index: uspace/srv/logger/Makefile
===================================================================
--- uspace/srv/logger/Makefile	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/srv/logger/Makefile	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,41 @@
+#
+# 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.
+#
+
+USPACE_PREFIX = ../..
+BINARY = logger
+STATIC_NEEDED = y
+
+SOURCES = \
+	ctl.c \
+	initlvl.c \
+	level.c \
+	logs.c \
+	main.c \
+	writer.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/logger/ctl.c
===================================================================
--- uspace/srv/logger/ctl.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/srv/logger/ctl.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,100 @@
+/*
+ * 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
+ * @{
+ */
+
+/** @file
+ */
+
+#include <unistd.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <errno.h>
+#include <io/logctl.h>
+#include <ipc/logger.h>
+#include "logger.h"
+
+static int handle_log_level_change(sysarg_t new_level)
+{
+	void *full_name;
+	int rc = async_data_write_accept(&full_name, true, 0, 0, 0, NULL);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	logger_log_t *log = find_log_by_name_and_acquire(full_name);
+	free(full_name);
+	if (log == NULL)
+		return ENOENT;
+
+	log->logged_level = new_level;
+
+	log_release(log);
+
+	return EOK;
+}
+
+void logger_connection_handler_control(ipc_callid_t callid)
+{
+	async_answer_0(callid, EOK);
+	printf(NAME "/control: new client.\n");
+
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+
+		if (!IPC_GET_IMETHOD(call))
+			break;
+
+		switch (IPC_GET_IMETHOD(call)) {
+		case LOGGER_CONTROL_SET_DEFAULT_LEVEL: {
+			int rc = set_default_logging_level(IPC_GET_ARG1(call));
+			async_answer_0(callid, rc);
+			break;
+		}
+		case LOGGER_CONTROL_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);
+			break;
+		}
+	}
+
+	printf(NAME "/control: client terminated.\n");
+}
+
+
+/**
+ * @}
+ */
Index: uspace/srv/logger/initlvl.c
===================================================================
--- uspace/srv/logger/initlvl.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/srv/logger/initlvl.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,98 @@
+/*
+ * 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
+ * @{
+ */
+
+/** @file
+ */
+#include <errno.h>
+#include <str_error.h>
+#include <sysinfo.h>
+#include <str.h>
+#include "logger.h"
+
+static void parse_single_level_setting(char *setting)
+{
+	char *tmp;
+	char *key = strtok_r(setting, "=", &tmp);
+	char *value = strtok_r(NULL, "=", &tmp);
+	if (key == NULL)
+		return;
+	if (value == NULL) {
+		log_level_t level;
+		int rc = log_level_from_str(key, &level);
+		if (rc != EOK)
+			return;
+		set_default_logging_level(level);
+		return;
+	}
+
+
+	log_level_t level;
+	int rc = log_level_from_str(value, &level);
+	if (rc != EOK)
+		return;
+
+	logger_log_t *log = find_or_create_log_and_acquire(key, 0);
+	if (log == NULL)
+		return;
+
+	log->logged_level = level;
+
+	log_release(log);
+}
+
+void parse_level_settings(char *settings)
+{
+	char *tmp;
+	char *single_setting = strtok_r(settings, " ", &tmp);
+	while (single_setting != NULL) {
+		parse_single_level_setting(single_setting);
+		single_setting = strtok_r(NULL, " ", &tmp);
+	}
+}
+
+void parse_initial_settings(void)
+{
+	size_t argument_size;
+	void *argument = sysinfo_get_data("init_args.logger", &argument_size);
+	if (argument == NULL)
+		return;
+
+	char level_str[200];
+	str_cpy(level_str, 200, (const char *) argument);
+
+	parse_level_settings(level_str);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/logger/level.c
===================================================================
--- uspace/srv/logger/level.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/srv/logger/level.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,63 @@
+/*
+ * 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
+ * @{
+ */
+
+/** @file
+ */
+
+#include <errno.h>
+#include "logger.h"
+
+log_level_t default_logging_level = LVL_NOTE;
+static FIBRIL_MUTEX_INITIALIZE(default_logging_level_guard);
+
+log_level_t get_default_logging_level(void)
+{
+	fibril_mutex_lock(&default_logging_level_guard);
+	log_level_t result = default_logging_level;
+	fibril_mutex_unlock(&default_logging_level_guard);
+	return result;
+}
+
+int set_default_logging_level(log_level_t new_level)
+{
+	if (new_level >= LVL_LIMIT)
+		return ERANGE;
+	fibril_mutex_lock(&default_logging_level_guard);
+	default_logging_level = new_level;
+	fibril_mutex_unlock(&default_logging_level_guard);
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/logger/logger.h
===================================================================
--- uspace/srv/logger/logger.h	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/srv/logger/logger.h	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,90 @@
+/*
+ * 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
+ * @{
+ */
+/** @file Common logger service definitions.
+ */
+
+#ifndef LOGGER_H_
+#define LOGGER_H_
+
+#include <adt/list.h>
+#include <adt/prodcons.h>
+#include <io/log.h>
+#include <async.h>
+#include <bool.h>
+#include <fibril_synch.h>
+#include <stdio.h>
+
+#define NAME "logger"
+#define MAX_SUBLOGS 64
+#define LOG_LEVEL_USE_DEFAULT (LVL_LIMIT + 1)
+
+typedef struct logger_log logger_log_t;
+
+typedef struct {
+	fibril_mutex_t guard;
+	char *filename;
+	FILE *logfile;
+} logger_dest_t;
+
+struct logger_log {
+	link_t link;
+
+	fibril_mutex_t guard;
+
+	char *name;
+	char *full_name;
+	logger_log_t *parent;
+	log_level_t logged_level;
+	logger_dest_t *dest;
+};
+
+logger_log_t *find_log_by_name_and_acquire(const char *name);
+logger_log_t *find_or_create_log_and_acquire(const char *, sysarg_t);
+logger_log_t *find_log_by_id_and_acquire(sysarg_t);
+bool shall_log_message(logger_log_t *, log_level_t);
+void log_release(logger_log_t *);
+void write_to_log(logger_log_t *, log_level_t, const char *);
+
+log_level_t get_default_logging_level(void);
+int set_default_logging_level(log_level_t);
+
+
+void logger_connection_handler_control(ipc_callid_t);
+void logger_connection_handler_writer(ipc_callid_t);
+
+void parse_initial_settings(void);
+void parse_level_settings(char *);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/logger/logs.c
===================================================================
--- uspace/srv/logger/logs.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/srv/logger/logs.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,223 @@
+/*
+ * 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(log_list_guard);
+static LIST_INITIALIZE(log_list);
+
+
+static logger_log_t *find_log_by_name_and_parent_no_list_lock(const char *name, logger_log_t *parent)
+{
+	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;
+	}
+
+	return NULL;
+}
+
+static int create_dest(const char *name, logger_dest_t **dest)
+{
+	logger_dest_t *result = malloc(sizeof(logger_dest_t));
+	if (result == NULL)
+		return ENOMEM;
+	int rc = asprintf(&result->filename, "/log/%s", name);
+	if (rc < 0) {
+		free(result);
+		return ENOMEM;
+	}
+	result->logfile = NULL;
+	fibril_mutex_initialize(&result->guard);
+	*dest = result;
+	return EOK;
+}
+
+static logger_log_t *create_log_no_locking(const char *name, logger_log_t *parent)
+{
+	logger_log_t *result = calloc(1, sizeof(logger_log_t));
+	if (result == NULL)
+		return NULL;
+
+	result->name = str_dup(name);
+	if (result->name == NULL)
+		goto error;
+
+	/*
+	 * Notice that we create new dest as the last
+	 * operation that can fail and thus there is no code
+	 * to deallocate dest.
+	 */
+	if (parent == NULL) {
+		result->full_name = str_dup(name);
+		if (result->full_name == NULL)
+			goto error;
+		int rc = create_dest(name, &result->dest);
+		if (rc != EOK)
+			goto error;
+	} else {
+		int rc = asprintf(&result->full_name, "%s/%s",
+		    parent->full_name, name);
+		if (rc < 0)
+			goto error;
+		result->dest = parent->dest;
+	}
+
+	/* Following initializations cannot fail. */
+	result->logged_level = LOG_LEVEL_USE_DEFAULT;
+	fibril_mutex_initialize(&result->guard);
+	link_initialize(&result->link);
+	result->parent = parent;
+
+	return result;
+
+error:
+	free(result->name);
+	free(result->full_name);
+	free(result);
+	return NULL;
+
+}
+
+logger_log_t *find_or_create_log_and_acquire(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_list_lock(name, parent);
+	if (result == NULL) {
+		result = create_log_no_locking(name, parent);
+		if (result == NULL)
+			goto leave;
+	}
+
+	fibril_mutex_lock(&result->guard);
+
+	list_append(&result->link, &log_list);
+
+leave:
+	fibril_mutex_unlock(&log_list_guard);
+
+	return result;
+}
+
+logger_log_t *find_log_by_name_and_acquire(const char *name)
+{
+	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 (str_cmp(log->full_name, name) == 0) {
+			fibril_mutex_lock(&log->guard);
+			result = log;
+			break;
+		}
+	}
+	fibril_mutex_unlock(&log_list_guard);
+
+	return result;
+}
+
+logger_log_t *find_log_by_id_and_acquire(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) {
+			fibril_mutex_lock(&log->guard);
+			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)
+{
+	fibril_mutex_lock(&log_list_guard);
+	bool result = level <= get_actual_log_level(log);
+	fibril_mutex_unlock(&log_list_guard);
+	return result;
+}
+
+void log_release(logger_log_t *log)
+{
+	assert(fibril_mutex_is_locked(&log->guard));
+	fibril_mutex_unlock(&log->guard);
+}
+
+void write_to_log(logger_log_t *log, log_level_t level, const char *message)
+{
+	assert(fibril_mutex_is_locked(&log->guard));
+	assert(log->dest != NULL);
+	fibril_mutex_lock(&log->dest->guard);
+	if (log->dest->logfile == NULL)
+		log->dest->logfile = fopen(log->dest->filename, "a");
+
+	if (log->dest->logfile != NULL) {
+		fprintf(log->dest->logfile, "[%s] %s: %s\n",
+		    log->full_name, log_level_str(level),
+		    (const char *) message);
+		fflush(log->dest->logfile);
+	}
+
+	fibril_mutex_unlock(&log->dest->guard);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/logger/main.c
===================================================================
--- uspace/srv/logger/main.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/srv/logger/main.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup logger Logging service.
+ * @brief HelenOS logging service.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <ipc/services.h>
+#include <ipc/logger.h>
+#include <io/log.h>
+#include <io/logctl.h>
+#include <ns.h>
+#include <async.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+#include <malloc.h>
+#include "logger.h"
+
+static void connection_handler(ipc_callid_t iid, ipc_call_t *icall, void *arg)
+{
+	logger_interface_t iface = IPC_GET_ARG1(*icall);
+
+	switch (iface) {
+	case LOGGER_INTERFACE_CONTROL:
+		logger_connection_handler_control(iid);
+		break;
+	case LOGGER_INTERFACE_WRITER:
+		logger_connection_handler_writer(iid);
+		break;
+	default:
+		async_answer_0(iid, EINVAL);
+		break;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS Logging Service\n");
+	
+	parse_initial_settings();
+	for (int i = 1; i < argc; i++) {
+		parse_level_settings(argv[i]);
+	}
+
+	async_set_client_connection(connection_handler);
+	
+	int rc = service_register(SERVICE_LOGGER);
+	if (rc != EOK) {
+		printf(NAME ": failed to register: %s.\n", str_error(rc));
+		return -1;
+	}
+	
+	printf(NAME ": Accepting connections\n");
+	async_manager();
+	
+	/* Never reached */
+	return 0;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/logger/writer.c
===================================================================
--- uspace/srv/logger/writer.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
+++ uspace/srv/logger/writer.c	(revision 52c4264a632a597d2252dcb23b0c56f28a711f57)
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+/**
+ * @defgroup logger Logging service.
+ * @brief HelenOS logging service.
+ * @{
+ */
+
+/** @file
+ */
+
+#include <ipc/services.h>
+#include <ipc/logger.h>
+#include <io/log.h>
+#include <io/logctl.h>
+#include <ns.h>
+#include <async.h>
+#include <stdio.h>
+#include <errno.h>
+#include <str_error.h>
+#include <malloc.h>
+#include "logger.h"
+
+
+static logger_log_t *handle_create_log(sysarg_t parent)
+{
+	void *name;
+	int rc = async_data_write_accept(&name, true, 1, 0, 0, NULL);
+	if (rc != EOK)
+		return NULL;
+
+	logger_log_t *log = find_or_create_log_and_acquire(name, parent);
+
+	free(name);
+
+	return log;
+}
+
+static int handle_receive_message(sysarg_t log_id, sysarg_t level)
+{
+	logger_log_t *log = find_log_by_id_and_acquire(log_id);
+	if (log == NULL)
+		return ENOENT;
+
+	void *message = NULL;
+	int rc = async_data_write_accept(&message, true, 1, 0, 0, NULL);
+	if (rc != EOK)
+		goto leave;
+
+	if (!shall_log_message(log, level)) {
+		rc = EOK;
+		goto leave;
+	}
+
+	printf("[%s] %s: %s\n",
+	    log->full_name, log_level_str(level),
+	    (const char *) message);
+	write_to_log(log, level, message);
+
+	rc = EOK;
+
+leave:
+	log_release(log);
+	free(message);
+
+	return rc;
+}
+
+void logger_connection_handler_writer(ipc_callid_t callid)
+{
+	/* Acknowledge the connection. */
+	async_answer_0(callid, EOK);
+
+	printf(NAME "/writer: new client.\n");
+
+	while (true) {
+		ipc_call_t call;
+		ipc_callid_t callid = async_get_call(&call);
+
+		if (!IPC_GET_IMETHOD(call))
+			break;
+
+		switch (IPC_GET_IMETHOD(call)) {
+		case LOGGER_WRITER_CREATE_LOG: {
+			logger_log_t *log = handle_create_log(IPC_GET_ARG1(call));
+			if (log == NULL) {
+				async_answer_0(callid, ENOMEM);
+				break;
+			}
+			log_release(log);
+			async_answer_1(callid, EOK, (sysarg_t) log);
+			break;
+		}
+		case LOGGER_WRITER_MESSAGE: {
+			int rc = handle_receive_message(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			async_answer_0(callid, rc);
+			break;
+		}
+		default:
+			async_answer_0(callid, EINVAL);
+			break;
+		}
+	}
+
+	// FIXME: destroy created logs
+}
+
+
+/**
+ * @}
+ */
