diff --git a/Makefile.dep b/Makefile.dep
index 85facbec086ed29ef269891945974f0739580736..58642b82190dfcea72c6fec8e04e0d9245d2a4c8 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -249,3 +249,8 @@ endif
 ifneq (,$(filter ng_at86rf2%,$(USEMODULE)))
   USEMODULE += ng_at86rf2xx
 endif
+
+# if any log_* is used, also use LOG pseudomodule
+ifneq (,$(filter log_%,$(USEMODULE)))
+  USEMODULE += log
+endif
diff --git a/Makefile.pseudomodules b/Makefile.pseudomodules
index 9b6867efccd91a3fc520c871d51a45e09ee8e7ee..f23954e445e28f211eac473e1885c0d7b9e935ae 100644
--- a/Makefile.pseudomodules
+++ b/Makefile.pseudomodules
@@ -6,6 +6,8 @@ PSEUDOMODULES += ng_ipv6_router_default
 PSEUDOMODULES += pktqueue
 PSEUDOMODULES += ng_netbase
 PSEUDOMODULES += ng_sixlowpan_default
+PSEUDOMODULES += log
+PSEUDOMODULES += log_printfnoformat
 
 # include variants of the AT86RF2xx drivers as pseudo modules
 PSEUDOMODULES += ng_at86rf23%
diff --git a/core/hwtimer.c b/core/hwtimer.c
index 3c7152b458a2c675b647511ee62b696a3f3aa767..89e9e961696be9803c6c28ecd5ddb3dd19f7d16a 100644
--- a/core/hwtimer.c
+++ b/core/hwtimer.c
@@ -34,6 +34,8 @@
 #define ENABLE_DEBUG (0)
 #include "debug.h"
 
+#include "log.h"
+
 #include "hwtimer.h"
 #include "hwtimer_cpu.h"
 #include "arch/hwtimer_arch.h"
