Allow single log file with fixed name rather than starting a new one each day.

This commit is contained in:
WB2OSZ 2017-06-17 19:39:59 -04:00
parent 647d698656
commit 52927ce54a
8 changed files with 241 additions and 95 deletions

View File

@ -9,10 +9,11 @@ This is a snapshot of ongoing development towards version of 1.5. Some features
- Time slots for beaconing. - Time slots for beaconing.
- V20 configuration item for listing stations known not to understaand AX.25 v2.2. This will speed up connection by going right to SABM and not trying SABME first and failing.
- Documentation updates describing cheap SDR frequency inaccuracy and how to compensate for it. - Documentation updates describing cheap SDR frequency inaccuracy and how to compensate for it.
- Allow single log file with fixed name rather than starting a new one each day.
### Bugs Fixed: ### ### Bugs Fixed: ###
- PACLEN configuration item no longer restricts length of received frames. - PACLEN configuration item no longer restricts length of received frames.
@ -31,7 +32,7 @@ This is a snapshot of ongoing development towards version of 1.5. Some features
- decode_aprs utility can now accept KISS frames and AX.25 frames as series of two digit hexadecimal numbers. - decode_aprs utility can now accept KISS frames and AX.25 frames as series of two digit hexadecimal numbers.
- New configuration option, V20, for listing stations known to not understand AX.25 v2.2. - New configuration option, V20, for listing stations known to not understand AX.25 v2.2. This will speed up connection by going right to SABM and not trying SABME first and failing.
### Bugs Fixed: ### ### Bugs Fixed: ###

View File

@ -877,7 +877,8 @@ void config_init (char *fname, struct audio_s *p_audio_config,
strlcpy (p_misc_config->gpsnmea_port, "", sizeof(p_misc_config->gpsnmea_port)); strlcpy (p_misc_config->gpsnmea_port, "", sizeof(p_misc_config->gpsnmea_port));
strlcpy (p_misc_config->waypoint_port, "", sizeof(p_misc_config->waypoint_port)); strlcpy (p_misc_config->waypoint_port, "", sizeof(p_misc_config->waypoint_port));
strlcpy (p_misc_config->logdir, "", sizeof(p_misc_config->logdir)); p_misc_config->log_daily_names = 0;
strlcpy (p_misc_config->log_path, "", sizeof(p_misc_config->log_path));
/* connected mode. */ /* connected mode. */
@ -4283,7 +4284,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
} }
/* /*
* LOGDIR - Directory name for storing log files. Use "." for current working directory. * LOGDIR - Directory name for automatically named daily log files. Use "." for current working directory.
*/ */
else if (strcasecmp(t, "logdir") == 0) { else if (strcasecmp(t, "logdir") == 0) {
t = split(NULL,0); t = split(NULL,0);
@ -4293,7 +4294,12 @@ void config_init (char *fname, struct audio_s *p_audio_config,
continue; continue;
} }
else { else {
strlcpy (p_misc_config->logdir, t, sizeof(p_misc_config->logdir)); if (strlen(p_misc_config->log_path) > 0) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: LOGDIR on line %d is replacing an earlier LOGDIR or LOGFILE.\n", line);
}
p_misc_config->log_daily_names = 1;
strlcpy (p_misc_config->log_path, t, sizeof(p_misc_config->log_path));
} }
t = split(NULL,0); t = split(NULL,0);
if (t != NULL) { if (t != NULL) {
@ -4302,6 +4308,31 @@ void config_init (char *fname, struct audio_s *p_audio_config,
} }
} }
/*
* LOGFILE - Log file name, including any directory part.
*/
else if (strcasecmp(t, "logfile") == 0) {
t = split(NULL,0);
if (t == NULL) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: Missing file name for LOGFILE on line %d.\n", line);
continue;
}
else {
if (strlen(p_misc_config->log_path) > 0) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: LOGFILE on line %d is replacing an earlier LOGDIR or LOGFILE.\n", line);
}
p_misc_config->log_daily_names = 0;
strlcpy (p_misc_config->log_path, t, sizeof(p_misc_config->log_path));
}
t = split(NULL,0);
if (t != NULL) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Config file: LOGFILE on line %d should have file name and nothing more.\n", line);
}
}
/* /*
* BEACON channel delay every message * BEACON channel delay every message
* *

View File

@ -77,7 +77,9 @@ struct misc_config_s {
#define WPT_FORMAT_KENWOOD 0x08 /* K $PKWDWPL */ #define WPT_FORMAT_KENWOOD 0x08 /* K $PKWDWPL */
char logdir[80]; /* Directory for saving activity logs. */ int log_daily_names; /* True to generate new log file each day. */
char log_path[80]; /* Either directory or full file name depending on above. */
int sb_configured; /* TRUE if SmartBeaconing is configured. */ int sb_configured; /* TRUE if SmartBeaconing is configured. */
int sb_fast_speed; /* MPH */ int sb_fast_speed; /* MPH */

