From c944d541717678846e86db386f39f35ed44c7269 Mon Sep 17 00:00:00 2001
From: Kaspar Schleiser <kaspar@schleiser.de>
Date: Wed, 25 Feb 2015 16:31:03 +0100
Subject: [PATCH] core: log: introduce logging API

---
 Makefile.dep                            |   5 ++
 Makefile.pseudomodules                  |   2 +
 core/hwtimer.c                          |   4 +-
 core/include/log.h                      | 103 ++++++++++++++++++++++++
 core/kernel_init.c                      |  10 +--
 core/lifo.c                             |   3 +-
 core/sched.c                            |   3 +-
 sys/Makefile                            |   3 +
 sys/Makefile.include                    |   3 +
 sys/log/Makefile                        |   3 +
 sys/log/Makefile.include                |   3 +
 sys/log/log_printfnoformat/log_module.h |  50 ++++++++++++
 12 files changed, 184 insertions(+), 8 deletions(-)
 create mode 100644 core/include/log.h
 create mode 100644 sys/log/Makefile
 create mode 100644 sys/log/Makefile.include
 create mode 100644 sys/log/log_printfnoformat/log_module.h

diff --git a/Makefile.dep b/Makefile.dep
index 85facbec08..58642b8219 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 9b6867efcc..f23954e445 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 3c7152b458..89e9e96169 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 0000000000..ecd1831f53
--- /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 a57f119acb..678f9759e8 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 2451c42ed3..7c6ce59ba1 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 9d404789fe..28ab4db244 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 b5ce3cd2bc..49919cef4b 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 ca3bce1556..68137f6cfb 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 0000000000..f1eb9fa686
--- /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 0000000000..769761aef4
--- /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 0000000000..9725290a2a
--- /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 */
-- 
GitLab