diff options
Diffstat (limited to 'examples')
-rw-r--r-- | examples/Makefile.am | 16 | ||||
-rw-r--r-- | examples/decode-binary.c | 160 | ||||
-rw-r--r-- | examples/print-binary.c | 43 | ||||
-rw-r--r-- | examples/print-example.c | 29 | ||||
-rw-r--r-- | examples/print-memory.c | 1 | ||||
-rw-r--r-- | examples/print-options.c | 18 | ||||
-rw-r--r-- | examples/print-simple.c | 4 | ||||
-rw-r--r-- | examples/print-thread-safe.c | 2 | ||||
-rw-r--r-- | examples/print-to-file.c | 59 | ||||
-rw-r--r-- | examples/print-with-object.c | 47 |
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; +} |