aboutsummaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/Makefile.am16
-rw-r--r--examples/decode-binary.c160
-rw-r--r--examples/print-binary.c43
-rw-r--r--examples/print-example.c29
-rw-r--r--examples/print-memory.c1
-rw-r--r--examples/print-options.c18
-rw-r--r--examples/print-simple.c4
-rw-r--r--examples/print-thread-safe.c2
-rw-r--r--examples/print-to-file.c59
-rw-r--r--examples/print-with-object.c47
10 files changed, 351 insertions, 28 deletions
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 38c5963..31a0466 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -7,28 +7,42 @@ EXTRA_PROGRAMS = print_to_file \
print_options \
print_simple \
print_memory \
- print_tty
+ print_tty \
+ print_with_object
+
+if ENABLE_BINARY_LOGS
+EXTRA_PROGRAMS += print_binary decode_binary
+endif
print_to_file_SOURCES = print-to-file.c
print_thread_safe_SOURCES = print-thread-safe.c
print_options_SOURCES = print-options.c
print_simple_SOURCES = print-simple.c
print_memory_SOURCES = print-memory.c
+print_binary_SOURCES = print-binary.c
+decode_binary_SOURCES = decode-binary.c
print_tty_SOURCES = print-tty.c
+print_with_object_SOURCES = print-with-object.c
print_to_file_LDFLAGS = $(VLDFLAGS)
print_thread_safe_LDFLAGS = $(VLDFLAGS)
print_options_LDFLAGS = $(VLDFLAGS)
print_simple_LDFLAGS = $(VLDFLAGS)
print_memory_LDFLAGS = $(VLDFLAGS)
+print_binary_LDFLAGS = $(VLDFLAGS)
+decode_binary_LDFLAGS = $(VLDFLAGS)
print_tty_LDFLAGS = $(VLDFLAGS)
+print_with_object_LDFLAGS = $(VLDFLAGS)
print_to_file_LDADD = $(VLDADD)
print_thread_safe_LDADD = $(VLDADD)
print_options_LDADD = $(VLDADD)
print_simple_LDADD = $(VLDADD)
print_memory_LDADD = $(VLDADD)
+print_binary_LDADD = $(VLDADD)
+decode_binary_LDADD = $(VLDADD)
print_tty_LDADD = $(VLDADD)
+print_with_object_LDADD = $(VLDADD)
.PHONY: examples
examples: $(EXTRA_PROGRAMS)
diff --git a/examples/decode-binary.c b/examples/decode-binary.c
new file mode 100644
index 0000000..d8283fc
--- /dev/null
+++ b/examples/decode-binary.c
@@ -0,0 +1,160 @@
+/* ==========================================================================
+ Licensed under BSD 2clause license See LICENSE file for more information
+ Author: Michał Łyszczek <michal.lyszczek@bofc.pl>
+ ========================================================================== */
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#include "embedlog.h"
+
+#define die_perror(x, ...) do { el_perror(ELF, x, __VA_ARGS__); exit(1); } while (0)
+
+static size_t decode_number
+(
+ const void *number, /* number to decode */
+ unsigned long long *out /* decoded number */
+)
+{
+ const unsigned char *n; /* just a 'number' as unsigned char */
+ size_t i; /* temporary index */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+ i = 0;
+ *out = 0;
+ n = number;
+
+ do
+ {
+ /* multiple stuff is happening in this one-liner
+ *
+ * - first we take 7 bits of number
+ * - calculate weigth of current number
+ * - set current number into right position of out */
+ *out |= (n[i] & 0x7f) << (i * 7);
+
+ /* we do this until number lacks of continuation bit, which
+ * means we are done */
+ }
+ while (n[i++] & 0x80);
+
+ /* return number of bytes processed from 'number' */
+
+ return i;
+}
+
+#ifdef EMBEDLOG_DEMO_LIBRARY
+int el_demo_decode_binary_main(int argc, char *argv[])
+#else
+int main(int argc, char *argv[])
+#endif
+{
+ int fd;
+ unsigned char *log;
+ struct stat st;
+ ssize_t i;
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+ el_init();
+
+ if (argc != 2)
+ {
+ fprintf(stderr, "Usage: %s <binary-file>\n", argv[0]);
+ return 1;
+ }
+
+ if (stat(argv[1], &st) != 0)
+ die_perror("stat(%s)", argv[1]);
+
+ if ((fd = open(argv[1], O_RDONLY)) < 0)
+ die_perror("open(%s)", argv[1]);
+
+ if ((log = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == NULL)
+ die_perror("mmap(NULL, %zu, PROT_READ, MAP_PRIVATE, %s)",
+ st.st_size, argv[1]);
+
+ /* Parse file, until all frames are read */
+ for (i = 0; i < st.st_size;)
+ {
+ char timestamp[128];
+ int tslen;
+ unsigned char flags;
+ unsigned long long seconds;
+ unsigned long long fract;
+ unsigned long long data_len;
+ struct tm *tm;
+ int level;
+
+ /* flag is always 1st byte of frame */
+ flags = log[i++];
+
+ timestamp[0] = '\0';
+
+ /* Get log level of message in frame */
+ level = flags >> EL_FLAG_LEVEL_SHIFT & EL_FLAG_LEVEL_MASK;
+
+ if (flags & EL_FLAG_TS)
+ {
+ /* Timestamp is present, read seconds from frame, right
+ * now length of seconds is unknown, decode_number() will
+ * return us number of bytes on which seconds were encoded */
+ i += decode_number(log + i, &seconds);
+
+ /* Create timstamp string from the read seconds */
+ tm = gmtime((time_t *)&seconds);
+ tslen = strftime(timestamp, 20, "%Y-%m-%d %H:%M:%S", tm);
+
+ if (flags >> EL_FLAG_TS_FRACT_SHIFT & EL_FLAG_TS_FRACT_MASK)
+ {
+ /* Fractions of seconds are present, read them too */
+ i += decode_number(log + i, &fract);
+
+ /* Append fraction of second into timestamp string,
+ * we will be appending a little differently depending
+ * in fraction unit. */
+
+ switch (flags >> EL_FLAG_TS_FRACT_SHIFT & EL_FLAG_TS_FRACT_MASK)
+ {
+ case 1: /* nanosecond precision */
+ tslen += sprintf(timestamp + tslen, ".%09lld", fract);
+ break;
+
+ case 2: /* microsecond precision */
+ tslen += sprintf(timestamp + tslen, ".%06lld", fract);
+ break;
+
+ case 3: /* millisecond precision */
+ tslen += sprintf(timestamp + tslen, ".%03lld", fract);
+ break;
+ }
+ }
+ }
+
+ /* Get length of data in the frame */
+ i += decode_number(log + i, &data_len);
+
+ /* If timestamp is set, print it with received log level */
+ if (timestamp[0] != '\0')
+ /* first 3 arguments are 0, since we don't want to print
+ * log level location, it's useless in this case, we we would
+ * only print this very location, not when log originally
+ * was printed */
+ el_print(0, 0, 0, level, "%s", timestamp);
+
+ /* Dump received data as hexdump */
+ el_pmemory(0, 0, 0, level, log + i, data_len);
+
+ /* Move to next frame */
+ i += data_len;
+ }
+
+ close(fd);
+ el_cleanup();
+ return 0;
+}
diff --git a/examples/print-binary.c b/examples/print-binary.c
new file mode 100644
index 0000000..704ef37
--- /dev/null
+++ b/examples/print-binary.c
@@ -0,0 +1,43 @@
+/* ==========================================================================
+ Licensed under BSD 2clause license See LICENSE file for more information
+ Author: Michał Łyszczek <michal.lyszczek@bofc.pl>
+ ========================================================================== */
+
+#include "embedlog.h"
+#include <string.h>
+
+#ifdef EMBEDLOG_DEMO_LIBRARY
+int el_demo_print_binary_main(void)
+#else
+int main(void)
+#endif
+{
+ const char *s;
+ el_init();
+
+ /* We can't print binary data to stderr, so we need to print file */
+ if (el_enable_file_log("/tmp/embedlog-print-binary.bin", 0, 0))
+ perror("Error opening file");
+
+ /* Print some data, we print string, but this can be absolutely
+ * anything, First message won't contain timestamp. Notice that
+ * these functions do not take LEVEL macro, but level enum.
+ * There is no point in logging log location in code when doing
+ * binary logs. */
+ s = "not so binary";
+ el_pbinary(EL_NOTICE, s, strlen(s));
+
+ /* Enable timestamps, but no fractions. */
+ el_set_timestamp(EL_TS_SHORT, EL_TS_TM_REALTIME, EL_TS_FRACT_OFF);
+ s = "ts in, fract out";
+ el_pbinary(EL_WARN, s, strlen(s));
+
+ /* Enable timestamps, with fractions. */
+ el_set_timestamp(EL_TS_SHORT, EL_TS_TM_REALTIME, EL_TS_FRACT_US);
+ s = "we are all in";
+ el_pbinary(EL_FATAL, s, strlen(s));
+
+ el_cleanup();
+
+ return 0;
+}
diff --git a/examples/print-example.c b/examples/print-example.c
new file mode 100644
index 0000000..74e22d0
--- /dev/null
+++ b/examples/print-example.c
@@ -0,0 +1,29 @@
+#include <embedlog.h>
+#include <errno.h>
+
+int main(void) {
+ const char *file = "/tmp/embedlog-test-file.log";
+
+ el_init();
+
+ el_print(ELN, "first print");
+
+ el_set_timestamp(EL_TS_LONG, EL_TS_TM_REALTIME, EL_TS_FRACT_US);
+ el_print(ELW, "warning with timestamp");
+
+ el_print_extra_info(1);
+ el_print(ELF, "fatal error, with code location");
+ el_print(ELI, "normal log with timestamp and code location");
+ el_print(ELD, "won't be printed, log level too low");
+ el_set_log_level(EL_DBG);
+ el_print(ELD, "but now it will be printed");
+
+ el_enable_file_log(file, 0, 0);
+ el_print(ELN, "from now on, logs will be printed to both file and stderr");
+
+ errno = ENAMETOOLONG;
+ el_perror(ELA, "simulated error, failed to open file: %s", file);
+
+ el_cleanup();
+ return 0;
+}
diff --git a/examples/print-memory.c b/examples/print-memory.c
index c1cf9c4..63ac590 100644
--- a/examples/print-memory.c
+++ b/examples/print-memory.c
@@ -21,6 +21,7 @@ int main(void)
el_init();
+ el_option(EL_PMEMORY_SPACE, 1);
el_pmemory(ELI, ascii, sizeof(ascii));
el_pmemory(ELI, s, sizeof(s));
diff --git a/examples/print-options.c b/examples/print-options.c
index dd245ea..01a7709 100644
--- a/examples/print-options.c
+++ b/examples/print-options.c
@@ -24,7 +24,23 @@ int main(void)
el_init();
- el_option(EL_PRINT_LEVEL, 0);
+ el_print(ELI, "most common options can be set with special functions");
+ el_set_timestamp(EL_TS_LONG, EL_TS_TM_REALTIME, EL_TS_FRACT_US);
+ el_print_extra_info(1);
+ el_print(ELI, "like, printing timestamp and log location in a file");
+ el_enable_colors(1);
+ el_print(ELI, "or enabling colors in output");
+ el_print(ELA, "to make it easy to spot error");
+ el_set_log_level(EL_DBG);
+ el_print(ELD, "These options are enough for vast majority of use cases. "
+ "But it more fine tuning is necessary, you can always use "
+ "el_option(3) function, to really fine tune your experience");
+ el_puts("log");
+
+ el_set_timestamp(EL_TS_OFF, 0, 0);
+ el_print_extra_info(0);
+ el_enable_colors(0);
+
el_print(ELI, "We can disable information about log level\b");
el_print(ELF, "message still will be filtered by log level");
el_print(ELA, "but there is no way to tell what level message is");
diff --git a/examples/print-simple.c b/examples/print-simple.c
index e5ffc6b..73cb564 100644
--- a/examples/print-simple.c
+++ b/examples/print-simple.c
@@ -11,7 +11,7 @@ int el_demo_print_simple_main(void)
int main(void)
#endif
{
- /* first we nned to initialize logger to known state, embedlog
+ /* first we need to initialize logger to known state, embedlog
* will print to stdout by default */
el_init();
@@ -24,7 +24,7 @@ int main(void)
/* we can change log level in runtime as we see fit, now enable
* debug prints */
- el_option(EL_LEVEL, EL_DBG);
+ el_set_log_level(EL_DBG);
el_print(ELD, "But now debug will be printed");
/* altough embedlog does not use dynamic allocation by itself,
diff --git a/examples/print-thread-safe.c b/examples/print-thread-safe.c
index 68f7417..effb24b 100644
--- a/examples/print-thread-safe.c
+++ b/examples/print-thread-safe.c
@@ -13,7 +13,7 @@ int main(void)
{
el_init();
- if (el_option(EL_THREAD_SAFE, 1) != 0)
+ if (el_enable_thread_safe(1))
{
el_perror(ELF, "Failed to enable thread safety");
el_cleanup();
diff --git a/examples/print-to-file.c b/examples/print-to-file.c
index 7789540..b79f343 100644
--- a/examples/print-to-file.c
+++ b/examples/print-to-file.c
@@ -12,55 +12,68 @@
#define WORKDIR "/tmp/embedlog-example"
#ifdef EMBEDLOG_DEMO_LIBRARY
-int el_demo_print_to_file_main(void)
+int el_demo_print_to_file_main(int argc, char *argv[])
#else
-int main(void)
+int main(int argc, char *argv[])
#endif
{
+ int date_rotate = 0;
+ int ret;
+
+
+ if (argc == 2)
+ date_rotate = 1;
+
el_init();
- el_option(EL_TS, EL_TS_LONG);
- el_option(EL_TS_TM, EL_TS_TM_REALTIME);
+ el_set_timestamp(EL_TS_LONG, EL_TS_TM_REALTIME, 0);
+ el_print_extra_info(1);
el_option(EL_FINFO, 1);
if (mkdir(WORKDIR, 0755) != 0 && errno != EEXIST)
{
- fprintf(stderr, "Couldn't create %s, error %s\n",
- WORKDIR, strerror(errno));
-
+ el_perror(ELF, "Couldn't create directory "WORKDIR);
goto error;
}
- if (el_option(EL_FPATH, WORKDIR"/log") != 0)
+ /* Enable printing to file, and set log rotation. embedlog will
+ * create maximum 5 files, and non of those files will be larger
+ * than 512. This is demo only, in real life you may want to set
+ * file size to 1M or so. */
+ if (date_rotate)
+ ret = el_enable_file_log(WORKDIR"/log", EL_ROT_DATE_MIN, 0);
+ else
+ ret = el_enable_file_log(WORKDIR"/log", 5, 512);
+
+ if (ret)
{
/* embedlog will try to open file now, this may fail for
- * various of reasons, if opening fails, we cannot log to
- * file - all el_print to files will return error */
- fprintf(stderr, "Couldn't open file for logging %s\n",
- strerror(errno));
+ * various of reasons */
+ if (errno == EINVAL || errno == ENAMETOOLONG)
+ {
+ /* EINVAL and ENAMETOOLONG are the only non-recovarable
+ * errors, if these are returned you can be sure embedlog
+ * will never successully write to a file. All other errors
+ * can be recovered from, and embedlog will start printing
+ * to file once that condition is fixed. This may be
+ * wrong permission, or not existing directory */
+ el_perror(ELF, "Failed to open file for logging");
+ goto error;
+ }
- goto error;
+ el_perror(ELW, "failed to open log file, we will keep trying");
}
- /* instruct logger to print into both file and standard error */
- el_option(EL_OUT, EL_OUT_FILE | EL_OUT_STDERR);
-
el_print(ELI, "This message will appear both in standard error");
el_print(ELI, "and in file %s", WORKDIR"/log");
el_print(ELI, "in this file there might be another logs like this "
"from consecutive execution if this code, as embedlog "
"does not truncate logs but append to file");
-
- /* enable file rotation and set file size to small enough value
- * to present how rotation works, in real life, rotate size
- * should be much higher to prevent unnecessary rotation */
- el_option(EL_FROTATE_NUMBER, 5);
- el_option(EL_FROTATE_SIZE, 512);
- el_print(ELI, "Now we enabled log rotation");
el_print(ELI, "If log cannot fit in current file");
el_print(ELI, "it will be stored in new file");
el_print(ELI, "and if library creates EL_FROTATE_NUMBER files");
el_print(ELI, "oldest file will be deleted and new file will be created");
el_print(ELI, "run this program multiple times and see how it works");
+ el_print(ELI, "File without number, always points to newest log file");
el_cleanup();
return 0;
diff --git a/examples/print-with-object.c b/examples/print-with-object.c
new file mode 100644
index 0000000..a86e5b6
--- /dev/null
+++ b/examples/print-with-object.c
@@ -0,0 +1,47 @@
+/* ==========================================================================
+ Licensed under BSD 2clause license See LICENSE file for more information
+ Author: Michał Łyszczek <michal.lyszczek@bofc.pl>
+ ========================================================================== */
+
+#include "embedlog.h"
+
+#define EL_OPTIONS_OBJECT g_log
+
+#ifdef EMBEDLOG_DEMO_LIBRARY
+int el_demo_print_simple_main(void)
+#else
+int main(void)
+#endif
+{
+ /* Declaration on stack, this should only be used on RTOS, where
+ * stable ABI is not a concern, but allocating on stack is desireable */
+ /* struct el g_log; */
+ /* Heap allocating will provide stable ABI in systems with dynamic
+ * linking, your program will not have to be recompilled each time
+ * embedlog changes */
+ struct el *g_log;
+
+ /* Stack initialization of embedlog object */
+ /* el_oinit(&g_log); */
+ /* Heap allocation of embedlog object */
+ g_log = el_new();
+
+ /* Now we can print almost just as easy as with default functions.
+ * We just have to use slightly different function name and LEVEL
+ * macro */
+ el_oprint(OELI, "Info message");
+ el_oprint(OELF, "Fatal message with additional argument %d", 42);
+ el_oprint(OELD, "Debug message that won't be printed due to log level");
+
+ /* we can change log level in runtime as we see fit, now enable
+ * debug prints */
+ el_oset_log_level(g_log, EL_DBG);
+ el_oprint(OELD, "But now debug will be printed");
+
+ /* Cleaning up stack allocated object */
+ /* el_ocleanup(&g_log); */
+ /* Cleaning up heap allocated object */
+ el_destroy(g_log);
+
+ return 0;
+}