aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichał Łyszczek <michal.lyszczek@bofc.pl>2018-04-15 20:03:57 +0200
committerMichał Łyszczek <michal.lyszczek@bofc.pl>2018-04-15 20:15:05 +0200
commit4449096e93f1f5f6e667bc358ea48bfe335aa557 (patch)
treefef78a0c82651a29b6fbfd34c1e4e92e8b9e9499
parent905421aac941de7eaeb5b23a2c8742fd36f29f23 (diff)
downloadembedlog-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.h3
-rw-r--r--man/el_option.335
-rw-r--r--readme.md4
-rw-r--r--src/el-file.c41
-rw-r--r--src/el-options.c8
-rw-r--r--src/el-print.c20
-rw-r--r--tst/Makefile.am1
-rw-r--r--tst/test-el-file.c118
-rw-r--r--tst/test-el-options.c29
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
diff --git a/readme.md b/readme.md
index 958e085..9e62f45 100644
--- a/readme.md
+++ b/readme.md
@@ -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);