1
1
mirror of https://github.com/tstack/lnav.git synced 2024-09-11 13:05:51 +03:00

[config] add more config directories to search

This commit is contained in:
Timothy Stack 2014-03-02 22:26:41 -08:00
parent fea18347f1
commit c347485834
14 changed files with 231 additions and 135 deletions

2
configure vendored
View File

@ -586,7 +586,7 @@ PACKAGE_BUGREPORT='lnav@googlegroups.com'
PACKAGE_URL=''
ac_unique_file="src/lnav.cc"
ac_default_prefix=/usr/
ac_default_prefix=/usr
# Factoring default headers for most tests.
ac_includes_default="\
#include <stdio.h>

View File

@ -4,7 +4,7 @@ AC_CONFIG_SRCDIR([src/lnav.cc])
AM_INIT_AUTOMAKE([foreign subdir-objects])
AM_SILENT_RULES([yes])
AC_PREFIX_DEFAULT(/usr/)
AC_PREFIX_DEFAULT(/usr)
AC_CANONICAL_HOST

View File

@ -27,6 +27,7 @@ AM_LDFLAGS = \
-pthread
AM_CPPFLAGS = \
-DSYSCONFDIR='"$(sysconfdir)"' \
-Wall \
$(SQLITE3_CFLAGS)

View File

@ -353,6 +353,7 @@ AM_LDFLAGS = \
-pthread
AM_CPPFLAGS = \
-DSYSCONFDIR='"$(sysconfdir)"' \
-Wall \
$(SQLITE3_CFLAGS)

View File

