Index: uspace/lib/c/generic/io/log.c
===================================================================
--- uspace/lib/c/generic/io/log.c	(revision 9a53e00d21d11ebcac23b5de1783fa861621d871)
+++ uspace/lib/c/generic/io/log.c	(revision 793cce1509684caa2f8b40f1adea9f76df2cda74)
@@ -86,5 +86,5 @@
 }
 
-static int logger_message(async_sess_t *session, log_level_t level, const char *message)
+static int logger_message(async_sess_t *session, log_context_t ctx, log_level_t level, const char *message)
 {
 	async_exch_t *exchange = async_exchange_begin(session);
@@ -93,5 +93,6 @@
 	}
 
-	aid_t reg_msg = async_send_1(exchange, LOGGER_MESSAGE, level, NULL);
+	aid_t reg_msg = async_send_2(exchange, LOGGER_MESSAGE,
+	    ctx, level, NULL);
 	int rc = async_data_write_start(exchange, message, str_size(message));
 	sysarg_t reg_msg_rc;
@@ -241,5 +242,29 @@
 }
 
-bool _log_shall_record(log_level_t level)
+/** Create logging context.
+ *
+ * This function always returns a valid context.
+ */
+log_context_t log_context_create(const char *name)
+{
+	async_exch_t *exchange = async_exchange_begin(logger_session);
+	if (exchange == NULL)
+		return LOG_CONTEXT_DEFAULT;
+
+	ipc_call_t answer;
+	aid_t reg_msg = async_send_0(exchange, LOGGER_CREATE_CONTEXT, &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 LOG_CONTEXT_DEFAULT;
+
+	return IPC_GET_ARG1(answer);
+}
+
+bool _log_shall_record(log_context_t context, log_level_t level)
 {
 	return get_current_observed_level() >= level;
@@ -253,10 +278,10 @@
  * @param fmt		Format string (no traling newline).
  */
-void _log_msg(log_level_t level, const char *fmt, ...)
+void _log_ctx_msg(log_context_t ctx, log_level_t level, const char *fmt, ...)
 {
 	va_list args;
 
 	va_start(args, fmt);
-	_log_msgv(level, fmt, args);
+	_log_ctx_msgv(ctx, level, fmt, args);
 	va_end(args);
 }
@@ -269,5 +294,5 @@
  * @param fmt		Format string (no trailing newline)
  */
-void _log_msgv(log_level_t level, const char *fmt, va_list args)
+void _log_ctx_msgv(log_context_t ctx, log_level_t level, const char *fmt, va_list args)
 {
 	assert(level < LVL_LIMIT);
@@ -283,5 +308,5 @@
 
 	vsnprintf(message_buffer, MESSAGE_BUFFER_SIZE, fmt, args);
-	logger_message(logger_session, level, message_buffer);
+	logger_message(logger_session, ctx, level, message_buffer);
 }
 
Index: uspace/lib/c/include/io/log.h
===================================================================
--- uspace/lib/c/include/io/log.h	(revision 9a53e00d21d11ebcac23b5de1783fa861621d871)
+++ uspace/lib/c/include/io/log.h	(revision 793cce1509684caa2f8b40f1adea9f76df2cda74)
@@ -36,4 +36,5 @@
 
 #include <stdarg.h>
+#include <inttypes.h>
 #include <bool.h>
 
@@ -50,26 +51,37 @@
 } log_level_t;
 
+typedef sysarg_t log_context_t;
+#define PRIlogctx PRIxn
+#define LOG_CONTEXT_DEFAULT 0
+
 extern const char *log_level_str(log_level_t);
 extern int log_level_from_str(const char *, log_level_t *);
 
-extern bool _log_shall_record(log_level_t);
+extern bool _log_shall_record(log_context_t, log_level_t);
 extern int log_init(const char *, log_level_t);
 
-#define log_msg(level, format, ...) \
+extern log_context_t log_context_create(const char *);
+
+#define log_ctx_msg(context, level, format, ...) \
 	do { \
-		if (_log_shall_record((level))) { \
-			_log_msg(level, format, ##__VA_ARGS__); \
+		if (_log_shall_record((context), (level))) { \
+			_log_ctx_msg((context), (level), format, ##__VA_ARGS__); \
 		} \
 	} while (false)
 
-#define log_msgv(level, format, args) \
+#define log_ctx_msgv(context, level, format, args) \
 	do { \
-		if (_log_shall_record((level))) { \
-			_log_msgv(level, format, args); \
+		if (_log_shall_record((context), (level))) { \
+			_log_ctx_msgv((context), (level), format, args); \
 		} \
 	} while (false)
 
-extern void _log_msg(log_level_t, const char *, ...);
-extern void _log_msgv(log_level_t, const char *, va_list);
+#define log_msg(level, format, ...) \
+	log_ctx_msg(LOG_CONTEXT_DEFAULT, (level), (format), ##__VA_ARGS__)
+#define log_msgv(level, format, args) \
+	log_ctx_msgv(LOG_CONTEXT_DEFAULT, (level), (format), (args))
+
+extern void _log_ctx_msg(log_context_t, log_level_t, const char *, ...);
+extern void _log_ctx_msgv(log_context_t, log_level_t, const char *, va_list);
 
 #endif
Index: uspace/lib/c/include/ipc/logger.h
===================================================================
--- uspace/lib/c/include/ipc/logger.h	(revision 9a53e00d21d11ebcac23b5de1783fa861621d871)
+++ uspace/lib/c/include/ipc/logger.h	(revision 793cce1509684caa2f8b40f1adea9f76df2cda74)
@@ -44,4 +44,5 @@
 typedef enum {
 	LOGGER_REGISTER = IPC_FIRST_USER_METHOD,
+	LOGGER_CREATE_CONTEXT,
 	LOGGER_MESSAGE,
 	LOGGER_BLOCK_UNTIL_READER_CHANGED
Index: uspace/srv/logger/logger.h
===================================================================
--- uspace/srv/logger/logger.h	(revision 9a53e00d21d11ebcac23b5de1783fa861621d871)
+++ uspace/srv/logger/logger.h	(revision 793cce1509684caa2f8b40f1adea9f76df2cda74)
@@ -57,6 +57,8 @@
 
 void namespace_wait_for_reader_change(logging_namespace_t *, bool *);
-bool namespace_has_reader(logging_namespace_t *, log_level_t);
-void namespace_add_message(logging_namespace_t *, const char *, log_level_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 *);
 
 log_level_t get_default_logging_level(void);
Index: uspace/srv/logger/main.c
===================================================================
--- uspace/srv/logger/main.c	(revision 9a53e00d21d11ebcac23b5de1783fa861621d871)
+++ uspace/srv/logger/main.c	(revision 793cce1509684caa2f8b40f1adea9f76df2cda74)
@@ -126,7 +126,7 @@
 }
 
-static int handle_receive_message(logging_namespace_t *namespace, int level)
-{
-	bool skip_message = !namespace_has_reader(namespace, level);
+static int handle_receive_message(logging_namespace_t *namespace, sysarg_t context, int level)
+{
+	bool skip_message = !namespace_has_reader(namespace, context, level);
 	if (skip_message) {
 		/* Abort the actual message buffer transfer. */
@@ -147,8 +147,27 @@
 	}
 
-	namespace_add_message(namespace, message, level);
+	namespace_add_message(namespace, message, context, level);
 
 	free(message);
 
+	return EOK;
+}
+
+static int handle_create_context(logging_namespace_t *namespace, sysarg_t *idx)
+{
+	void *name;
+	int rc = async_data_write_accept(&name, true, 0, 0, 0, NULL);
+	if (rc != EOK) {
+		return rc;
+	}
+
+	rc = namespace_create_context(namespace, name);
+
+	free(name);
+
+	if (rc < 0)
+		return rc;
+
+	*idx = (sysarg_t) rc;
 	return EOK;
 }
@@ -166,8 +185,13 @@
 
 		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);
+			break;
 		case LOGGER_MESSAGE:
-			rc = handle_receive_message(namespace, IPC_GET_ARG1(call));
+			rc = handle_receive_message(namespace, IPC_GET_ARG1(call), IPC_GET_ARG2(call));
 			async_answer_0(callid, rc);
 			break;
Index: uspace/srv/logger/namespace.c
===================================================================
--- uspace/srv/logger/namespace.c	(revision 9a53e00d21d11ebcac23b5de1783fa861621d871)
+++ uspace/srv/logger/namespace.c	(revision 793cce1509684caa2f8b40f1adea9f76df2cda74)
@@ -41,4 +41,10 @@
  */
 
+#define CONTEXT_SIZE 16
+
+typedef struct {
+	const char *name;
+	log_level_t level;
+} logging_context_t;
 
 struct logging_namespace {
@@ -50,4 +56,8 @@
 	const char *name;
 
+	// FIXME: make dynamic
+	size_t context_count;
+	logging_context_t context[CONTEXT_SIZE];
+
 	link_t link;
 };
@@ -56,8 +66,12 @@
 static LIST_INITIALIZE(namespace_list);
 
-static log_level_t namespace_get_actual_log_level(logging_namespace_t *namespace)
-{
-	fibril_mutex_lock(&namespace->guard);
-	log_level_t level = namespace->level;
+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);
+		return LVL_FATAL;
+	}
+	log_level_t level = namespace->context[context].level;
 	fibril_mutex_unlock(&namespace->guard);
 
@@ -115,4 +129,8 @@
 	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);
 	fibril_condvar_initialize(&namespace->level_changed_cv);
@@ -206,4 +224,7 @@
 	fibril_mutex_lock(&namespace->guard);
 	namespace->level = level;
+	for (size_t i = 0; i < namespace->context_count; i++) {
+		namespace->context[i].level = level;
+	}
 	fibril_condvar_broadcast(&namespace->level_changed_cv);
 	fibril_mutex_unlock(&namespace->guard);
@@ -213,7 +234,33 @@
 
 
-bool namespace_has_reader(logging_namespace_t *namespace, log_level_t level)
-{
-	return level <= namespace_get_actual_log_level(namespace);
+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;
 }
 
@@ -230,10 +277,20 @@
 
 
-void namespace_add_message(logging_namespace_t *namespace, const char *message, log_level_t level)
-{
-	if (level <= namespace_get_actual_log_level(namespace)) {
+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);
-		printf("[%s %s]: %s\n", namespace->name, level_name, message);
-		fprintf(namespace->logfile, "%s: %s\n", level_name, message);
+		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);
