diff --git a/doc/components.txt b/doc/components.txt
index ae77ff8ec..6aee3f32b 100644
--- a/doc/components.txt
+++ b/doc/components.txt
@@ -314,6 +314,9 @@ Separate components:
:'os/src/server/terminal_log':
Adapter for forwarding LOG messages to a terminal session.
+:'libports/src/server/fs_log':
+ Adapter that writes LOG messages to files on a file system.
+
:'demo/src/server/nitlog':
Provides a LOG session, printing log output on screen via a nitpicker
session.
diff --git a/libports/src/server/fs_log/README b/libports/src/server/fs_log/README
new file mode 100644
index 000000000..315d96bbd
--- /dev/null
+++ b/libports/src/server/fs_log/README
@@ -0,0 +1,18 @@
+LOG server that writes log messages onto a file system.
+
+Using this component, log messages of different processes can be redirected
+to files on a file-system service. The assignment of processes to files can
+be expressed in the configuration as follows:
+
+!
+!
+!
+!
+!
+!
+!
+!
+
+In this example, all messages originating from the noux process are directed
+to the file '/noux.log'. All messages originating from children of the noux
+process end up in the file '/noux_process.log'.
diff --git a/libports/src/server/fs_log/main.cc b/libports/src/server/fs_log/main.cc
new file mode 100644
index 000000000..d7b485e46
--- /dev/null
+++ b/libports/src/server/fs_log/main.cc
@@ -0,0 +1,170 @@
+/*
+ * \brief LOG service that writes to a file
+ * \author Alexander Tarasikov
+ * \author Norman Feske
+ * \date 2013-05-07
+ */
+
+/*
+ * Copyright (C) 2013 Ksys Labs LLC
+ * Copyright (C) 2012-2013 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* libc includes */
+#include
+#include
+
+
+class Log_component : public Genode::Rpc_object
+{
+ public:
+
+ enum { LABEL_LEN = 64 };
+
+ private:
+
+ typedef Genode::size_t size_t;
+
+ char _label[LABEL_LEN];
+ size_t _label_len;
+ int _fd;
+
+ public:
+
+ /**
+ * Constructor
+ */
+ Log_component(const char *label, char const *filename)
+ :
+ _fd(::open(filename, O_CREAT | O_WRONLY | O_APPEND))
+ {
+ using namespace Genode;
+
+ if (_fd < 0) {
+ PERR("unable to open \"%s\"", filename);
+ throw Root::Unavailable();
+ }
+
+ snprintf(_label, LABEL_LEN, "[%s] ", label);
+ _label_len = strlen(_label);
+
+ PINF("log client \"%s\" to file \"%s\")", label, filename);
+ }
+
+ /**
+ * Destructor
+ */
+ ~Log_component() { ::close(_fd); }
+
+
+ /*****************
+ ** Log session **
+ *****************/
+
+ /**
+ * Write a log-message to the file.
+ */
+ size_t write(String const &string_buf)
+ {
+ if (!(string_buf.is_valid_string())) {
+ PERR("corrupted string");
+ return 0;
+ }
+
+ char const *string = string_buf.string();
+ Genode::size_t const len = Genode::strlen(string);
+
+ ::write(_fd, _label, _label_len);
+ ::write(_fd, string, len);
+
+ return len;
+ }
+};
+
+
+class Log_root : public Genode::Root_component
+{
+ private:
+
+ int _fd;
+
+ protected:
+
+ /**
+ * Root component interface
+ */
+ Log_component *_create_session(const char *args)
+ {
+ using namespace Genode;
+
+ char label_buf[Log_component::LABEL_LEN];
+ Arg label_arg = Arg_string::find_arg(args, "label");
+ label_arg.string(label_buf, sizeof(label_buf), "");
+
+ /* obtain file name from configured policy */
+ enum { FILENAME_MAX_LEN = 256 };
+ char filename[FILENAME_MAX_LEN];
+ try {
+ Session_policy policy(args);
+ policy.attribute("file").value(filename, sizeof(filename));
+ } catch (...) {
+ PERR("Invalid session request, no matching policy");
+ throw Root::Unavailable();
+ }
+
+ return new (md_alloc()) Log_component(label_buf, filename);
+ }
+
+ public:
+
+ /**
+ * Constructor
+ *
+ * \param session_ep entry point for managing cpu session objects
+ * \param md_alloc meta-data allocator to be used by root component
+ */
+ Log_root(Genode::Rpc_entrypoint *session_ep, Genode::Allocator *md_alloc)
+ : Genode::Root_component(session_ep, md_alloc) { }
+};
+
+
+int main(int argc, char **argv)
+{
+ using namespace Genode;
+
+ /*
+ * Initialize server entry point
+ *
+ * Use a large stack because we are calling libc functions from the
+ * context of the entrypoint.
+ */
+ enum { STACK_SIZE = sizeof(addr_t)*16*1024 };
+ static Cap_connection cap;
+ static Rpc_entrypoint ep(&cap, STACK_SIZE, "fs_log_ep");
+
+ static Log_root log_root(&ep, env()->heap());
+
+ /*
+ * Announce services
+ */
+ env()->parent()->announce(ep.manage(&log_root));
+
+ /**
+ * Got to sleep forever
+ */
+ sleep_forever();
+ return 0;
+}
diff --git a/libports/src/server/fs_log/target.mk b/libports/src/server/fs_log/target.mk
new file mode 100644
index 000000000..d3640b9a3
--- /dev/null
+++ b/libports/src/server/fs_log/target.mk
@@ -0,0 +1,3 @@
+TARGET = fs_log
+SRC_CC = main.cc
+LIBS = base libc_fs libc