diff options
author | Michał Łyszczek <michal.lyszczek@bofc.pl> | 2018-04-15 20:03:57 +0200 |
---|---|---|
committer | Michał Łyszczek <michal.lyszczek@bofc.pl> | 2018-04-15 20:15:05 +0200 |
commit | 4449096e93f1f5f6e667bc358ea48bfe335aa557 (patch) | |
tree | fef78a0c82651a29b6fbfd34c1e4e92e8b9e9499 | |
parent | 905421aac941de7eaeb5b23a2c8742fd36f29f23 (diff) | |
download | embedlog-4449096e93f1f5f6e667bc358ea48bfe335aa557.tar.gz embedlog-4449096e93f1f5f6e667bc358ea48bfe335aa557.tar.bz2 embedlog-4449096e93f1f5f6e667bc358ea48bfe335aa557.zip |
add possibility to always sync do disc chosen log levels
-rw-r--r-- | include/embedlog.h | 3 | ||||
-rw-r--r-- | man/el_option.3 | 35 | ||||
-rw-r--r-- | readme.md | 4 | ||||
-rw-r--r-- | src/el-file.c | 41 | ||||
-rw-r--r-- | src/el-options.c | 8 | ||||
-rw-r--r-- | src/el-print.c | 20 | ||||
-rw-r--r-- | tst/Makefile.am | 1 | ||||
-rw-r--r-- | tst/test-el-file.c | 118 | ||||
-rw-r--r-- | tst/test-el-options.c | 29 |
9 files changed, 254 insertions, 5 deletions
diff --git a/include/embedlog.h b/include/embedlog.h index cc68043..29cbba8 100644 --- a/include/embedlog.h +++ b/include/embedlog.h @@ -104,6 +104,7 @@ enum el_option EL_FROTATE_NUMBER, EL_FROTATE_SIZE, EL_FILE_SYNC_EVERY, + EL_FILE_SYNC_LEVEL, EL_OPT_ERROR /* internal use only */ }; @@ -140,6 +141,8 @@ struct el_options unsigned int print_newline:1; unsigned int finfo:1; unsigned int level:3; + unsigned int level_current_msg:3; + unsigned int file_sync_level:3; int serial_fd; int frotate_number; diff --git a/man/el_option.3 b/man/el_option.3 index e8107a1..29bd814 100644 --- a/man/el_option.3 +++ b/man/el_option.3 @@ -494,6 +494,41 @@ Value is less than 0 . RE .RE .PP +.BI "EL_FILE_SYNC_LEVEL (" enum " " el_level " level)" +.RS +If level of printed message is +. I level +or less (that is higher priority), it will be synced to disk every single time +regardless of +. B EL_FILE_SYNC_EVERY +option. +Messages with level +. B EL_FATAL +(that is also default value for level sync) are synced always regardless of any +options set. +Messages printed with functions that don't take log level, will be treated as +messages with +. B EL_DBG +level. +If +. I level +is set to +. B EL_DBG +every message printed with any function will be immediately synced to drive +(careful with that, this will impact performance a great deal if you print a lot +of debug messages). +. PP +. B ERRORS +. RS +. B EINVAL +. RS +specified +. I level +is invalid (bigger than EL_DBG). +. RE +. RE +.RE +.PP .BI "EL_TTY_DEV (" const\ char\ * "dev, " speed_t " speed)" .RS Tells @@ -11,8 +11,10 @@ systems, it is general **c/c++** logger that can be used in any application. Implemented features are: * printing to different outputs (simultaneously) like: + * syslog + * directly to serial device (like /dev/ttyS0) * standard error (stderr) - * file (with optional log rotate) + * file (with optional log rotate, and syncing to prevent data loss) * custom routine - can be anything **embedlog** just calls custom function with string to print * appending timestamp to every message diff --git a/src/el-file.c b/src/el-file.c index dff93f8..80bb3bd 100644 --- a/src/el-file.c +++ b/src/el-file.c @@ -62,6 +62,34 @@ /* ========================================================================== + __ __ __ + ____ _ / /____ / /_ ____ _ / / + / __ `// // __ \ / __ \ / __ `// / + / /_/ // // /_/ // /_/ // /_/ // / + \__, //_/ \____//_.___/ \__,_//_/ + /____/ + _ __ __ + _ __ ____ _ _____ (_)____ _ / /_ / /___ _____ + | | / // __ `// ___// // __ `// __ \ / // _ \ / ___/ + | |/ // /_/ // / / // /_/ // /_/ // // __/(__ ) + |___/ \__,_//_/ /_/ \__,_//_.___//_/ \___//____/ + + ========================================================================== */ + + +#ifdef RUN_TESTS + +/* + * there is no easy way to check if file has been fsynced to disk or not, + * so we introduce this helper variable to know if we executed syncing + * code or not + */ +extern int file_synced; + +#endif + + +/* ========================================================================== _ __ ____ _____ (_)_ __ ____ _ / /_ ___ / __ \ / ___// /| | / // __ `// __// _ \ @@ -602,7 +630,8 @@ int el_file_puts options->fpos += sl; options->written_after_sync += sl; - if (options->written_after_sync >= options->file_sync_every) + if (options->written_after_sync >= options->file_sync_every || + options->level_current_msg <= options->file_sync_level) { /* * file store operation has particular issue. You can like, write @@ -624,7 +653,7 @@ int el_file_puts #if HAVE_FSYNC && HAVE_FILENO int fd; /* systems file descriptor for options->file */ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -#endif +#endif /* HAVE_FSYNC && HAVE_FILENO */ /* * first flush data from stdio library buffers into kernel @@ -649,7 +678,7 @@ int el_file_puts { return -1; } -#else +#else /* HAVE_FSYNC && HAVE_FILENO */ /* * if system does not implement fileno and fsync our only hope lies * int closing (which should sync file to block device) and then @@ -664,7 +693,11 @@ int el_file_puts errno = EBADF; return -1; } -#endif + +#ifdef RUN_TESTS + file_synced = 1; +#endif /* RUN_TESTS */ +#endif /* HAVE_FSYNC && HAVE_FILENO */ options->written_after_sync = 0; } diff --git a/src/el-options.c b/src/el-options.c index 3c2a2d0..a43dd89 100644 --- a/src/el-options.c +++ b/src/el-options.c @@ -166,6 +166,12 @@ static int el_vooption options->level = value_int; return 0; + case EL_FILE_SYNC_LEVEL: + value_int = va_arg(ap, int); + VALID(EINVAL, value_int <= 7); + options->file_sync_level = value_int; + return 0; + case EL_OUT: value_int = va_arg(ap, int); VALID(EINVAL, (value_int & ~EL_OUT_ALL) == 0x00); @@ -399,6 +405,8 @@ int el_oinit options->print_newline = 1; options->timestamp_useconds = 1; options->level = EL_INFO; + options->level_current_msg = EL_DBG; + options->file_sync_level = EL_FATAL; options->serial_fd = -1; options->file_sync_every = 32768; return 0; diff --git a/src/el-print.c b/src/el-print.c index 2299e27..c513e3a 100644 --- a/src/el-print.c +++ b/src/el-print.c @@ -694,11 +694,31 @@ int el_ovprint buf[w++] = '\0'; + /* + * some modules (like el-file) needs to know level of message they are + * printing, and such information may not be available from string, thus + * we set it here in a 'object global' variable + */ + + options->level_current_msg = level; + if (el_oputs(options, buf) != 0) { + options->level_current_msg = EL_DBG; return -1; } + /* + * after message is printed set current messasge level to debug, as next + * call might be using el_puts, which does not contain log level, and we + * thread all el_puts messages as they were debug. Note, it does not + * apply to log filtering, el_puts does not filter messages, but modules + * like el-file, will need this information to determin wheter fsync() + * data to file or not. + */ + + options->level_current_msg = EL_DBG; + if (e) { errno = e; diff --git a/tst/Makefile.am b/tst/Makefile.am index fe72bc6..b07cfbc 100644 --- a/tst/Makefile.am +++ b/tst/Makefile.am @@ -16,6 +16,7 @@ test_CFLAGS = -I$(top_srcdir)/include \ -I$(top_srcdir)/src \ -I/usr/local/include \ -I/usr/include \ + -DRUN_TESTS=1 \ $(COVERAGE_CFLAGS) test_LDFLAGS = -L/usr/local/lib \ diff --git a/tst/test-el-file.c b/tst/test-el-file.c index 864ec65..4fa7980 100644 --- a/tst/test-el-file.c +++ b/tst/test-el-file.c @@ -30,6 +30,29 @@ /* ========================================================================== + __ __ __ + ____ _ / /____ / /_ ____ _ / / + / __ `// // __ \ / __ \ / __ `// / + / /_/ // // /_/ // /_/ // /_/ // / + \__, //_/ \____//_.___/ \__,_//_/ + /____/ + _ __ __ + _ __ ____ _ _____ (_)____ _ / /_ / /___ _____ + | | / // __ `// ___// // __ `// __ \ / // _ \ / ___/ + | |/ // /_/ // / / // /_/ // /_/ // // __/(__ ) + |___/ \__,_//_/ /_/ \__,_//_.___//_/ \___//____/ + + ========================================================================== */ + + +/* + * variable is set in el-file.c when we successfully executed fsync path of + * the code + */ +int file_synced; + + +/* ========================================================================== _ __ ____ _____ (_)_ __ ____ _ / /_ ___ / __ \ / ___// /| | / // __ `// __// _ \ @@ -50,6 +73,7 @@ #define s8 "qwertyui" #define s5 "qwert" #define s3 "asd" +#define s1 "a" mt_defs_ext(); @@ -108,6 +132,7 @@ static void test_prepare(void) el_option(EL_FROTATE_NUMBER, 0); el_option(EL_FPATH, WORKDIR"/log"); el_option(EL_FILE_SYNC_EVERY, 0); + file_synced = 0; } @@ -1095,6 +1120,96 @@ static void file_rotate_fail(void) /* ========================================================================== + ========================================================================== */ + + +static void file_sync_always(void) +{ + el_option(EL_FILE_SYNC_EVERY, 0); + mt_fok(el_puts(s8)); + mt_fail(file_synced == 1); +} + + +/* ========================================================================== + ========================================================================== */ + + +static void file_sync_periodic(void) +{ + el_option(EL_FILE_SYNC_EVERY, 8); + mt_fok(el_puts(s5)); + mt_fail(file_synced == 0); + mt_fok(el_puts(s3)); + mt_fail(file_synced == 1); + file_synced = 0; + + mt_fok(el_puts(s5)); + mt_fail(file_synced == 0); + mt_fok(el_puts(s8)); + mt_fail(file_synced == 1); + file_synced = 0; + + mt_fok(el_puts(s5)); + mt_fail(file_synced == 0); + mt_fok(el_puts(s5)); + mt_fail(file_synced == 1); +} + + +/* ========================================================================== + ========================================================================== */ + + +static void file_sync_level(void) +{ + el_option(EL_FILE_SYNC_EVERY, 1024); + el_option(EL_FILE_SYNC_LEVEL, EL_ERROR); + el_option(EL_LEVEL, EL_DBG); + mt_fok(el_print(ELW, s8)); + mt_fail(file_synced == 0); + mt_fok(el_print(ELW, s8)); + mt_fail(file_synced == 0); + mt_fok(el_puts(s5)); + mt_fail(file_synced == 0); + + mt_fok(el_print(ELE, s1)); + mt_fail(file_synced == 1); + file_synced = 0; + + mt_fok(el_print(ELC, s1)); + mt_fail(file_synced == 1); + file_synced = 0; + + mt_fok(el_print(ELA, s1)); + mt_fail(file_synced == 1); + file_synced = 0; + + mt_fok(el_print(ELF, s1)); + mt_fail(file_synced == 1); + file_synced = 0; + + mt_fok(el_print(ELW, s1)); + mt_fail(file_synced == 0); + + mt_fok(el_print(ELN, s1)); + mt_fail(file_synced == 0); + + mt_fok(el_print(ELI, s1)); + mt_fail(file_synced == 0); + + mt_fok(el_print(ELD, s1)); + mt_fail(file_synced == 0); + + mt_fok(el_pmemory(ELI, s8, sizeof(s8))); + mt_fail(file_synced == 0); + + mt_fok(el_pmemory(ELF, s8, sizeof(s8))); + mt_fail(file_synced == 1); +} + + +/* ========================================================================== __ __ / /_ ___ _____ / /_ ____ _ _____ ____ __ __ ____ / __// _ \ / ___// __/ / __ `// ___// __ \ / / / // __ \ @@ -1161,6 +1276,9 @@ void el_file_test_group(void) mt_run(file_rotate_filename_too_long); mt_run(file_rotate_path_too_long); mt_run(file_rotate_fail); + mt_run(file_sync_always); + mt_run(file_sync_periodic); + mt_run(file_sync_level); rmdir(WORKDIR); #endif diff --git a/tst/test-el-options.c b/tst/test-el-options.c index edf44cd..be1899b 100644 --- a/tst/test-el-options.c +++ b/tst/test-el-options.c @@ -95,6 +95,8 @@ static void options_init(void) memset(&default_options, 0, sizeof(default_options)); default_options.outputs = 0; default_options.level = EL_INFO; + default_options.file_sync_level = EL_FATAL; + default_options.level_current_msg = EL_DBG; default_options.colors = 0; default_options.timestamp = EL_TS_OFF; default_options.timestamp_timer = EL_TS_TM_TIME; @@ -165,6 +167,32 @@ static void options_level_set(void) ========================================================================== */ +static void options_file_sync_level_set(void) +{ + int i; + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + + + for (i = 0; i != 16; ++i) + { + if (i <= EL_DBG) + { + mt_fail(el_option(EL_FILE_SYNC_LEVEL, i) == 0); + mt_fail(g_options.file_sync_level == i); + } + else + { + mt_ferr(el_option(EL_FILE_SYNC_LEVEL, i), EINVAL); + mt_fail(g_options.file_sync_level == EL_DBG); + } + } +} + + +/* ========================================================================== + ========================================================================== */ + + static void options_output(void) { int current_outputs; @@ -441,6 +469,7 @@ void el_options_test_group(void) mt_cleanup_test = &test_cleanup; mt_run(options_level_set); + mt_run(options_file_sync_level_set); mt_run(options_output); mt_run(options_log_allowed); mt_run(options_opt_print_level); |