diff --git a/README.md b/README.md index c78bc07..8857bd6 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Add --verbose for detailed debug information. --robot or --robot=json for json output. --robot=fields for semicolon separated fields. --separator=X change field separator to X. + --logfile=file --meterfiles=dir to create status files below dir, named dir/meter_name, containing the latest reading. --meterfiles defaults dir to /tmp. diff --git a/install.sh b/install.sh index c8d061d..03af17a 100755 --- a/install.sh +++ b/install.sh @@ -128,6 +128,7 @@ device=auto logtelegrams=false robot=json meterfilesdir=/var/log/wmbusmeters/meter_readings +logfile=/var/log/wmbusmeters/wmbusmeters.log EOF chmod 644 $ROOT/etc/wmbusmeters.conf echo conf file: created $ROOT/etc/wmbusmeters.conf diff --git a/src/cmdline.cc b/src/cmdline.cc index 0981fcf..9e6eccc 100644 --- a/src/cmdline.cc +++ b/src/cmdline.cc @@ -147,6 +147,19 @@ unique_ptr parseCommandLine(int argc, char **argv) { i++; continue; } + if (!strncmp(argv[i], "--logfile=", 10)) { + c->use_logfile = true; + if (strlen(argv[i]) > 10) { + size_t len = strlen(argv[i])-10; + if (len > 0) { + c->logfile = string(argv[i]+10, len); + } else { + error("Not a valid log file name."); + } + } + i++; + continue; + } if (!strncmp(argv[i], "--shell=", 8)) { string cmd = string(argv[i]+8); if (cmd == "") { diff --git a/src/config.cc b/src/config.cc index 0064fa7..6fb611a 100644 --- a/src/config.cc +++ b/src/config.cc @@ -118,6 +118,15 @@ void handleMeterfilesdir(Configuration *c, string meterfilesdir) } } +void handleLogfile(Configuration *c, string logfile) +{ + if (logfile.length() > 0) + { + c->use_logfile = true; + c->logfile = logfile; + } +} + void handleRobot(Configuration *c, string robot) { if (robot == "json") @@ -162,6 +171,7 @@ unique_ptr loadConfiguration(string root) else if (p.first == "device") handleDevice(c, p.second); else if (p.first == "logtelegrams") handleLogtelegrams(c, p.second); else if (p.first == "meterfilesdir") handleMeterfilesdir(c, p.second); + else if (p.first == "logfile") handleLogfile(c, p.second); else if (p.first == "robot") handleRobot(c, p.second); else if (p.first == "separator") handleSeparator(c, p.second); else diff --git a/src/config.h b/src/config.h index adc7ade..c56129d 100644 --- a/src/config.h +++ b/src/config.h @@ -55,6 +55,8 @@ struct Configuration { bool logtelegrams {}; bool meterfiles {}; std::string meterfiles_dir; + bool use_logfile {}; + std::string logfile; bool json {}; bool fields {}; char separator { ';' }; diff --git a/src/main.cc b/src/main.cc index 7961be2..9e0abe9 100644 --- a/src/main.cc +++ b/src/main.cc @@ -54,6 +54,7 @@ int main(int argc, char **argv) printf(" --robot or --robot=json for json output.\n"); printf(" --robot=fields for semicolon separated fields.\n"); printf(" --separator=X change field separator to X.\n"); + printf(" --logfile=file\n"); printf(" --meterfiles=dir to create status files below dir,\n" " named dir/meter_name, containing the latest reading.\n"); printf(" --meterfiles defaults dir to /tmp.\n"); @@ -315,8 +316,19 @@ void startDaemon(string pid_file) void startUsingConfigFiles(string root, bool is_daemon) { - unique_ptr cmdline = loadConfiguration(root); - cmdline->daemon = is_daemon; + unique_ptr config = loadConfiguration(root); + config->daemon = is_daemon; - startUsingCommandline(cmdline.get()); + if (config->use_logfile) { + bool ok = enableLogfile(config->logfile); + if (!ok) { + if (is_daemon) { + warning("Could not open log file, will use syslog instead.\n"); + } else { + error("Could not open log file.\n"); + } + } + } + + startUsingCommandline(config.get()); } diff --git a/src/meters_common_implementation.h b/src/meters_common_implementation.h index f746903..8eb1d0c 100644 --- a/src/meters_common_implementation.h +++ b/src/meters_common_implementation.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2019 Fredrik Öhrström + Copyright (C) 2018-2019 Fredrik Öhrström 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 diff --git a/src/printer.cc b/src/printer.cc index df49f74..775fefb 100644 --- a/src/printer.cc +++ b/src/printer.cc @@ -68,18 +68,29 @@ void Printer::printFiles(Meter *meter, string &human_readable, string &fields, s warning("Could not open file \"%s\" for writing!\n", filename); } } - if (json_) { - fprintf(output, "%s\n", json.c_str()); + if (output) { + fprintf(output, "%s\n", json.c_str()); + } else { + notice("%s\n", json.c_str()); + } } else if (fields_) { - fprintf(output, "%s\n", fields.c_str()); + if (output) { + fprintf(output, "%s\n", fields.c_str()); + } else { + notice("%s\n", fields.c_str()); + } } else { - fprintf(output, "%s\n", human_readable.c_str()); + if (output) { + fprintf(output, "%s\n", human_readable.c_str()); + } else { + notice("%s\n", human_readable.c_str()); + } } - if (output != stdout) { + if (output != stdout && output) { fclose(output); } } diff --git a/src/util.cc b/src/util.cc index 3ce38b1..29e5b6c 100644 --- a/src/util.cc +++ b/src/util.cc @@ -148,11 +148,14 @@ void error(const char* fmt, ...) { } bool syslog_enabled_ = false; +bool logfile_enabled_ = false; bool warning_enabled_ = true; bool verbose_enabled_ = false; bool debug_enabled_ = false; bool log_telegrams_enabled_ = false; +string log_file_; + void warningSilenced(bool b) { warning_enabled_ = !b; } @@ -161,6 +164,26 @@ void enableSyslog() { syslog_enabled_ = true; } +bool enableLogfile(string logfile) { + log_file_ = logfile; + logfile_enabled_ = true; + FILE *output = fopen(log_file_.c_str(), "a"); + if (output) { + char buf[256]; + time_t now = time(NULL); + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&now)); + int n = fprintf(output, "(wmbusmeters) logging started %s\n", buf); + fclose(output); + if (n == 0) { + logfile_enabled_ = false; + return false; + } + return true; + } + logfile_enabled_ = false; + return false; +} + void verboseEnabled(bool b) { verbose_enabled_ = b; } @@ -192,25 +215,47 @@ bool isLogTelegramsEnabled() { return log_telegrams_enabled_; } +void outputStuff(int syslog_level, const char *fmt, va_list args) +{ + if (logfile_enabled_) + { + // Open close at every log occasion, should not be too big of + // a performance issue, since normal reception speed of + // wmbusmessages are quite low. + FILE *output = fopen(log_file_.c_str(), "a"); + if (output) { + vfprintf(output, fmt, args); + fclose(output); + } else { + // Ouch, disable the log file. + // Reverting to syslog or stdout depending on settings. + logfile_enabled_ = false; + // This warning might be written in syslog or stdout. + warning("Log file could not be written!\n"); + // Try again with logfile disabled. + outputStuff(syslog_level, fmt, args); + return; + } + } else + if (syslog_enabled_) { + vsyslog(syslog_level, fmt, args); + } + else { + vprintf(fmt, args); + } +} + void info(const char* fmt, ...) { va_list args; va_start(args, fmt); - if (syslog_enabled_) { - vsyslog(LOG_NOTICE, fmt, args); - } else { - vprintf(fmt, args); - } + outputStuff(LOG_INFO, fmt, args); va_end(args); } void notice(const char* fmt, ...) { va_list args; va_start(args, fmt); - if (syslog_enabled_) { - vsyslog(LOG_NOTICE, fmt, args); - } else { - vprintf(fmt, args); - } + outputStuff(LOG_NOTICE, fmt, args); va_end(args); } @@ -218,11 +263,7 @@ void warning(const char* fmt, ...) { if (warning_enabled_) { va_list args; va_start(args, fmt); - if (syslog_enabled_) { - vsyslog(LOG_WARNING, fmt, args); - } else { - vprintf(fmt, args); - } + outputStuff(LOG_WARNING, fmt, args); va_end(args); } } @@ -231,11 +272,7 @@ void verbose(const char* fmt, ...) { if (verbose_enabled_) { va_list args; va_start(args, fmt); - if (syslog_enabled_) { - vsyslog(LOG_NOTICE, fmt, args); - } else { - vprintf(fmt, args); - } + outputStuff(LOG_NOTICE, fmt, args); va_end(args); } } @@ -244,11 +281,7 @@ void debug(const char* fmt, ...) { if (debug_enabled_) { va_list args; va_start(args, fmt); - if (syslog_enabled_) { - vsyslog(LOG_NOTICE, fmt, args); - } else { - vprintf(fmt, args); - } + outputStuff(LOG_NOTICE, fmt, args); va_end(args); } } diff --git a/src/util.h b/src/util.h index 3ec6f44..881377f 100644 --- a/src/util.h +++ b/src/util.h @@ -39,6 +39,7 @@ void strprintf(std::string &s, const char* fmt, ...); void xorit(uchar *srca, uchar *srcb, uchar *dest, int len); +bool enableLogfile(std::string logfile); void enableSyslog(); void error(const char* fmt, ...); void verbose(const char* fmt, ...); diff --git a/test.sh b/test.sh index 6f0b12e..fcaa2bd 100755 --- a/test.sh +++ b/test.sh @@ -13,3 +13,4 @@ tests/test_t1_meters.sh $PROG tests/test_shell.sh $PROG tests/test_meterfiles.sh $PROG tests/test_config1.sh $PROG +tests/test_logfile.sh $PROG diff --git a/tests/config2/etc/wmbusmeters.conf b/tests/config2/etc/wmbusmeters.conf new file mode 100644 index 0000000..020f3a7 --- /dev/null +++ b/tests/config2/etc/wmbusmeters.conf @@ -0,0 +1,6 @@ +loglevel=normal +device=simulations/simulation_t1.txt +logtelegrams=false +robot=json +meterfilesdir=testoutput/meter_readings2 +logfile=testoutput/thelog2.txt diff --git a/tests/test_logfile.sh b/tests/test_logfile.sh new file mode 100755 index 0000000..6f312f0 --- /dev/null +++ b/tests/test_logfile.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +PROG="$1" +TEST=testoutput +mkdir -p $TEST/meter_readings2 + +cat simulations/simulation_t1.txt | grep '^{' > $TEST/test_expected.txt + +WMBUSMETERS_CONFIG_ROOT=tests/config2 $PROG --useconfig