logging: introduce library-internal logging categories
authorHarald Welte <laforge@gnumonks.org>
Mon, 27 Jun 2011 08:29:17 +0000 (10:29 +0200)
committerHarald Welte <laforge@gnumonks.org>
Mon, 27 Jun 2011 08:40:25 +0000 (10:40 +0200)
We do this by using a trick: library-internal log categories use
negative subsystem numbers, which are converted into positive
array indexes at the time of logging.

library-internal log categories need to be knwo at compile-time,
while application-specified categories now are of unlimited number,
as they are dynamically allocated.

include/osmocom/core/logging.h
src/application.c
src/logging.c

index db02940..b477a66 100644 (file)
@@ -5,7 +5,6 @@
 #include <stdint.h>
 #include <osmocom/core/linuxlist.h>
 
-#define LOG_MAX_CATEGORY       32
 #define LOG_MAX_CTX            8
 #define LOG_MAX_FILTERS        8
 
@@ -20,7 +19,7 @@
 #endif
 
 
-void logp(unsigned int subsys, char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
+void logp(int subsys, char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
 
 /* new logging interface */
 #define LOGP(ss, level, fmt, args...) \
@@ -37,6 +36,10 @@ void logp(unsigned int subsys, char *file, int line, int cont, const char *forma
 
 #define LOG_FILTER_ALL 0x0001
 
+/* logging levels defined by the library itself */
+#define DLGLOBAL       -1
+#define OSMO_NUM_DLIB  1
+
 struct log_category {
        uint8_t loglevel;
        uint8_t enabled;
@@ -65,8 +68,9 @@ struct log_info {
        log_filter *filter_fn;
 
        /* per-category information */
-       const struct log_info_cat *cat;
+       struct log_info_cat *cat;
        unsigned int num_cat;
+       unsigned int num_cat_user;
 };
 
 enum log_target_type {
@@ -82,7 +86,8 @@ struct log_target {
        int filter_map;
        void *filter_data[LOG_MAX_FILTERS+1];
 
-       struct log_category categories[LOG_MAX_CATEGORY+1];
+       struct log_category *categories;
+
        uint8_t loglevel;
        int use_color:1;
        int print_timestamp:1;
@@ -110,10 +115,10 @@ struct log_target {
 };
 
 /* use the above macros */
-void logp2(unsigned int subsys, unsigned int level, char *file,
+void logp2(int subsys, unsigned int level, char *file,
           int line, int cont, const char *format, ...)
                                __attribute__ ((format (printf, 6, 7)));
-void log_init(const struct log_info *cat);
+int log_init(const struct log_info *inf, void *talloc_ctx);
 
 /* context management */
 void log_reset_context(void);
index 5f8f447..b7e943d 100644 (file)
@@ -44,7 +44,7 @@ void osmo_init_ignore_signals(void)
 
 int osmo_init_logging(const struct log_info *log_info)
 {
-       log_init(log_info);
+       log_init(log_info, NULL);
        osmo_stderr_target = log_target_create_stderr();
        if (!osmo_stderr_target)
                return -1;
index 3c9dc03..def13b3 100644 (file)
@@ -40,7 +40,7 @@
 
 #include <osmocom/vty/logging.h>       /* for LOGGING_STR. */
 
-const struct log_info *osmo_log_info;
+struct log_info *osmo_log_info;
 
 static struct log_context log_context;
 static void *tall_log_ctx = NULL;
@@ -58,6 +58,16 @@ static const struct value_string loglevel_strs[LOGLEVEL_DEFS+1] = {
        { 0, NULL },
 };
 
+#define INT2IDX(x)     (-1*(x)-1)
+static const struct log_info_cat internal_cat[OSMO_NUM_DLIB] = {
+       [INT2IDX(DLGLOBAL)] = { /* -1 becomes 0 */
+               .name = "DLGLOBAL",
+               .description = "Library-internal global log family",
+               .loglevel = LOGL_NOTICE,
+               .enabled = 1,
+       },
+};
+
 /* You have to keep this in sync with the structure loglevel_strs. */
 const char *loglevel_descriptions[LOGLEVEL_DEFS+1] = {
        "Log simply everything",
@@ -69,6 +79,12 @@ const char *loglevel_descriptions[LOGLEVEL_DEFS+1] = {
        NULL,
 };
 
+/* special magic for negative (library-internal) log subsystem numbers */
+static int subsys_lib2index(int subsys)
+{
+       return (subsys * -1) + (osmo_log_info->num_cat_user-1);
+}
+
 int log_parse_level(const char *lvl)
 {
        return get_string_value(loglevel_strs, lvl);
@@ -84,6 +100,8 @@ int log_parse_category(const char *category)
        int i;
 
        for (i = 0; i < osmo_log_info->num_cat; ++i) {
+               if (osmo_log_info->cat[i].name == NULL)
+                       continue;
                if (!strcasecmp(osmo_log_info->cat[i].name+1, category))
                        return i;
        }
@@ -103,7 +121,7 @@ void log_parse_category_mask(struct log_target* target, const char *_mask)
        char *category_token = NULL;
 
        /* Disable everything to enable it afterwards */
-       for (i = 0; i < ARRAY_SIZE(target->categories); ++i)
+       for (i = 0; i < osmo_log_info->num_cat; ++i)
                target->categories[i].enabled = 0;
 
        category_token = strtok(mask, ":");
@@ -112,6 +130,9 @@ void log_parse_category_mask(struct log_target* target, const char *_mask)
                        char* colon = strstr(category_token, ",");
                        int length = strlen(category_token);
 
+                       if (!osmo_log_info->cat[i].name)
+                               continue;
+
                        if (colon)
                            length = colon - category_token;
 
@@ -189,12 +210,17 @@ err:
        target->output(target, level, buf);
 }
 
-
-static void _logp(unsigned int subsys, int level, char *file, int line,
+static void _logp(int subsys, int level, char *file, int line,
                  int cont, const char *format, va_list ap)
 {
        struct log_target *tar;
 
+       if (subsys < 0)
+               subsys = subsys_lib2index(subsys);
+
+       if (subsys > osmo_log_info->num_cat)
+               subsys = DLGLOBAL;
+
        llist_for_each_entry(tar, &osmo_log_target_list, entry) {
                struct log_category *category;
                int output = 0;
@@ -234,7 +260,7 @@ static void _logp(unsigned int subsys, int level, char *file, int line,
        }
 }
 
-void logp(unsigned int subsys, char *file, int line, int cont,
+void logp(int subsys, char *file, int line, int cont,
          const char *format, ...)
 {
        va_list ap;
@@ -244,7 +270,7 @@ void logp(unsigned int subsys, char *file, int line, int cont,
        va_end(ap);
 }
 
-void logp2(unsigned int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...)
+void logp2(int subsys, unsigned int level, char *file, int line, int cont, const char *format, ...)
 {
        va_list ap;
 
@@ -326,6 +352,14 @@ struct log_target *log_target_create(void)
        if (!target)
                return NULL;
 
+       target->categories = talloc_zero_array(target, 
+                                               struct log_category,
+                                               osmo_log_info->num_cat);
+       if (!target->categories) {
+               talloc_free(target);
+               return NULL;
+       }
+
        INIT_LLIST_HEAD(&target->entry);
 
        /* initialize the per-category enabled/loglevel from defaults */
@@ -441,8 +475,11 @@ const char *log_vty_command_string(const struct log_info *info)
        int size = strlen("logging level () ()") + 1;
        char *str;
 
-       for (i = 0; i < info->num_cat; i++)
+       for (i = 0; i < info->num_cat; i++) {
+               if (info->cat[i].name == NULL)
+                       continue;
                size += strlen(info->cat[i].name) + 1;
+       }
 
        for (i = 0; i < LOGLEVEL_DEFS; i++)
                size += strlen(loglevel_strs[i].str) + 1;
@@ -458,17 +495,19 @@ const char *log_vty_command_string(const struct log_info *info)
        OSMO_SNPRINTF_RET(ret, rem, offset, len);
 
        for (i = 0; i < info->num_cat; i++) {
-               int j, name_len = strlen(info->cat[i].name)+1;
-               char name[name_len];
+               if (info->cat[i].name) {
+                       int j, name_len = strlen(info->cat[i].name)+1;
+                       char name[name_len];
 
-               for (j = 0; j < name_len; j++)
-                       name[j] = tolower(info->cat[i].name[j]);
+                       for (j = 0; j < name_len; j++)
+                               name[j] = tolower(info->cat[i].name[j]);
 
-               name[name_len-1] = '\0';
-               ret = snprintf(str + offset, rem, "%s|", name+1);
-               if (ret < 0)
-                       goto err;
-               OSMO_SNPRINTF_RET(ret, rem, offset, len);
+                       name[name_len-1] = '\0';
+                       ret = snprintf(str + offset, rem, "%s|", name+1);
+                       if (ret < 0)
+                               goto err;
+                       OSMO_SNPRINTF_RET(ret, rem, offset, len);
+               }
        }
        offset--;       /* to remove the trailing | */
        rem++;
@@ -512,8 +551,11 @@ const char *log_vty_command_description(const struct log_info *info)
                strlen(LOGGING_STR
                       "Set the log level for a specified category\n") + 1;
 
-       for (i = 0; i < info->num_cat; i++)
+       for (i = 0; i < info->num_cat; i++) {
+               if (info->cat[i].name == NULL)
+                       continue;
                size += strlen(info->cat[i].description) + 1;
+       }
 
        for (i = 0; i < LOGLEVEL_DEFS; i++)
                size += strlen(loglevel_descriptions[i]) + 1;
@@ -537,6 +579,8 @@ const char *log_vty_command_description(const struct log_info *info)
        OSMO_SNPRINTF_RET(ret, rem, offset, len);
 
        for (i = 0; i < info->num_cat; i++) {
+               if (info->cat[i].name == NULL)
+                       continue;
                ret = snprintf(str + offset, rem, "%s\n",
                                info->cat[i].description);
                if (ret < 0)
@@ -555,8 +599,36 @@ err:
        return str;
 }
 
-void log_init(const struct log_info *cat)
+int log_init(const struct log_info *inf, void *ctx)
 {
-       tall_log_ctx = talloc_named_const(NULL, 1, "logging");
-       osmo_log_info = cat;
+       int i;
+
+       tall_log_ctx = talloc_named_const(ctx, 1, "logging");
+       if (!tall_log_ctx)
+               return -ENOMEM;
+
+       osmo_log_info = talloc_zero(tall_log_ctx, struct log_info);
+       if (!osmo_log_info)
+               return -ENOMEM;
+
+       osmo_log_info->num_cat_user = inf->num_cat;
+       /* total number = number of user cat + library cat */
+       osmo_log_info->num_cat = inf->num_cat + OSMO_NUM_DLIB;
+
+       osmo_log_info->cat = talloc_zero_array(osmo_log_info,
+                                       struct log_info_cat,
+                                       osmo_log_info->num_cat);
+       if (!osmo_log_info->cat) {
+               talloc_free(osmo_log_info);
+               osmo_log_info = NULL;
+               return -ENOMEM;
+       }
+
+       /* copy over the user part */
+       for (i = 0; i < inf->num_cat; i++) {
+               memcpy(&osmo_log_info->cat[i], &inf->cat[i],
+                       sizeof(struct log_info_cat));
+       }
+
+       /* copy over the library part */
 }