@@ -157,7 +159,7 @@ static int _hwtimer_set(unsigned long offset, void (*callback)(void*), void *ptr
     if (n == -1) {
         restoreIRQ(state);
 
-        puts("No hwtimer left.");
+        LOG_WARNING("No hwtimer left.");
         return -1;
     }
 
diff --git a/core/include/log.h b/core/include/log.h
new file mode 100644
index 0000000000000000000000000000000000000000..ecd1831f538db7bdb3a341472b6e91bc97ba4df4
--- /dev/null
+++ b/core/include/log.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @addtogroup  core_util
+ * @{
+ *
+ * @brief       System logging header
+ *
+ * This header offers a bunch of "LOG_*" functions that, with the default
+ * implementation, just use printf, but honour a verbosity level.
+ *
+ * If desired, it is possible to implement a log module which then will be used
+ * instead the default printf-based implementation.  In order to do so, the log
+ * module has to
+ *
+ * 1. provide "log_module.h"
+ * 2. have a name starting with "log_" *or* depend on the pseudo-module LOG,
+ * 3. implement log_write()
+ *
+ * See "sys/log/log_printfnoformat" for an example.
+ *
+ * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ */
+
+#ifndef __LOG_H
+#define __LOG_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/**
+ * @brief defined log levels
+ *
+ * These are the logging levels a user can choose.
+ * The idea is to set LOG_LEVEL to one of these values in the application's Makefile.
+ * That will restrict output of log statements to those with equal or lower log level.
+ *
+ * The default log level is LOG_INFO, which will print every message.
+ *
+ * The log function calls of filtered messages will be optimized out at compile
+ * time, so a lower log level might result in smaller code size.
+ */
+enum {
+    LOG_NONE,       /**< Lowest log level, will output nothing */
+    LOG_ERROR,      /**< Error log level, will print only critical,
+                         non-recoverable errors like hardware initialization
+                         failures */
+    LOG_WARNING,    /**< Warning log level, will print warning messages for
+                         temporary errors */
+    LOG_INFO,       /**< Informational log level, will print purely
+                         informational messages like successful system bootup,
+                         network link state, ...*/
+    LOG_DEBUG,      /**< Debug log level, printing developer stuff considered
+                         too verbose for production use */
+    LOG_ALL         /**< print everything */
+};
+
+#ifndef LOG_LEVEL
+/**
+ * @brief Default log level define
+ */
+#define LOG_LEVEL LOG_INFO
+#endif
+
+/**
+ * @brief Log message if level <= LOG_LEVEL
+ */
+#define LOG(level, ...) if (level <= LOG_LEVEL) log_write(level, __VA_ARGS__)
+
+/**
+ * @brief logging convenience defines
+ * @{
+ */
+#define LOG_ERROR(...) LOG(LOG_ERROR, __VA_ARGS__)
+#define LOG_WARNING(...) LOG(LOG_WARNING, __VA_ARGS__)
+#define LOG_INFO(...) LOG(LOG_INFO, __VA_ARGS__)
+#define LOG_DEBUG(...) LOG(LOG_DEBUG, __VA_ARGS__)
+/** @} */
+
+#ifdef MODULE_LOG
+#include "log_module.h"
+#else
+#include <stdio.h>
+
+/**
+ * @brief Default log_write function, just maps to printf
+ */
+#define log_write(level, ...) printf(__VA_ARGS__)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LOG_H */
+/** @} */
diff --git a/core/kernel_init.c b/core/kernel_init.c
index a57f119acb299da517ca3a8c3bbee469feb3464f..678f9759e8b4016306ae38a1cb6a43de4e90b6eb 100644
--- a/core/kernel_init.c
+++ b/core/kernel_init.c
@@ -18,7 +18,6 @@
  * @}
  */
 
-#include <stdio.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <errno.h>
@@ -32,6 +31,7 @@
 #include "thread.h"
 #include "hwtimer.h"
 #include "irq.h"
+#include "log.h"
 
 #define ENABLE_DEBUG (0)
 #include "debug.h"
@@ -82,19 +82,19 @@ static char idle_stack[KERNEL_CONF_STACKSIZE_IDLE];
 void kernel_init(void)
 {
     (void) disableIRQ();
-    printf("kernel_init(): This is RIOT! (Version: %s)\n", RIOT_VERSION);
+    LOG_INFO("kernel_init(): This is RIOT! (Version: %s)\n", RIOT_VERSION);
 
     hwtimer_init();
 
     if (thread_create(idle_stack, sizeof(idle_stack), PRIORITY_IDLE, CREATE_WOUT_YIELD | CREATE_STACKTEST, idle_thread, NULL, idle_name) < 0) {
-        printf("kernel_init(): error creating idle task.\n");
+        LOG_ERROR("kernel_init(): error creating idle task.\n");
     }
 
     if (thread_create(main_stack, sizeof(main_stack), PRIORITY_MAIN, CREATE_WOUT_YIELD | CREATE_STACKTEST, main_trampoline, NULL, main_name) < 0) {
-        printf("kernel_init(): error creating main task.\n");
+        LOG_ERROR("kernel_init(): error creating main task.\n");
     }
 
-    printf("kernel_init(): jumping into first task...\n");
+    LOG_INFO("kernel_init(): jumping into first task...\n");
 
     cpu_switch_context_exit();
 }
diff --git a/core/lifo.c b/core/lifo.c
index 2451c42ed3a0d3e355fc39f8d88a3d2fc03dc391..7c6ce59ba1be831218053d5a4a58a4d5c84181cf 100644
--- a/core/lifo.c
+++ b/core/lifo.c
@@ -17,6 +17,7 @@
  */
 
 #include "lifo.h"
+#include "log.h"
 
 #define ENABLE_DEBUG (0)
 #include "debug.h"
@@ -42,7 +43,7 @@ void lifo_insert(int *array, int i)
 
 #if DEVELHELP
     if ((array[index] != -1) && (array[0] != -1)) {
-        printf("lifo_insert: overwriting array[%i] == %i with %i\n\n\n\t\tThe lifo is broken now.\n\n\n", index, array[index], array[0]);
+        LOG_WARNING("lifo_insert: overwriting array[%i] == %i with %i\n\n\n\t\tThe lifo is broken now.\n\n\n", index, array[index], array[0]);
     }
 #endif
 
diff --git a/core/sched.c b/core/sched.c
index 9d404789fed9d911297ae1bd5aa41dffa30186d3..28ab4db244624260578c12345f865a2005633fd3 100644
--- a/core/sched.c
+++ b/core/sched.c
@@ -29,6 +29,7 @@
 #include "irq.h"
 #include "thread.h"
 #include "irq.h"
+#include "log.h"
 
 #if SCHEDSTATISTICS
 #include "hwtimer.h"
@@ -86,7 +87,7 @@ int sched_run(void)
 
 #ifdef SCHED_TEST_STACK
         if (*((uintptr_t *) active_thread->stack_start) != (uintptr_t) active_thread->stack_start) {
-            printf("scheduler(): stack overflow detected, pid=%" PRIkernel_pid "\n", active_thread->pid);
+            LOG_WARNING("scheduler(): stack overflow detected, pid=%" PRIkernel_pid "\n", active_thread->pid);
         }
 #endif
 
diff --git a/sys/Makefile b/sys/Makefile
index b5ce3cd2bc0395cd1c71963e786aae1ea5a9244d..49919cef4b38c47ef86d8862261dbcac806827d9 100644
--- a/sys/Makefile
+++ b/sys/Makefile
@@ -143,6 +143,9 @@ endif
 ifneq (,$(filter hwtimer_compat,$(USEMODULE)))
     DIRS += compat/hwtimer
 endif
+ifneq (,$(filter log_%,$(USEMODULE)))
+    DIRS += log
+endif
 
 DIRS += $(dir $(wildcard $(addsuffix /Makefile, ${USEMODULE})))
 
diff --git a/sys/Makefile.include b/sys/Makefile.include
index ca3bce1556e38cb1e12ed39df91a7ae7f1a602ef..68137f6cfb886bb76e22836e0c4db9c230ebfd9e 100644
--- a/sys/Makefile.include
+++ b/sys/Makefile.include
@@ -90,3 +90,6 @@ ifneq (,$(filter embunit,$(USEMODULE)))
         CFLAGS += -DOUTPUT=OUTPUT_COMPILER
     endif
 endif
+ifneq (,$(filter log_%,$(USEMODULE)))
+    include $(RIOTBASE)/sys/log/Makefile.include
+endif
diff --git a/sys/log/Makefile b/sys/log/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..f1eb9fa686a0c9a51647e82737df848f7af5cc5a
--- /dev/null
+++ b/sys/log/Makefile
@@ -0,0 +1,3 @@
+DIRS += $(dir $(wildcard $(addsuffix /Makefile, ${USEMODULE})))
+
+include $(RIOTBASE)/Makefile.base
diff --git a/sys/log/Makefile.include b/sys/log/Makefile.include
new file mode 100644
index 0000000000000000000000000000000000000000..769761aef444ed0dc9d3ced27109be77a8e28ce7
--- /dev/null
+++ b/sys/log/Makefile.include
@@ -0,0 +1,3 @@
+ifneq (,$(filter log_printfnoformat,$(USEMODULE)))
+    USEMODULE_INCLUDES += $(RIOTBASE)/sys/log/log_printfnoformat
+endif
diff --git a/sys/log/log_printfnoformat/log_module.h b/sys/log/log_printfnoformat/log_module.h
new file mode 100644
index 0000000000000000000000000000000000000000..9725290a2a231f8b101d11806a451755da874c69
--- /dev/null
+++ b/sys/log/log_printfnoformat/log_module.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @defgroup    sys_log_printfnoformat puts log module
+ * @ingroup     sys
+ * @brief       This module implements an example logging module
+ * @{
+ *
+ * @file        log_module.h
+ * @brief       log_module header
+ *
+ * @author      Jason Linehan <patientulysses@gmail.com>
+ * @author      Christian Mehlis <mehlis@inf.fu-berlin.de>
+ * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ */
+
+#ifndef __LOG_FORMAT_H
+#define __LOG_FORMAT_H
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief log_write overridden function
+ *
+ * This example function will only print the log's format string.
+ * Use it where printf might be too heavy.
+ *
+ * @param[in] level (unused)
+ * @param[in] format String that the function will print
+ */
+static inline void log_write(unsigned level, const char *format, ...) {
+    (void)level;
+    puts(format);
+}
+
+#ifdef __cplusplus
+}
+#endif
+/**@}*/
+#endif /* __LOG_FORMAT_H */