View File

@ -194,7 +194,8 @@ int main (int argc, char *argv[])
struct igate_config_s igate_config; struct igate_config_s igate_config;
int r_opt = 0, n_opt = 0, b_opt = 0, B_opt = 0, D_opt = 0; /* Command line options. */ int r_opt = 0, n_opt = 0, b_opt = 0, B_opt = 0, D_opt = 0; /* Command line options. */
char P_opt[16]; char P_opt[16];
char l_opt[80]; char l_opt_logdir[80];
char L_opt_logfile[80];
char input_file[80]; char input_file[80];
// char timestamp[16]; // char timestamp[16];
@ -215,7 +216,8 @@ int main (int argc, char *argv[])
int E_tx_opt = 0; /* "-E n" Error rate % for clobbering trasmit frames. */ int E_tx_opt = 0; /* "-E n" Error rate % for clobbering trasmit frames. */
int E_rx_opt = 0; /* "-E Rn" Error rate % for clobbering receive frames. */ int E_rx_opt = 0; /* "-E Rn" Error rate % for clobbering receive frames. */
strlcpy(l_opt, "", sizeof(l_opt)); strlcpy(l_opt_logdir, "", sizeof(l_opt_logdir));
strlcpy(L_opt_logfile, "", sizeof(L_opt_logfile));
strlcpy(P_opt, "", sizeof(P_opt)); strlcpy(P_opt, "", sizeof(P_opt));
#if __WIN32__ #if __WIN32__
@ -356,7 +358,7 @@ int main (int argc, char *argv[])
/* ':' following option character means arg is required. */ /* ':' following option character means arg is required. */
c = getopt_long(argc, argv, "P:B:D:c:pxr:b:n:d:q:t:Ul:Sa:E:", c = getopt_long(argc, argv, "P:B:D:c:pxr:b:n:d:q:t:Ul:L:Sa:E:",
long_options, &option_index); long_options, &option_index);
if (c == -1) if (c == -1)
break; break;
@ -532,11 +534,17 @@ int main (int argc, char *argv[])
exit (0); exit (0);
break; break;
case 'l': /* -l for log file directory name */ case 'l': /* -l for log directory with daily files */
strlcpy (l_opt, optarg, sizeof(l_opt)); strlcpy (l_opt_logdir, optarg, sizeof(l_opt_logdir));
break; break;
case 'L': /* -L for log file name with full path */
strlcpy (L_opt_logfile, optarg, sizeof(L_opt_logfile));
break;
case 'S': /* Print symbol tables and exit. */ case 'S': /* Print symbol tables and exit. */
symbols_init (); symbols_init ();
@ -674,8 +682,19 @@ int main (int argc, char *argv[])
audio_config.recv_error_rate = E_rx_opt; audio_config.recv_error_rate = E_rx_opt;
if (strlen(l_opt) > 0) { if (strlen(l_opt_logdir) > 0 && strlen(L_opt_logfile) > 0) {
strlcpy (misc_config.logdir, l_opt, sizeof(misc_config.logdir)); text_color_set(DW_COLOR_ERROR);
dw_printf ("Logging options -l and -L can't be used together. Pick one or the other.\n");
exit(1);
}
if (strlen(L_opt_logfile) > 0) {
misc_config.log_daily_names = 0;
strlcpy (misc_config.log_path, L_opt_logfile, sizeof(misc_config.log_path));
}
else if (strlen(l_opt_logdir) > 0) {
misc_config.log_daily_names = 1;
strlcpy (misc_config.log_path, l_opt_logdir, sizeof(misc_config.log_path));
} }
misc_config.enable_kiss_pt = enable_pseudo_terminal; misc_config.enable_kiss_pt = enable_pseudo_terminal;
@ -794,7 +813,7 @@ int main (int argc, char *argv[])
* log the tracker beacon transmissions with fake channel 999. * log the tracker beacon transmissions with fake channel 999.
*/ */
log_init(misc_config.logdir); log_init(misc_config.log_daily_names, misc_config.log_path);
mheard_init (d_m_opt); mheard_init (d_m_opt);
beacon_init (&audio_config, &misc_config, &igate_config); beacon_init (&audio_config, &misc_config, &igate_config);

Binary file not shown.

125
log.c
View File

