265 lines
6.5 KiB
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);
|
|
}
|
|
|