vty: integration with logging framework

The logging categories are registered by the applications, like
osmo-nitb, during startup. Thus, the VTY have to provide the logging
commands according to the logging categories that the application
has registered.

Before this patch, the VTY contained the logging categories
hardcoded. Thus, any change in the logging categories by the
application would not be shown by the VTY.

So far, this was not a problem because all applications used the
same logging categories. However, according to what Harald told
me, this may be a problem in the future.

This patch resolve the lack of integration between the logging
framework and the VTY by generating the VTY logging commands
from the logging categories registered.

Since this patch changes one function of the libosmocore API,
it follows another patch for the openbsc application to get in
sync with the new function layout.

I have reworked and renamed the functions:

 * log_vty_category_string()
 * log_vty_level_string()

to provide the new ones that generate the exact output that VTY
requires.

This patch does not release the memory allocated by
talloc_zero_size() to store the VTY strings for the commands
and the description. I found no exit function that can clean
up resources that were allocated.
This commit is contained in:
Pablo Neira Ayuso 2011-03-09 13:05:08 +01:00 committed by Harald Welte
parent 63196de6d8
commit 04139f14b6
4 changed files with 140 additions and 89 deletions

View File

@ -4,8 +4,9 @@
#define LOGGING_STR "Configure log message to this terminal\n"
#define FILTER_STR "Filter log messages\n"
void logging_vty_add_cmds(void);
struct log_info;
void logging_vty_add_cmds(const struct log_info *cat);
struct vty;
struct log_target *osmo_log_vty2tgt(struct vty *vty);
#endif /* _VTY_LOGGING_H */

View File

@ -144,9 +144,9 @@ int log_target_file_reopen(struct log_target *tgt);
void log_add_target(struct log_target *target);
void log_del_target(struct log_target *target);
/* Gernerate command argument strings for VTY use */
const char *log_vty_category_string(struct log_info *info);
const char *log_vty_level_string(struct log_info *info);
/* Generate command string for VTY use */
const char *log_vty_command_string(const struct log_info *info);
const char *log_vty_command_description(const struct log_info *info);
struct log_target *log_target_find(int type, const char *fname);
extern struct llist_head osmo_log_target_list;

View File

@ -26,6 +26,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
@ -37,13 +38,17 @@
#include <osmocore/utils.h>
#include <osmocore/logging.h>
#include <osmocom/vty/logging.h> /* for LOGGING_STR. */
const struct log_info *osmo_log_info;
static struct log_context log_context;
static void *tall_log_ctx = NULL;
LLIST_HEAD(osmo_log_target_list);
static const struct value_string loglevel_strs[] = {
#define LOGLEVEL_DEFS 6 /* Number of loglevels.*/
static const struct value_string loglevel_strs[LOGLEVEL_DEFS+1] = {
{ 0, "EVERYTHING" },
{ LOGL_DEBUG, "DEBUG" },
{ LOGL_INFO, "INFO" },
@ -53,6 +58,17 @@ static const struct value_string loglevel_strs[] = {
{ 0, NULL },
};
/* You have to keep this in sync with the structure loglevel_strs. */
const char *loglevel_descriptions[LOGLEVEL_DEFS+1] = {
"Log simply everything",
"Log debug messages and higher levels",
"Log informational messages and higher levels",
"Log noticable messages and higher levels",
"Log error messages and higher levels",
"Log only fatal messages",
NULL,
};
int log_parse_level(const char *lvl)
{
return get_string_value(loglevel_strs, lvl);
@ -418,49 +434,125 @@ int log_target_file_reopen(struct log_target *target)
return 0;
}
const char *log_vty_level_string(struct log_info *info)
/* This can go into some header file so others can benefit from it. */
#define SNPRINTF_FAILURE(ret, rem, offset, len) \
do { \
len += ret; \
if (ret > rem) \
ret = rem; \
offset += ret; \
rem -= ret; \
} while (0)
/* This generates the logging command string for VTY. */
const char *log_vty_command_string(const 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;
int len = 0, offset = 0, ret, i, rem;
int size = strlen("logging level () ()") + 1;
char *str;
for (i = 0; i < info->num_cat; i++)
len += strlen(info->cat[i].name) + 1;
size += strlen(info->cat[i].name) + 1;
str = talloc_zero_size(NULL, len);
for (i = 0; i < LOGLEVEL_DEFS; i++)
size += strlen(loglevel_strs[i].str) + 1;
rem = size;
str = talloc_zero_size(NULL, size);
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] = ')';
ret = snprintf(str + offset, rem, "logging level (");
if (ret < 0)
goto err;
SNPRINTF_FAILURE(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];
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;
SNPRINTF_FAILURE(ret, rem, offset, len);
}
offset--; /* to remove the trailing | */
rem++;
ret = snprintf(str + offset, rem, ") (");
if (ret < 0)
goto err;
SNPRINTF_FAILURE(ret, rem, offset, len);
for (i = 0; i < LOGLEVEL_DEFS; i++) {
int j, loglevel_str_len = strlen(loglevel_strs[i].str)+1;
char loglevel_str[loglevel_str_len];
for (j = 0; j < loglevel_str_len; j++)
loglevel_str[j] = tolower(loglevel_strs[i].str[j]);
loglevel_str[loglevel_str_len-1] = '\0';
ret = snprintf(str + offset, rem, "%s|", loglevel_str);
if (ret < 0)
goto err;
SNPRINTF_FAILURE(ret, rem, offset, len);
}
offset--; /* to remove the trailing | */
rem++;
ret = snprintf(str + offset, rem, ")");
if (ret < 0)
goto err;
SNPRINTF_FAILURE(ret, rem, offset, len);
err:
return str;
}
/* This generates the logging command description for VTY. */
const char *log_vty_command_description(const struct log_info *info)
{
char *str;
int i, ret, len = 0, offset = 0, rem;
unsigned int size =
strlen(LOGGING_STR
"Set the log level for a specified category\n") + 1;
for (i = 0; i < info->num_cat; i++)
size += strlen(info->cat[i].description) + 1;
for (i = 0; i < LOGLEVEL_DEFS; i++)
size += strlen(loglevel_descriptions[i]) + 1;
rem = size;
str = talloc_zero_size(NULL, size);
if (!str)
return NULL;
ret = snprintf(str + offset, rem, LOGGING_STR
"Set the log level for a specified category\n");
if (ret < 0)
goto err;
SNPRINTF_FAILURE(ret, rem, offset, len);
for (i = 0; i < info->num_cat; i++) {
ret = snprintf(str + offset, rem, "%s\n",
info->cat[i].description);
if (ret < 0)
goto err;
SNPRINTF_FAILURE(ret, rem, offset, len);
}
for (i = 0; i < LOGLEVEL_DEFS; i++) {
ret = snprintf(str + offset, rem, "%s\n",
loglevel_descriptions[i]);
if (ret < 0)
goto err;
SNPRINTF_FAILURE(ret, rem, offset, len);
}
err:
return str;
}

