LOGGING: Pass the log level down to the log target output function
[osmocom-bb.git] / src / logging.c
index ea03d30..4452862 100644 (file)
@@ -37,7 +37,7 @@
 #include <osmocore/utils.h>
 #include <osmocore/logging.h>
 
-static const struct log_info *log_info;
+const struct log_info *osmo_log_info;
 
 static struct log_context log_context;
 static void *tall_log_ctx = NULL;
@@ -58,12 +58,17 @@ int log_parse_level(const char *lvl)
        return get_string_value(loglevel_strs, lvl);
 }
 
+const char *log_level_str(unsigned int lvl)
+{
+       return get_value_string(loglevel_strs, lvl);
+}
+
 int log_parse_category(const char *category)
 {
        int i;
 
-       for (i = 0; i < log_info->num_cat; ++i) {
-               if (!strcasecmp(log_info->cat[i].name+1, category))
+       for (i = 0; i < osmo_log_info->num_cat; ++i) {
+               if (!strcasecmp(osmo_log_info->cat[i].name+1, category))
                        return i;
        }
 
@@ -87,15 +92,15 @@ void log_parse_category_mask(struct log_target* target, const char *_mask)
 
        category_token = strtok(mask, ":");
        do {
-               for (i = 0; i < log_info->num_cat; ++i) {
+               for (i = 0; i < osmo_log_info->num_cat; ++i) {
                        char* colon = strstr(category_token, ",");
                        int length = strlen(category_token);
 
                        if (colon)
                            length = colon - category_token;
 
-                       if (strncasecmp(log_info->cat[i].name, category_token,
-                                       length) == 0) {
+                       if (strncasecmp(osmo_log_info->cat[i].name,
+                                       category_token, length) == 0) {
                                int level = 0;
 
                                if (colon)
@@ -112,15 +117,15 @@ void log_parse_category_mask(struct log_target* target, const char *_mask)
 
 static const char* color(int subsys)
 {
-       if (subsys < log_info->num_cat)
-               return log_info->cat[subsys].color;
+       if (subsys < osmo_log_info->num_cat)
+               return osmo_log_info->cat[subsys].color;
 
        return NULL;
 }
 
 static void _output(struct log_target *target, unsigned int subsys,
-                   char *file, int line, int cont, const char *format,
-                   va_list ap)
+                   unsigned int level, char *file, int line, int cont,
+                   const char *format, va_list ap)
 {
        char col[30];
        char sub[30];
@@ -159,9 +164,10 @@ static void _output(struct log_target *target, unsigned int subsys,
                sub[sizeof(sub)-1] = '\0';
        }
 
-       snprintf(final, sizeof(final), "%s%s%s%s\033[0;m", col, tim, sub, buf);
+       snprintf(final, sizeof(final), "%s%s%s%s%s", col, tim, sub, buf,
+                target->use_color ? "\033[0;m" : "");
        final[sizeof(final)-1] = '\0';
-       target->output(target, final);
+       target->output(target, level, final);
 }
 
 
@@ -193,8 +199,8 @@ static void _logp(unsigned int subsys, int level, char *file, int line,
                 * say stop, continue, output */
                if ((tar->filter_map & LOG_FILTER_ALL) != 0)
                        output = 1;
-               else if (log_info->filter_fn)
-                       output = log_info->filter_fn(&log_context,
+               else if (osmo_log_info->filter_fn)
+                       output = osmo_log_info->filter_fn(&log_context,
                                                       tar);
 
                if (output) {
@@ -206,7 +212,7 @@ static void _logp(unsigned int subsys, int level, char *file, int line,
                         * with the same va_list will segfault */
                        va_list bp;
                        va_copy(bp, ap);
-                       _output(tar, subsys, file, line, cont, format, bp);
+                       _output(tar, subsys, level, file, line, cont, format, bp);
                        va_end(bp);
                }
        }
@@ -231,25 +237,6 @@ void logp2(unsigned int subsys, unsigned int level, char *file, int line, int co
        va_end(ap);
 }
 
-static char hexd_buff[4096];
-
-char *hexdump(const unsigned char *buf, int len)
-{
-       int i;
-       char *cur = hexd_buff;
-
-       hexd_buff[0] = 0;
-       for (i = 0; i < len; i++) {
-               int len_remain = sizeof(hexd_buff) - (cur - hexd_buff);
-               int rc = snprintf(cur, len_remain, "%02x ", buf[i]);
-               if (rc <= 0)
-                       break;
-               cur += rc;
-       }
-       hexd_buff[sizeof(hexd_buff)-1] = 0;
-       return hexd_buff;
-}
-
 void log_add_target(struct log_target *target)
 {
        llist_add_tail(&target->entry, &target_list);
@@ -301,16 +288,17 @@ void log_set_log_level(struct log_target *target, int log_level)
 void log_set_category_filter(struct log_target *target, int category,
                               int enable, int level)
 {
-       if (category >= log_info->num_cat)
+       if (category >= osmo_log_info->num_cat)
                return;
        target->categories[category].enabled = !!enable;
        target->categories[category].loglevel = level;
 }
 
-static void _stderr_output(struct log_target *target, const char *log)
+static void _file_output(struct log_target *target, unsigned int level,
+                        const char *log)
 {
-       fprintf(target->tgt_stdout.out, "%s", log);
-       fflush(target->tgt_stdout.out);
+       fprintf(target->tgt_file.out, "%s", log);
+       fflush(target->tgt_file.out);
 }
 
 struct log_target *log_target_create(void)
@@ -325,10 +313,10 @@ struct log_target *log_target_create(void)
        INIT_LLIST_HEAD(&target->entry);
 
        /* initialize the per-category enabled/loglevel from defaults */
-       for (i = 0; i < log_info->num_cat; i++) {
+       for (i = 0; i < osmo_log_info->num_cat; i++) {
                struct log_category *cat = &target->categories[i];
-               cat->enabled = log_info->cat[i].enabled;
-               cat->loglevel = log_info->cat[i].loglevel;
+               cat->enabled = osmo_log_info->cat[i].enabled;
+               cat->loglevel = osmo_log_info->cat[i].loglevel;
        }
 
        /* global settings */
@@ -341,6 +329,24 @@ struct log_target *log_target_create(void)
 }
 
 struct log_target *log_target_create_stderr(void)
+{
+/* since C89/C99 says stderr is a macro, we can safely do this! */
+#ifdef stderr
+       struct log_target *target;
+
+       target = log_target_create();
+       if (!target)
+               return NULL;
+
+       target->tgt_file.out = stderr;
+       target->output = _file_output;
+       return target;
+#else
+       return NULL;
+#endif /* stderr */
+}
+
+struct log_target *log_target_create_file(const char *fname)
 {
        struct log_target *target;
 
@@ -348,13 +354,100 @@ struct log_target *log_target_create_stderr(void)
        if (!target)
                return NULL;
 
-       target->tgt_stdout.out = stderr;
-       target->output = _stderr_output;
+       target->tgt_file.out = fopen(fname, "a");
+       if (!target->tgt_file.out)
+               return NULL;
+
+       target->output = _file_output;
+
+       target->tgt_file.fname = talloc_strdup(target, fname);
+
        return target;
 }
 
+void log_target_destroy(struct log_target *target)
+{
+
+       /* just in case, to make sure we don't have any references */
+       log_del_target(target);
+
+       if (target->output == &_file_output) {
+/* since C89/C99 says stderr is a macro, we can safely do this! */
+#ifdef stderr
+               /* don't close stderr */
+               if (target->tgt_file.out != stderr)
+#endif
+               {
+                       fclose(target->tgt_file.out);
+                       target->tgt_file.out = NULL;
+               }
+       }
+
+       talloc_free(target);
+}
+
+/* close and re-open a log file (for log file rotation) */
+int log_target_file_reopen(struct log_target *target)
+{
+       fclose(target->tgt_file.out);
+
+       target->tgt_file.out = fopen(target->tgt_file.fname, "a");
+       if (!target->tgt_file.out)
+               return -errno;
+
+       /* we assume target->output already to be set */
+
+       return 0;
+}
+
+const char *log_vty_level_string(struct log_info *info)
+{
+       const struct value_string *vs;
+       unsigned int len = 3; /* ()\0 */
+       char *str;
+
+       for (vs = loglevel_strs; vs->value || vs->str; vs++)
+               len += strlen(vs->str) + 1;
+
+       str = talloc_zero_size(NULL, len);
+       if (!str)
+               return NULL;
+
+       str[0] = '(';
+       for (vs = loglevel_strs; vs->value || vs->str; vs++) {
+               strcat(str, vs->str);
+               strcat(str, "|");
+       }
+       str[strlen(str)-1] = ')';
+
+       return str;
+}
+
+const char *log_vty_category_string(struct log_info *info)
+{
+       unsigned int len = 3;   /* "()\0" */
+       unsigned int i;
+       char *str;
+
+       for (i = 0; i < info->num_cat; i++)
+               len += strlen(info->cat[i].name) + 1;
+
+       str = talloc_zero_size(NULL, len);
+       if (!str)
+               return NULL;
+
+       str[0] = '(';
+       for (i = 0; i < info->num_cat; i++) {
+               strcat(str, info->cat[i].name+1);
+               strcat(str, "|");
+       }
+       str[strlen(str)-1] = ')';
+
+       return str;
+}
+
 void log_init(const struct log_info *cat)
 {
        tall_log_ctx = talloc_named_const(NULL, 1, "logging");
-       log_info = cat;
+       osmo_log_info = cat;
 }