@ -2547,6 +2547,7 @@ static void usage(void)
"Options:\n"
" -h Print this message, then exit.\n"
" -H Display the internal help text.\n"
" -I path An additional configuration directory.\n"
" -C Check configuration and then exit.\n"
" -d file Write debug messages to the given file.\n"
" -V Print version information.\n"
@ -3775,7 +3776,102 @@ int main(int argc, char *argv[])
log_install_handlers();
load_formats(loader_errors);
lnav_data.ld_debug_log_name = "/dev/null";
while ((c = getopt(argc, argv, "hHarsCc:I:f:d:ntw:V")) != -1) {
switch (c) {
case 'h':
usage();
exit(retval);
break;
case 'H':
lnav_data.ld_flags |= LNF_HELP;
break;
case 'C':
lnav_data.ld_flags |= LNF_CHECK_CONFIG;
break;
case 'c':
switch (optarg[0]) {
case ':':
case '/':
case ';':
case '|':
break;
default:
fprintf(stderr, "error: command arguments should start with a "
"colon, semi-colon, or pipe-symbol to denote:\n");
fprintf(stderr, "error: a built-in command, SQL query, "
"or a file path that contains commands to execute\n");
usage();
exit(EXIT_FAILURE);
break;
}
lnav_data.ld_commands.push_back(optarg);
break;
case 'f':
if (access(optarg, R_OK) != 0) {
perror("invalid command file");
exit(EXIT_FAILURE);
}
lnav_data.ld_commands.push_back("|" + string(optarg));
break;
case 'I':
if (access(optarg, X_OK) != 0) {
perror("invalid config path");
exit(EXIT_FAILURE);
}
lnav_data.ld_config_paths.push_back(optarg);
break;
case 'd':
lnav_data.ld_debug_log_name = optarg;
break;
case 'a':
lnav_data.ld_flags |= LNF__ALL;
break;
case 'n':
lnav_data.ld_flags |= LNF_HEADLESS;
break;
case 'r':
lnav_data.ld_flags |= LNF_ROTATED;
break;
case 's':
lnav_data.ld_flags |= LNF_SYSLOG;
break;
case 't':
lnav_data.ld_flags |= LNF_TIMESTAMP;
break;
case 'w':
stdin_out = optarg;
break;
case 'V':
printf("%s\n", PACKAGE_STRING);
exit(0);
break;
default:
retval = EXIT_FAILURE;
break;
}
}
argc -= optind;
argv += optind;
lnav_log_file = fopen(lnav_data.ld_debug_log_name, "a");
load_formats(lnav_data.ld_config_paths, loader_errors);
if (!loader_errors.empty()) {
for (std::vector<std::string>::iterator iter = loader_errors.begin();
iter != loader_errors.end();
@ -3786,6 +3882,10 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
if (lnav_data.ld_flags & LNF_CHECK_CONFIG) {
return EXIT_SUCCESS;
}
/* If we statically linked against an ncurses library that had a non-
* standard path to the terminfo database, we need to set this variable
* so that it will try the default path.
@ -3914,92 +4014,6 @@ int main(int argc, char *argv[])
lnav_data.ld_looping = true;
lnav_data.ld_mode = LNM_PAGING;
lnav_data.ld_debug_log_name = "/dev/null";
while ((c = getopt(argc, argv, "hHarsCc:f:d:ntw:V")) != -1) {
switch (c) {
case 'h':
usage();
exit(retval);
break;
case 'H':
lnav_data.ld_flags |= LNF_HELP;
break;
case 'C':
exit(EXIT_SUCCESS);
break;
case 'c':
switch (optarg[0]) {
case ':':
case '/':
case ';':
case '|':
break;
default:
fprintf(stderr, "error: command arguments should start with a "
"colon, semi-colon, or pipe-symbol to denote:\n");
fprintf(stderr, "error: a built-in command, SQL query, "
"or a file path that contains commands to execute\n");
usage();
exit(EXIT_FAILURE);
break;
}
lnav_data.ld_commands.push_back(optarg);
break;
case 'f':
if (access(optarg, R_OK) != 0) {
perror("invalid command file");
exit(EXIT_FAILURE);
}
lnav_data.ld_commands.push_back("|" + string(optarg));
break;
case 'd':
lnav_data.ld_debug_log_name = optarg;
break;
case 'a':
lnav_data.ld_flags |= LNF__ALL;
break;
case 'n':
lnav_data.ld_flags |= LNF_HEADLESS;
break;
case 'r':
lnav_data.ld_flags |= LNF_ROTATED;
break;
case 's':
lnav_data.ld_flags |= LNF_SYSLOG;
break;
case 't':
lnav_data.ld_flags |= LNF_TIMESTAMP;
break;
case 'w':
stdin_out = optarg;
break;
case 'V':
printf("%s\n", PACKAGE_STRING);
exit(0);
break;
default:
retval = EXIT_FAILURE;
break;
}
}
argc -= optind;
argv += optind;
lnav_log_file = fopen(lnav_data.ld_debug_log_name, "a");
if (isatty(STDIN_FILENO) && argc == 0 &&
!(lnav_data.ld_flags & LNF__ALL)) {

View File

@ -77,6 +77,7 @@ enum {
LNB_HELP,
LNB_HEADLESS,
LNB_ROTATED,
LNB_CHECK_CONFIG,
};
/** Flags set on the lnav command-line. */
@ -88,6 +89,7 @@ typedef enum {
LNF_TIMESTAMP = (1L << LNB_TIMESTAMP),
LNF_HELP = (1L << LNB_HELP),
LNF_HEADLESS = (1L << LNB_HEADLESS),
LNF_CHECK_CONFIG = (1L << LNB_CHECK_CONFIG),
LNF__ALL = (LNF_SYSLOG|LNF_HELP)
} lnav_flags_t;
@ -139,6 +141,7 @@ struct _lnav_data {
const char * ld_debug_log_name;
std::list<std::string> ld_commands;
std::vector<std::string> ld_config_paths;
std::set<std::pair<std::string, int> > ld_file_names;
std::list<logfile *> ld_files;
std::list<std::string> ld_other_files;

View File

@ -45,6 +45,10 @@
#include "format-text-files.hh"
#include "default-log-formats-json.hh"
#ifndef SYSCONFDIR
#define SYSCONFDIR "/usr/etc"
#endif
using namespace std;
static map<string, external_log_format *> LOG_FORMATS;
@ -343,53 +347,38 @@ static struct json_path_handler format_handlers[] = {
json_path_handler()
};
void load_formats(std::vector<std::string> &errors)
static void write_sample_file(void)
{
string default_source = string(dotlnav_path("formats") + "/default/");
yajlpp_parse_context ypc_builtin(default_source, format_handlers);
std::vector<std::string> retval;
yajl_handle handle;
string sample_path = dotlnav_path("formats/default/default-formats.json.sample");
auto_fd sample_fd;
{
string sample_path = dotlnav_path("formats/default/default-formats.json.sample");
auto_fd sample_fd;
if ((sample_fd = open(sample_path.c_str(),
O_WRONLY|O_TRUNC|O_CREAT,
0644)) == -1) {
perror("error: unable to write default format file");
}
else {
write(sample_fd.get(),
default_log_formats_json,
strlen(default_log_formats_json));
}
if ((sample_fd = open(sample_path.c_str(),
O_WRONLY|O_TRUNC|O_CREAT,
0644)) == -1) {
perror("error: unable to write default format file");
}
else {
write(sample_fd.get(),
default_log_formats_json,
strlen(default_log_formats_json));
}
{
string sh_path = dotlnav_path("formats/default/dump-pid.sh");
auto_fd sh_fd;
string sh_path = dotlnav_path("formats/default/dump-pid.sh");
auto_fd sh_fd;
if ((sh_fd = open(sh_path.c_str(), O_WRONLY|O_TRUNC|O_CREAT, 0755)) == -1) {
perror("error: unable to write default text file");
}
else {
write(sh_fd.get(), dump_pid_sh, strlen(dump_pid_sh));
}
if ((sh_fd = open(sh_path.c_str(), O_WRONLY|O_TRUNC|O_CREAT, 0755)) == -1) {
perror("error: unable to write default text file");
}
handle = yajl_alloc(&ypc_builtin.ypc_callbacks, NULL, &ypc_builtin);
if (yajl_parse(handle,
(const unsigned char *)default_log_formats_json,
strlen(default_log_formats_json)) != yajl_status_ok) {
errors.push_back("builtin: invalid json -- " +
string((char *)yajl_get_error(handle, 1, (unsigned char *)default_log_formats_json, strlen(default_log_formats_json))));
else {
write(sh_fd.get(), dump_pid_sh, strlen(dump_pid_sh));
}
yajl_complete_parse(handle);
yajl_free(handle);
}
string format_path = dotlnav_path("formats/*/*.json");
static void load_from_path(const string &path, std::vector<string> &errors)
{
string format_path = path + "/formats/*/*.json";
static_root_mem<glob_t, globfree> gl;
yajl_handle handle;
log_info("loading formats from path: %s", format_path.c_str());
if (glob(format_path.c_str(), 0, NULL, gl.inout()) == 0) {
@ -441,6 +430,37 @@ void load_formats(std::vector<std::string> &errors)
}
}
}
}
void load_formats(const std::vector<std::string> &extra_paths,
std::vector<std::string> &errors)
{
string default_source = string(dotlnav_path("formats") + "/default/");
yajlpp_parse_context ypc_builtin(default_source, format_handlers);
std::vector<std::string> retval;
yajl_handle handle;
write_sample_file();
handle = yajl_alloc(&ypc_builtin.ypc_callbacks, NULL, &ypc_builtin);
if (yajl_parse(handle,
(const unsigned char *)default_log_formats_json,
strlen(default_log_formats_json)) != yajl_status_ok) {
errors.push_back("builtin: invalid json -- " +
string((char *)yajl_get_error(handle, 1, (unsigned char *)default_log_formats_json, strlen(default_log_formats_json))));
}
yajl_complete_parse(handle);
yajl_free(handle);
load_from_path("/etc/lnav", errors);
load_from_path(SYSCONFDIR "/lnav", errors);
load_from_path(dotlnav_path(""), errors);
for (vector<string>::const_iterator path_iter = extra_paths.begin();
path_iter != extra_paths.end();
++path_iter) {
load_from_path(*path_iter, errors);
}
for (map<string, external_log_format *>::iterator iter = LOG_FORMATS.begin();
iter != LOG_FORMATS.end();

View File

@ -35,6 +35,7 @@
#include <vector>
#include <string>
void load_formats(std::vector<std::string> &errors);
void load_formats(const std::vector<std::string> &extra_paths,
std::vector<std::string> &errors);
#endif

View File

@ -132,6 +132,7 @@ dist_noinst_SCRIPTS = \
test_cmds.sh \
test_data_parser.sh \
test_grep_proc.sh \
test_json_format.sh \
test_line_buffer.sh \
test_listview.sh \
test_logfile.sh \
@ -164,6 +165,7 @@ dist_noinst_DATA = \
logfile_empty.0 \
logfile_generic.0 \
logfile_glog.0 \
logfile_json.json \
logfile_multiline.0 \
logfile_strace_log.0 \
logfile_syslog.0 \
@ -176,6 +178,7 @@ dist_noinst_DATA = \
vt52_curses_input.1 \
vt52_curses_output.0 \
vt52_curses_output.1 \
formats/jsontest/format.json \
log-samples/sample-27353a72ba4025448f261dcfa6ea16e474187795.txt \
log-samples/sample-70c906b3c1a1cf03f15bde92ee78edfa6f9b7960.txt \
log-samples/sample-ad31f12d2adabd07e3ddda3ad5b0dbf6b49c4c99.txt
@ -195,6 +198,7 @@ TESTS = \
test_grep_proc.sh \
test_grep_proc2 \
test_hist_source \
test_json_format.sh \
test_pcrepp \
test_sql.sh \
test_sql_coll_func.sh \
@ -211,6 +215,7 @@ XFAIL_TESTS = \
DISTCLEANFILES = \
*.dat \
*.err \
*.db \
*.dpt \
*.diff \

View File

@ -95,11 +95,11 @@ TESTS = test_ansi_scrubber$(EXEEXT) test_auto_fd$(EXEEXT) \
test_auto_mem$(EXEEXT) test_bookmarks$(EXEEXT) test_cmds.sh \
test_line_buffer.sh test_line_buffer2$(EXEEXT) \
test_listview.sh test_grep_proc.sh test_grep_proc2$(EXEEXT) \
test_hist_source$(EXEEXT) test_pcrepp$(EXEEXT) test_sql.sh \
test_sql_coll_func.sh test_sql_fs_func.sh test_sql_str_func.sh \
test_view_colors.sh test_vt52_curses.sh \
test_top_status$(EXEEXT) test_data_parser.sh \
test_yajlpp$(EXEEXT)
test_hist_source$(EXEEXT) test_json_format.sh \
test_pcrepp$(EXEEXT) test_sql.sh test_sql_coll_func.sh \
test_sql_fs_func.sh test_sql_str_func.sh test_view_colors.sh \
test_vt52_curses.sh test_top_status$(EXEEXT) \
test_data_parser.sh test_yajlpp$(EXEEXT)
subdir = test
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/mkinstalldirs $(dist_noinst_SCRIPTS) \
@ -687,6 +687,7 @@ dist_noinst_SCRIPTS = \
test_cmds.sh \
test_data_parser.sh \
test_grep_proc.sh \
test_json_format.sh \
test_line_buffer.sh \
test_listview.sh \
test_logfile.sh \
@ -719,6 +720,7 @@ dist_noinst_DATA = \
logfile_empty.0 \
logfile_generic.0 \
logfile_glog.0 \
logfile_json.json \
logfile_multiline.0 \
logfile_strace_log.0 \
logfile_syslog.0 \
@ -731,6 +733,7 @@ dist_noinst_DATA = \
vt52_curses_input.1 \
vt52_curses_output.0 \
vt52_curses_output.1 \
formats/jsontest/format.json \
log-samples/sample-27353a72ba4025448f261dcfa6ea16e474187795.txt \
log-samples/sample-70c906b3c1a1cf03f15bde92ee78edfa6f9b7960.txt \
log-samples/sample-ad31f12d2adabd07e3ddda3ad5b0dbf6b49c4c99.txt
@ -743,6 +746,7 @@ XFAIL_TESTS = \
DISTCLEANFILES = \
*.dat \
*.err \
*.db \
*.dpt \
*.diff \
@ -1190,6 +1194,13 @@ test_hist_source.log: test_hist_source$(EXEEXT)
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
test_json_format.sh.log: test_json_format.sh
@p='test_json_format.sh'; \
b='test_json_format.sh'; \
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
test_pcrepp.log: test_pcrepp$(EXEEXT)
@p='test_pcrepp$(EXEEXT)'; \
b='test_pcrepp'; \

View File

@ -52,9 +52,9 @@ int main(int argc, char *argv[])
bool prompt = false;
{
std::vector<std::string> errors;
std::vector<std::string> paths, errors;
load_formats(errors);
load_formats(paths, errors);
}
while ((c = getopt(argc, argv, "p")) != -1) {

View File

@ -0,0 +1,24 @@
{
"test_log" : {
"title" : "Test JSON Log",
"json" : true,
"file-pattern" : ".*\\.json.*",
"description" : "Test config",
"line-format" : [
{ "field" : "ts" },
" ",
{ "field" : "lvl" },
" ",
{ "field" : "msg" }
],
"level-field" : "lvl",
"timestamp-field": "ts",
"body-field" : "msg",
"value" : {
"user" : {
"kind" : "string",
"identifier" : true
}
}
}
}

2
test/logfile_json.json Normal file
View File

@ -0,0 +1,2 @@
{"ts": "2013-09-06T20:00:49.124817Z", "lvl": "INFO", "msg": "Starting up service"}
{"ts": "2013-09-06T22:00:49.124817Z", "lvl": "INFO", "msg": "Shutting down service", "user": "steve@example.com"}

14
test/test_json_format.sh Normal file
View File

@ -0,0 +1,14 @@
#! /bin/bash
lnav_test="${top_builddir}/src/lnav-test"
run_test ${lnav_test} -n \
-I ${test_dir} \
${test_dir}/logfile_json.json
check_output "json log format is not working" <<EOF
2013-09-06T20:00:49.124 INFO Starting up service
2013-09-06T22:00:49.124 INFO Shutting down service
user: steve@example.com
EOF