@ -28,6 +28,13 @@
* unreadable, format, write separated properties into * unreadable, format, write separated properties into
* CSV format for easy reading and later processing. * CSV format for easy reading and later processing.
* *
* There are two alternatives here.
*
* -L logfile Specify full file path.
*
* -l logdir Daily names will be created here.
*
* Use one or the other but not both.
* *
*------------------------------------------------------------------*/ *------------------------------------------------------------------*/
@ -91,26 +98,39 @@ static void quote_for_csv (char *out, size_t outsize, const char *in) {
* *
* Purpose: Initialization at start of application. * Purpose: Initialization at start of application.
* *
* Inputs: path - Path of log file directory. * Inputs: daily_names - True if daily names should be generated.
* In this case path is a directory.
* When false, path would be the file name.
*
* path - Log file name or just directory.
* Use "." for current directory. * Use "." for current directory.
* Empty string disables feature. * Empty string disables feature.
* *
* Global Out: g_log_dir - Save directory here for later use. * Global Out: g_daily_names - True if daily names should be generated.
*
* g_log_path - Save directory or full name here for later use.
*
* g_log_fp - File pointer for writing. * g_log_fp - File pointer for writing.
* Note that file is kept open.
* We don't open/close for every new item.
*
* g_open_fname - Name of currently open file. * g_open_fname - Name of currently open file.
* Applicable only when g_daily_names is true.
* *
*------------------------------------------------------------------*/ *------------------------------------------------------------------*/
static char g_log_dir[80]; static int g_daily_names;
static char g_log_path[80];
static FILE *g_log_fp; static FILE *g_log_fp;
static char g_open_fname[20]; static char g_open_fname[20];
void log_init (char *path) void log_init (int daily_names, char *path)
{ {
struct stat st; struct stat st;
strlcpy (g_log_dir, "", sizeof(g_log_dir)); g_daily_names = daily_names;
strlcpy (g_log_path, "", sizeof(g_log_path));
g_log_fp = NULL; g_log_fp = NULL;
strlcpy (g_open_fname, "", sizeof(g_open_fname)); strlcpy (g_open_fname, "", sizeof(g_open_fname));
@ -118,17 +138,21 @@ void log_init (char *path)
return; return;
} }
if (g_daily_names) {
// Original strategy. Automatic daily file names.
if (stat(path,&st) == 0) { if (stat(path,&st) == 0) {
// Exists, but is it a directory? // Exists, but is it a directory?
if (S_ISDIR(st.st_mode)) { if (S_ISDIR(st.st_mode)) {
// Specified directory exists. // Specified directory exists.
strlcpy (g_log_dir, path, sizeof(g_log_dir)); strlcpy (g_log_path, path, sizeof(g_log_path));
} }
else { else {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Log file location \"%s\" is not a directory.\n", path); dw_printf ("Log file location \"%s\" is not a directory.\n", path);
dw_printf ("Using current working directory \".\" instead.\n"); dw_printf ("Using current working directory \".\" instead.\n");
strlcpy (g_log_dir, ".", sizeof(g_log_dir)); strlcpy (g_log_path, ".", sizeof(g_log_path));
} }
} }
else { else {
@ -143,17 +167,28 @@ void log_init (char *path)
// Success. // Success.
text_color_set(DW_COLOR_INFO); text_color_set(DW_COLOR_INFO);
dw_printf ("Log file location \"%s\" has been created.\n", path); dw_printf ("Log file location \"%s\" has been created.\n", path);
strlcpy (g_log_dir, path, sizeof(g_log_dir)); strlcpy (g_log_path, path, sizeof(g_log_path));
} }
else { else {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Failed to create log file location \"%s\".\n", path); dw_printf ("Failed to create log file location \"%s\".\n", path);
dw_printf ("%s\n", strerror(errno)); dw_printf ("%s\n", strerror(errno));
dw_printf ("Using current working directory \".\" instead.\n"); dw_printf ("Using current working directory \".\" instead.\n");
strlcpy (g_log_dir, ".", sizeof(g_log_dir)); strlcpy (g_log_path, ".", sizeof(g_log_path));
} }
} }
} }
else {
// Added in version 1.5. Single file.
// Typically logrotate would be used to keep size under control.
text_color_set(DW_COLOR_INFO);
dw_printf ("Log file is \"%s\"\n", path);
strlcpy (g_log_path, path, sizeof(g_log_path));
}
} /* end log_init */
@ -177,17 +212,25 @@ void log_init (char *path)
void log_write (int chan, decode_aprs_t *A, packet_t pp, alevel_t alevel, retry_t retries) void log_write (int chan, decode_aprs_t *A, packet_t pp, alevel_t alevel, retry_t retries)
{ {
time_t now; // make 'now' a parameter so we can process historical data ??? time_t now;
char fname[20];
struct tm tm; struct tm tm;
if (strlen(g_log_dir) == 0) return; if (strlen(g_log_path) == 0) return;
now = time(NULL); // Get current time.
(void)gmtime_r (&now, &tm);
if (g_daily_names) {
// Original strategy. Automatic daily file names.
char fname[20];
// Generate the file name from current date, UTC. // Generate the file name from current date, UTC.
// Why UTC rather than local time? I don't recall the reasoning.
now = time(NULL); // It's been there a few years and no on complained so leave it alone for now.
(void)gmtime_r (&now, &tm);
// Microsoft doesn't recognize %F as equivalent to %Y-%m-%d // Microsoft doesn't recognize %F as equivalent to %Y-%m-%d
@ -206,7 +249,7 @@ void log_write (int chan, decode_aprs_t *A, packet_t pp, alevel_t alevel, retry_
struct stat st; struct stat st;
int already_there; int already_there;
strlcpy (full_path, g_log_dir, sizeof(full_path)); strlcpy (full_path, g_log_path, sizeof(full_path));
#if __WIN32__ #if __WIN32__
strlcat (full_path, "\\", sizeof(full_path)); strlcat (full_path, "\\", sizeof(full_path));
#else #else
@ -214,10 +257,10 @@ void log_write (int chan, decode_aprs_t *A, packet_t pp, alevel_t alevel, retry_
#endif #endif
strlcat (full_path, fname, sizeof(full_path)); strlcat (full_path, fname, sizeof(full_path));
// See if it already exists. // See if file already exists and not empty.
// This is used later to write a header if it did not exist already. // This is used later to write a header if it did not exist already.
already_there = stat(full_path,&st) == 0; already_there = (stat(full_path,&st) == 0) && (st.st_size > 0);
text_color_set(DW_COLOR_INFO); text_color_set(DW_COLOR_INFO);
dw_printf("Opening log file \"%s\".\n", fname); dw_printf("Opening log file \"%s\".\n", fname);
@ -242,6 +285,46 @@ void log_write (int chan, decode_aprs_t *A, packet_t pp, alevel_t alevel, retry_
fprintf (g_log_fp, "chan,utime,isotime,source,heard,level,error,dti,name,symbol,latitude,longitude,speed,course,altitude,frequency,offset,tone,system,status,telemetry,comment\n"); fprintf (g_log_fp, "chan,utime,isotime,source,heard,level,error,dti,name,symbol,latitude,longitude,speed,course,altitude,frequency,offset,tone,system,status,telemetry,comment\n");
} }
} }
}
else {
// Added in version 1.5. Single file.
// Open for append if not already open.
if (g_log_fp == NULL) {
struct stat st;
int already_there;
// See if file already exists and not empty.
// This is used later to write a header if it did not exist already.
already_there = (stat(g_log_path,&st) == 0) && (st.st_size > 0);
text_color_set(DW_COLOR_INFO);
dw_printf("Opening log file \"%s\"\n", g_log_path);
g_log_fp = fopen (g_log_path, "a");
if (g_log_fp == NULL) {
text_color_set(DW_COLOR_ERROR);
dw_printf("Can't open log file \"%s\" for write.\n", g_log_path);
dw_printf ("%s\n", strerror(errno));
strlcpy (g_log_path, "", sizeof(g_log_path));
return;
}
// Write a header suitable for importing into a spreadsheet
// only if this will be the first line.
if ( ! already_there) {
fprintf (g_log_fp, "chan,utime,isotime,source,heard,level,error,dti,name,symbol,latitude,longitude,speed,course,altitude,frequency,offset,tone,system,status,telemetry,comment\n");
}
}
}
// Add line to file if it is now open.
if (g_log_fp != NULL) { if (g_log_fp != NULL) {
@ -439,7 +522,13 @@ void log_term (void)
if (g_log_fp != NULL) { if (g_log_fp != NULL) {
text_color_set(DW_COLOR_INFO); text_color_set(DW_COLOR_INFO);
if (g_daily_names) {
dw_printf("Closing log file \"%s\".\n", g_open_fname); dw_printf("Closing log file \"%s\".\n", g_open_fname);
}
else {
dw_printf("Closing log file \"%s\".\n", g_log_path);
}
fclose (g_log_fp); fclose (g_log_fp);

2
log.h
View File

@ -10,7 +10,7 @@
void log_init (char *path); void log_init (int daily_names, char *path);
void log_write (int chan, decode_aprs_t *A, packet_t pp, alevel_t alevel, retry_t retries); void log_write (int chan, decode_aprs_t *A, packet_t pp, alevel_t alevel, retry_t retries);

View File

@ -27,8 +27,12 @@ RMS Express, and many others.
Read configuration file from specified location rather than the default locations. Read configuration file from specified location rather than the default locations.
.TP .TP
.BI "-l " "dir" .BI "-l " "logdir"
Generate log files in specified directory. Use "." for current directory. Generate daily log files in specified directory. Use "." for current directory.
.TP
.BI "-L " "logfile"
Generate single log file with fixed name.
.TP .TP
.BI "-r " "n" .BI "-r " "n"