osmo-cc-sip-endpoint/src/liblogging/logging.c

265 lines
6.5 KiB
C

/* Logging (on segmented part of the window)
*
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <sys/ioctl.h>
#include <math.h>
#include <errno.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/application.h>
#include <osmocom/cc/misc.h>
#include "logging.h"
int loglevel = LOGL_INFO;
static int scroll_window_start = 0;
static int scroll_window_end = 0;
static int scroll_window_height = 0;
void lock_logging(void)
{
log_tgt_mutex_lock();
}
void unlock_logging(void)
{
log_tgt_mutex_unlock();
}
void get_win_size(int *w, int *h)
{
struct winsize win;
int rc;
rc = ioctl(0, TIOCGWINSZ, &win);
if (rc) {
*w = 80;
*h = 25;
return;
}
if (h)
*h = win.ws_row;
if (w)
*w = win.ws_col;
}
void enable_limit_scroll(bool enable)
{
/* Before the window is set, keep scrolling everything. */
if (scroll_window_height == 0)
return;
/* If window is too small. */
if (scroll_window_end - scroll_window_start <= 0)
return;
if (enable) {
printf("\0337\033[%d;%dr\0338", scroll_window_start, scroll_window_end);
} else
printf("\0337\033[%d;%dr\0338", 1, scroll_window_height);
fflush(stdout);
}
void logging_limit_scroll_top(int lines)
{
lock_logging();
get_win_size(NULL, &scroll_window_height);
scroll_window_start = lines + 1;
if (scroll_window_end == 0)
scroll_window_end = scroll_window_height;
enable_limit_scroll(true);
unlock_logging();
}
void logging_limit_scroll_bottom(int lines)
{
int i;
lock_logging();
get_win_size(NULL, &scroll_window_height);
scroll_window_end = scroll_window_height - lines;
if (scroll_window_start == 0)
scroll_window_start = 1;
/* Make space by adding empty lines. */
for (i = scroll_window_end; i < scroll_window_height; i++)
printf("\n");
/* Go up by number of lines to be in window. */
printf("\033[%dA", scroll_window_height - scroll_window_end);
/* Enable window. */
enable_limit_scroll(true);
unlock_logging();
}
const char *debug_amplitude(double level)
{
static char text[42];
strcpy(text, " : ");
if (level > 1.0)
level = 1.0;
if (level < -1.0)
level = -1.0;
text[20 + (int)(level * 20)] = '*';
return text;
}
#define level2db(level) (20 * log10(level))
const char *debug_db(double level_db)
{
static char text[128];
int l;
strcpy(text, ": . : . : . : . : . : . : . : . | . : . : . : . : . : . : . : . :");
if (level_db <= 0.0)
return text;
l = (int)round(level2db(level_db));
if (l > 48)
return text;
if (l < -48)
return text;
text[l + 48] = '*';
return text;
}
void logging_print_help(void)
{
printf(" -v --verbose <level> | <level>,<category>[,<category>[,...]] | list\n");
printf(" Use 'list' to get a list of all levels and categories.\n");
printf(" Verbose level: digit of debug level (default = '%d')\n", loglevel);
printf(" Verbose level+category: level digit followed by one or more categories\n");
printf(" -> If no category is specified, all categories are selected\n");
printf(" -v --verbose date\n");
printf(" Show date with debug output\n");
}
static unsigned char log_levels[] = { LOGL_DEBUG, LOGL_INFO, LOGL_NOTICE, LOGL_ERROR };
static char *log_level_names[] = { "debug", "info", "notice", "error" };
static void list_cat(void)
{
int i;
printf("Give number of debug level:\n");
for (i = 0; i < (int)sizeof(log_levels); i++)
printf(" %d = %s\n", log_levels[i], log_level_names[i]);
printf("\n");
printf("Give name(s) of debug category:\n");
for (i = 0; i < (int)log_categories_size; i++) {
if (!log_categories[i].name)
continue;
printf(" ");
if (log_categories[i].color)
printf("%s", log_categories[i].color);
if (log_categories[i].name)
printf("%s\033[0;39m = %s\n", log_categories[i].name, log_categories[i].description);
}
printf("\n");
}
int parse_logging_opt(const char *optarg)
{
int i;
char *dup, *dstring, *p;
if (!strcasecmp(optarg, "list")) {
list_cat();
return 1;
}
if (!strcasecmp(optarg, "date")) {
log_set_print_timestamp(osmo_stderr_target, 1);
return 0;
}
dup = dstring = strdup(optarg);
p = strsep(&dstring, ",");
for (i = 0; i < p[i]; i++) {
if (p[i] < '0' || p[i] > '9') {
fprintf(stderr, "Only digits are allowed for debug level!\n");
free(dup);
return -EINVAL;
}
}
loglevel = atoi(p);
for (i = 0; i < (int)sizeof(log_levels); i++) {
if (log_levels[i] == loglevel)
break;
}
if (i == (int)sizeof(log_levels)) {
fprintf(stderr, "Logging level does not exist, use '-v list' to show available levels!\n");
free(dup);
return -EINVAL;
}
/* Set loglevel and enable all categories, if dstring is not set. Else set loglevel and disable all categories. */
for (i = 0; i < (int)log_categories_size; i++)
log_set_category_filter(osmo_stderr_target, i, (!dstring), loglevel);
/* Enable each given category. */
while((p = strsep(&dstring, ","))) {
for (i = 0; i < (int)log_categories_size; i++) {
if (!log_category_name(i))
continue;
if (!strcasecmp(p, log_category_name(i)))
break;
}
if (i == (int)log_categories_size) {
fprintf(stderr, "Given logging category '%s' unknown, use '-v list' to show available categories!\n", p);
free(dup);
return -EINVAL;
}
log_set_category_filter(osmo_stderr_target, i, 1, loglevel);
}
free(dup);
return 0;
}
/* Call after configuation above. */
void logging_init(void)
{
int i;
struct log_info log_info = {
.cat = log_categories,
.num_cat = log_categories_size,
};
osmo_cc_set_log_cat(DLCC);
osmo_init_logging2(NULL, &log_info);
log_set_print_timestamp(osmo_stderr_target, 0);
log_set_print_level(osmo_stderr_target, 1);
log_set_print_category_hex(osmo_stderr_target, 0);
log_set_print_category(osmo_stderr_target, 1);
/* Set loglevel and enable all categories. */
for (i = 0; i < (int)log_categories_size; i++)
log_set_category_filter(osmo_stderr_target, i, 1, loglevel);
}