View File

@ -149,56 +149,10 @@ DEFUN(logging_prnt_timestamp,
return CMD_SUCCESS;
}
/* FIXME: those have to be kept in sync with the log levels and categories */
#define VTY_DEBUG_CATEGORIES "(rll|cc|mm|rr|rsl|nm|sms|pag|mncc|inp|mi|mib|mux|meas|sccp|msc|mgcp|ho|db|ref|gprs|ns|bssgp|llc|sndcp|isup|m2ua|pcap|nat|all)"
#define CATEGORIES_HELP \
"A-bis Radio Link Layer (RLL)\n" \
"Layer3 Call Control (CC)\n" \
"Layer3 Mobility Management (MM)\n" \
"Layer3 Radio Resource (RR)\n" \
"A-bis Radio Signalling Link (RSL)\n" \
"A-bis Network Management / O&M (NM/OML)\n" \
"Layer3 Short Messagaging Service (SMS)\n" \
"Paging Subsystem\n" \
"MNCC API for Call Control application\n" \
"A-bis Input Subsystem\n" \
"A-bis Input Driver for Signalling\n" \
"A-bis Input Driver for B-Channel (voice data)\n" \
"A-bis B-Channel / Sub-channel Multiplexer\n" \
"Radio Measurements\n" \
"SCCP\n" \
"Mobile Switching Center\n" \
"Media Gateway Control Protocol\n" \
"Hand-over\n" \
"Database Layer\n" \
"Reference Counting\n" \
"GPRS Core\n" \
"GPRS Network Service (NS)\n" \
"GPRS BSS Gateway Protocol (BSSGP)\n" \
"GPRS Logical Link Control Protocol (LLC)\n" \
"GPRS Sub-Network Dependent Control Protocol (SNDCP)\n" \
"ISDN User Part (ISUP)\n" \
"SCTP M2UA\n" \
"Trace message IO\n" \
"BSC NAT\n" \
"Global setting for all subsytems\n"
#define VTY_DEBUG_LEVELS "(everything|debug|info|notice|error|fatal)"
#define LEVELS_HELP \
"Log simply everything\n" \
"Log debug messages and higher levels\n" \
"Log informational messages and higher levels\n" \
"Log noticable messages and higher levels\n" \
"Log error messages and higher levels\n" \
"Log only fatal messages\n"
DEFUN(logging_level,
logging_level_cmd,
"logging level " VTY_DEBUG_CATEGORIES " " VTY_DEBUG_LEVELS,
LOGGING_STR
"Set the log level for a specified category\n"
CATEGORIES_HELP
LEVELS_HELP)
NULL, /* cmdstr is dynamically set in logging_vty_add_cmds(). */
NULL) /* same thing for helpstr. */
{
int category = log_parse_category(argv[0]);
int level = log_parse_level(argv[1]);
@ -596,7 +550,7 @@ static int config_write_log(struct vty *vty)
return 1;
}
void logging_vty_add_cmds()
void logging_vty_add_cmds(const struct log_info *cat)
{
install_element_ve(&enable_logging_cmd);
install_element_ve(&disable_logging_cmd);
@ -604,6 +558,10 @@ void logging_vty_add_cmds()
install_element_ve(&logging_use_clr_cmd);
install_element_ve(&logging_prnt_timestamp_cmd);
install_element_ve(&logging_set_category_mask_cmd);
/* Logging level strings are generated dynamically. */
logging_level_cmd.string = log_vty_command_string(cat);
logging_level_cmd.doc = log_vty_command_description(cat);
install_element_ve(&logging_level_cmd);
install_element_ve(&show_logging_vty_cmd);