Git Product home page Git Product logo

zf_log's Introduction

Build Status Build Status Gitter Chat

zf_log

Core logging library for C, Objective-C and C++

Following the Unix way, this library provides the logging core which can be used directly or extended. In essence, it's a thin wrapper around snprintf() function. By implementing less than 20% of functionality found in more sophisticated and feature reach libraries, it covers more than 80% of common use cases. Found to be particularly useful in cross-platform applications and on mobile/embedded platforms. Focus is made on simplicity, ease of use and performance (to be more precise - low overhead).

Features:

  • Debug logging is reduced to no-op in release builds:

    /* no runtime overhead whatsoever if verbose log is disabled */
    ZF_LOGV("entering foobar(), args: %i, %s", arg0, arg1);
  • No "unused" warning for variables used in log statements only:

    /* no warning about err being unused even if verbose log is disabled */
    int err = close(fd);
    ZF_LOGV("close status %i", err);
  • Arguments are not evaluated when the message is not logged:

    /* to_utf8() will not be called if debug log is turned off or disabled */
    ZF_LOGD("Login: %s", to_utf8(loginUtf16));
  • Log a memory region as HEX and ASCII:

    /* will print HEX and ASCII view of received network packet */
    ZF_LOGD_MEM(pkg_ptr, pkg_sz, "Received network packet (%u bytes):", pkg_sz);
  • Compiler warnings when format string and arguments don't match:

    /* warning: format specifies type 'char *' but the argument has type 'int' */
    ZF_LOGI("This is int %s", 42);
  • Conditional logging of sensitive information (also known as Personally Identifiable Information or PII):

    /* will be logged only when logging of sensitive information is enabled */
    ZF_LOG_SECRET(ZF_LOGI("Credit card number: %s", credit_card));
  • Custom output functions

  • Custom log message formats

  • Compile time configuration of logging level

  • Run time configuration of logging level

  • Optional built-in support for Android log and Apple system log (iOS, OS X)

  • Reasonably cross-platform (OS X, iOS, Linux, Android, other Unix flavors, POSIX platforms and Windows)

  • No external dependencies

  • Compact call site (smaller executables)

  • Thread safe

  • Library size is under 10Kb (when compiled for x86_64)

  • Can be used privatly in libraries

Examples

Library provides a set of ZF_LOGX macros where X is an abbreviated log level (e.g. I for INFO). This code will log an INFO message:

ZF_LOGI("Number of arguments: %i", argc);

And will produce the following log line if NDEBUG is defined (aka release build):

+- month           +- process id
|  +- day          |      +- thread id      +- message
|  |               |      |                 |
04-29 22:43:20.244 40059  1299 I hello.MAIN Number of arguments: 1
      |                        | |     |
      +- time                  | |     +- tag (optional)
                               | +- tag prefix (optional)
                               +- level

And if NDEBUG is NOT defined (aka debug build):

04-29 22:43:20.244 40059  1299 I hello.MAIN [email protected]:9 Number of arguments: 1
                                            |    |       |
                                            |    |       +- line number
                                            |    +- source file name
                                            +- function name

It's also possible to dump a memory region. For example:

const char data[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
ZF_LOGI_MEM(data, sizeof(data), "Lorem ipsum at %p", data);

Will produce the following output:

05-06 00:54:33.825 35864  1299 I hello.MAIN Lorem ipsum at 0x10fbc0f20:
05-06 00:54:33.825 35864  1299 I hello.MAIN 4c6f72656d20697073756d20646f6c6f  Lorem ipsum dolo
05-06 00:54:33.825 35864  1299 I hello.MAIN 722073697420616d65742c20636f6e73  r sit amet, cons
05-06 00:54:33.825 35864  1299 I hello.MAIN 65637465747572206164697069736369  ectetur adipisci
05-06 00:54:33.825 35864  1299 I hello.MAIN 6e6720656c69742e00                ng elit.?

More examples available in examples folder. For more details see comments in zf_log/zf_log.h file.

Usage

Embedding

The simplest way of using this library is to embed its sources into existing project. For that, copy the following files to your source tree:

See comments in those files for configuration macros. One particularly useful option when embedding into a library project is ZF_LOG_LIBRARY_PREFIX. It could be used to decorate zf_log exported symbols to avoid linker conflicts (when that library project is used in other project that is also uses zf_log).

Embedding with CMake

Another options is avaibale for projects that are using CMake. Copy zf_log folder to you source tree and add it with add_subdirectory() call in one of your CMakeLists.txt files. Also see zf_log/CMakeLists.txt for available ZF_LOG_ configuration options. For example:

set(ZF_LOG_USE_ANDROID_LOG ON)
add_subdirectory(zf_log)

This will add zf_log library target. For each target that uses zf_log in corresponding CMakeLists.txt file add:

target_link_libraries(my_target zf_log)

Installation

Another option is to build and install the library:

git clone https://github.com/wonder-mice/zf_log.git zf_log.git
mkdir zf_log.build && cd zf_log.build
cmake ../zf_log.git -DCMAKE_INSTALL_PREFIX=/usr/local
make
sudo make install

This will also install ${CMAKE_INSTALL_PREFIX}/lib/cmake/zf_log/zf_log.cmake and ${CMAKE_INSTALL_PREFIX}/lib/cmake/zf_log/zf_log-config.cmake. The first one is for direct include from CMakeLists.txt files. The second can be located by CMake with:

find_package(zf_log)

Both will add zf_log imported library target. For each target that uses zf_log in corresponding CMakeLists.txt file add:

target_link_libraries(my_target zf_log)

To build as a shared library set CMake variable BUILD_SHARED_LIBS:

cmake ../zf_log.git -DBUILD_SHARED_LIBS:BOOL=ON

Performance

Log statements that are below current log level (compile time check) have no overhead - they are compiled out and their log arguments will not be evaluated. Consider:

#include <signal.h>
#include <unistd.h>
#define ZF_LOG_LEVEL ZF_LOG_INFO
#include <zf_log.h>

int main(int argc, char *argv[])
{
	ZF_LOGV("Argument of this VERBOSE message will not be evaluated: %i",
			kill(getpid(), SIGKILL));
	ZF_LOGI("So you will see that INFO message");
	return 0;
}

Log statements that are below output log level (run time check) have a small overhead of compare operation and conditional jump. Arguments will not be evaluated and no function call will be performed. Consider:

#include <stdlib.h>
#define ZF_LOG_LEVEL ZF_LOG_INFO
#include <zf_log.h>

int main(int argc, char *argv[])
{
	zf_log_set_output_level(ZF_LOG_WARN);
	int count = 0;
	for (int i = 2; 0 < i--;)
	{
		ZF_LOGI("Argument of this INFO message will be evaluated only once: %i",
				++count);
		zf_log_set_output_level(ZF_LOG_INFO);
	}
	if (1 != count)
	{
		abort();
	}
	ZF_LOGI("And you will see that INFO message");
	return 0;
}

Log statements that are on or above current log level and output log level will go into log output (and arguments will be evaluated). In that case it's hard to talk about performance because string formatting routines will be called and IO will be performed.

To conclude, it is OK to have log statements for debug and development purposes, even in performance critical parts. But make sure to set correct current log level (to compile them out) or output log level (to suppress them) in release builds.

That said, in some rare cases it could be useful to provide a custom output function that will use memory buffer for the log output.

Output

By default log messages are written to the stderr, but it is also possible to set custom output function. Library has an optional built-in support for the following output facilities (see zf_log/zf_log.c for details):

  • Android Log (via android/log.h)
  • Apple System Log (iOS, OS X via asl.h)

See examples/custom_output.c for an example of custom output function.

Comparison

This table is work in progress. See tests/perf folder for how this table was generated (fully automated).

Easylogging++ g3log glog spdlog zf_log
Call site size: string 304 B 360 B 160 B 352 B 48 B
Call site size: 3 integers 856 B 384 B 320 B 312 B 72 B
Executable size: 1 module 208.84 KB 183.73 KB 137.37 KB 133.69 KB 18.33 KB
Module compile time 3.182 sec 0.511 sec 0.374 sec 2.163 sec 0.024 sec
Executable link time 0.025 sec 0.022 sec 0.026 sec 0.020 sec 0.017 sec
Speed: 1 thread, string 378,722 1,257,168 385,098 1,909,253 5,296,201
Speed: 1 thread, 3 integers 311,690 1,023,108 321,507 1,470,271 3,173,097
Speed: 1 thread, string, off 4,199,431 55,297,247 411,960 78,675,820 482,713,041
Speed: 1 thread, slow function, off 743 54,877,221 732 750 423,658,146
Speed: 4 threads, string 132,836 2,353,169 196,950 196,930 9,690,216
Speed: 4 threads, 3 integers 116,696 1,896,178 235,141 172,880 5,545,075
Speed: 4 threads, string, off 244,448 106,600,866 186,233 164,582,184 1,229,398,467
Speed: 4 threads, slow function, off 733 111,685,033 2,887 2,976 1,106,166,551
Speed: 8 threads, string 131,691 2,447,058 172,824 183,277 9,731,434
Speed: 8 threads, 3 integers 115,991 1,936,270 176,594 177,950 5,596,045
Speed: 8 threads, string, off 240,538 104,424,749 182,465 164,632,729 1,228,058,986
Speed: 8 threads, slow function, off 774 116,354,224 5,815 5,976 1,127,173,552

Details:

  • Call site size - amount of code generated for each LOG() statement when logging a string, format string with 4 integers or format string with 4 integers where the function is used to get an integer.
  • Compile time - time to compile a source file that includes public API header from the logging library.
  • Speed - log lines per second. Thread(s) call LOG() N times in a tight loop for T seconds. N/T is log lines per second.
  • When it says "off", it means that log level was turned off. Expecting very low overhead in this mode.

Why zf?

It stands for Ze Foundation. "Ze" is like "The" but with french or german accent. Mostly because zf_anything looks better than tf_anything.

zf_log's People

Contributors

eepp avatar makerj avatar mgiaco avatar spexguy avatar two-bit-xor avatar wonder-mice avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

zf_log's Issues

incorrect month on windows

#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__MONTH ,(unsigned)(tm.tm_mon + 1)

that +1 is incorrect on Windows

same goes for this (not checked)

#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__MONTH p = put_uint_r((unsigned)tm.tm_mon + 1, 2, '0', p);

with the way it is it gives me 12-27 not 11-27.

you may wanna add
tm->tm_mon++;

somwhere around:

*msec = (unsigned)tv.tv_usec / 1000;

instead.

run tests on windows7 64Bit with msys2 mingw64

Hello,

I am able to build and test the lib on windows 7 but I get two errors I do not found out what´s exactly wrong.
My problem is that I am new to CTEST. I have never used it before. Is there any good way to dig into that failed tests only and found out something more?

Test project E:/github_c/zf_log/Debug
      Start  1: test_log_level_switches_verbose_c99
 1/54 Test  #1: test_log_level_switches_verbose_c99 ...........   Passed    0.01 sec
      Start  2: test_log_level_switches_verbose_c11
 2/54 Test  #2: test_log_level_switches_verbose_c11 ...........   Passed    0.01 sec
      Start  3: test_log_level_switches_debug_c99
 3/54 Test  #3: test_log_level_switches_debug_c99 .............   Passed    0.01 sec
      Start  4: test_log_level_switches_debug_c11
 4/54 Test  #4: test_log_level_switches_debug_c11 .............   Passed    0.01 sec
      Start  5: test_log_level_switches_info_c99
 5/54 Test  #5: test_log_level_switches_info_c99 ..............   Passed    0.01 sec
      Start  6: test_log_level_switches_info_c11
 6/54 Test  #6: test_log_level_switches_info_c11 ..............   Passed    0.01 sec
      Start  7: test_log_level_switches_warn_c99
 7/54 Test  #7: test_log_level_switches_warn_c99 ..............   Passed    0.01 sec
      Start  8: test_log_level_switches_warn_c11
 8/54 Test  #8: test_log_level_switches_warn_c11 ..............   Passed    0.01 sec
      Start  9: test_log_level_switches_error_c99
 9/54 Test  #9: test_log_level_switches_error_c99 .............   Passed    0.01 sec
      Start 10: test_log_level_switches_error_c11
10/54 Test #10: test_log_level_switches_error_c11 .............   Passed    0.01 sec
      Start 11: test_log_level_switches_fatal_c99
11/54 Test #11: test_log_level_switches_fatal_c99 .............   Passed    0.01 sec
      Start 12: test_log_level_switches_fatal_c11
12/54 Test #12: test_log_level_switches_fatal_c11 .............   Passed    0.01 sec
      Start 13: test_log_level_switches_none_c99
13/54 Test #13: test_log_level_switches_none_c99 ..............   Passed    0.01 sec
      Start 14: test_log_level_switches_none_c11
14/54 Test #14: test_log_level_switches_none_c11 ..............   Passed    0.01 sec
      Start 15: test_log_level_override_c99
15/54 Test #15: test_log_level_override_c99 ...................   Passed    0.01 sec
      Start 16: test_log_level_override_c11
16/54 Test #16: test_log_level_override_c11 ...................   Passed    0.01 sec
      Start 17: test_log_message_content_c99
17/54 Test #17: test_log_message_content_c99 ..................   Passed    0.01 sec
      Start 18: test_log_message_content_c11
18/54 Test #18: test_log_message_content_c11 ..................   Passed    0.01 sec
      Start 19: test_log_message_content_Os_c99
19/54 Test #19: test_log_message_content_Os_c99 ...............***Failed    0.01 sec
      Start 20: test_log_message_content_Os_c11
20/54 Test #20: test_log_message_content_Os_c11 ...............***Failed    0.01 sec
      Start 21: test_source_location_none_c99
21/54 Test #21: test_source_location_none_c99 .................   Passed    0.01 sec
      Start 22: test_source_location_none_c11
22/54 Test #22: test_source_location_none_c11 .................   Passed    0.00 sec
      Start 23: test_source_location_short_c99
23/54 Test #23: test_source_location_short_c99 ................   Passed    0.01 sec
      Start 24: test_source_location_short_c11
24/54 Test #24: test_source_location_short_c11 ................   Passed    0.01 sec
      Start 25: test_source_location_long_c99
25/54 Test #25: test_source_location_long_c99 .................   Passed    0.00 sec
      Start 26: test_source_location_long_c11
26/54 Test #26: test_source_location_long_c11 .................   Passed    0.00 sec
      Start 27: test_source_location_none_Os_c99
27/54 Test #27: test_source_location_none_Os_c99 ..............   Passed    0.01 sec
      Start 28: test_source_location_none_Os_c11
28/54 Test #28: test_source_location_none_Os_c11 ..............   Passed    0.01 sec
      Start 29: test_source_location_short_Os_c99
29/54 Test #29: test_source_location_short_Os_c99 .............   Passed    0.01 sec
      Start 30: test_source_location_short_Os_c11
30/54 Test #30: test_source_location_short_Os_c11 .............   Passed    0.01 sec
      Start 31: test_source_location_long_Os_c99
31/54 Test #31: test_source_location_long_Os_c99 ..............   Passed    0.00 sec
      Start 32: test_source_location_long_Os_c11
32/54 Test #32: test_source_location_long_Os_c11 ..............   Passed    0.01 sec
      Start 33: test_conditional_c99
33/54 Test #33: test_conditional_c99 ..........................   Passed    0.01 sec
      Start 34: test_conditional_c11
34/54 Test #34: test_conditional_c11 ..........................   Passed    0.01 sec
      Start 35: test_censoring_off_c99
35/54 Test #35: test_censoring_off_c99 ........................   Passed    0.01 sec
      Start 36: test_censoring_off_c11
36/54 Test #36: test_censoring_off_c11 ........................   Passed    0.01 sec
      Start 37: test_censoring_on_c99
37/54 Test #37: test_censoring_on_c99 .........................   Passed    0.01 sec
      Start 38: test_censoring_on_c11
38/54 Test #38: test_censoring_on_c11 .........................   Passed    0.01 sec
      Start 39: test_private_parts_c99
39/54 Test #39: test_private_parts_c99 ........................   Passed    0.01 sec
      Start 40: test_private_parts_c11
40/54 Test #40: test_private_parts_c11 ........................   Passed    0.00 sec
      Start 41: test_decoration_c99
41/54 Test #41: test_decoration_c99 ...........................   Passed    0.01 sec
      Start 42: test_decoration_c11
42/54 Test #42: test_decoration_c11 ...........................   Passed    0.01 sec
      Start 43: test_aux_spec_c99
43/54 Test #43: test_aux_spec_c99 .............................   Passed    0.01 sec
      Start 44: test_aux_spec_c11
44/54 Test #44: test_aux_spec_c11 .............................   Passed    0.01 sec
      Start 45: test_externally_defined_state_c99
45/54 Test #45: test_externally_defined_state_c99 .............   Passed    0.00 sec
      Start 46: test_externally_defined_state_c11
46/54 Test #46: test_externally_defined_state_c11 .............   Passed    0.01 sec
      Start 47: test_externally_defined_state_cpp
47/54 Test #47: test_externally_defined_state_cpp .............   Passed    0.01 sec
      Start 48: test_compilation_cpp
48/54 Test #48: test_compilation_cpp ..........................   Passed    0.01 sec
      Start 49: test_call_site_size_msg_only_check
49/54 Test #49: test_call_site_size_msg_only_check ............   Passed    0.00 sec
      Start 50: test_call_site_size_fmt_args_check
50/54 Test #50: test_call_site_size_fmt_args_check ............   Passed    0.00 sec
      Start 51: test_call_site_size_conditional_true_check
51/54 Test #51: test_call_site_size_conditional_true_check ....   Passed    0.00 sec
      Start 52: test_call_site_size_conditional_false_check
52/54 Test #52: test_call_site_size_conditional_false_check ...   Passed    0.00 sec
      Start 53: test_call_site_size_censoring_on_check
53/54 Test #53: test_call_site_size_censoring_on_check ........   Passed    0.00 sec
      Start 54: test_call_site_size_censoring_off_check
54/54 Test #54: test_call_site_size_censoring_off_check .......   Passed    0.00 sec

96% tests passed, 2 tests failed out of 54

Total Test time (real) =   0.34 sec

The following tests FAILED:
	 19 - test_log_message_content_Os_c99 (Failed)
	 20 - test_log_message_content_Os_c11 (Failed)

thanks

warning for ARM Embedded GCC 8.x

I have seen that there was the #ifdef _AIX added. I do get a warning here also but the _AIX dose not help.

#if defined(_AIX)
static struct tm g_tcache_tm = {0, 0, 0, 0, 0, 0, 0, 0, 0};
#else
static struct tm g_tcache_tm = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
#endif

the time.h struct definition is:

struct tm
{
  int	tm_sec;
  int	tm_min;
  int	tm_hour;
  int	tm_mday;
  int	tm_mon;
  int	tm_year;
  int	tm_wday;
  int	tm_yday;
  int	tm_isdst;
#ifdef __TM_GMTOFF
  long	__TM_GMTOFF;
#endif
#ifdef __TM_ZONE
  const char *__TM_ZONE;
#endif
};

So I do not add any pull because you will have any better idea. :-)

va_list version of logging functions

Hi,

It would be great if there is va_list version of logging functions/macros be released for customized package, something like:

ZF_VLOGI(valist)

would be help when we have our own logging function:

void info(/*blah blah*/ const char *fmt, ...) { va_list vl; va_start(vl, fmt); /* blah blah */ ZF_VLOGI(fmt, vl); va_close(); }

Of course ZF_LOGI_STR() with an extra snprint() could do the same, but one more snprintf costs.
Thanks!

-Wundef warning

When building with -Wundef, we get this diagnostic

$ cmake .. -DCMAKE_C_FLAGS="-Wundef"
-- Configuring done
-- Generating done
-- Build files have been written to: /home/smarchi/src/zf_log/build
$ make
[ 50%] Building C object zf_log/CMakeFiles/zf_log.dir/zf_log.c.o
/home/smarchi/src/zf_log/zf_log/zf_log.c: In function ‘put_tag’:
/home/smarchi/src/zf_log/zf_log/zf_log.c:452:15: error: "_ZF_LOG_MESSAGE_FORMAT_MASK__TAG" is not defined, evaluates to 0 [-Werror=undef]
  _PP_CONCAT_3(_ZF_LOG_MESSAGE_FORMAT_MASK_, _, field)
               ^
/home/smarchi/src/zf_log/zf_log/zf_log.c:347:30: note: in definition of macro ‘_PP_PASTE_3’
 #define _PP_PASTE_3(a, b, c) a ## b ## c
                              ^
/home/smarchi/src/zf_log/zf_log/zf_log.c:452:2: note: in expansion of macro ‘_PP_CONCAT_3’
  _PP_CONCAT_3(_ZF_LOG_MESSAGE_FORMAT_MASK_, _, field)
  ^~~~~~~~~~~~
/home/smarchi/src/zf_log/zf_log/zf_log.c:467:3: note: in expansion of macro ‘_ZF_LOG_MESSAGE_FORMAT_MASK’
  (_ZF_LOG_MESSAGE_FORMAT_MASK(field) & _ZF_LOG_MESSAGE_FORMAT_FIELDS(format))
   ^~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/smarchi/src/zf_log/zf_log/zf_log.c:1159:6: note: in expansion of macro ‘_ZF_LOG_MESSAGE_FORMAT_CONTAINS’
 #if !_ZF_LOG_MESSAGE_FORMAT_CONTAINS(TAG, ZF_LOG_MESSAGE_TAG_FORMAT)
      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I tried to investigate but quickly got lost in the macros. I believe that it might be important, as some value that's supposed to be a mask is actually 0.

out_android_callback skips src location

out_android_callback ends with the line

__android_log_print(android_lvl(msg->lvl), tag, "%s", msg->msg_b);

When logging src locations, the buffer and relevant pointers in msg look something like this:

tag_b          msg_b
  |              |
  [TAG] [SRCLOC] [MESSAGE]
      |
    tag_e

tag is just the char* from tag_b to tag_e, so the src location doesn't get passed to __android_log_print.


A potential fix might be to add a char *src_b field to the zf_log_message struct, and have the callback use

__android_log_print(android_lvl(msg->lvl), tag, "%s", msg->src_b);

iOS: custom_output can only output at a fixed level threshold?

On iOS, with the sample code custom_output,

static void custom_output_callback(const zf_log_message *msg, void *arg)
{
    (void)arg;
    /* p points to the log message end. By default, message is not terminated
     * with 0, but it has some space allocated for EOL area, so there is always
     * some place for terminating zero in the end (see ZF_LOG_EOL_SZ define in
     * zf_log.c).
     */
    *msg->p = 0;
#if defined(OUTPUT_DEBUG_STRING)
    OutputDebugStringA(msg->buf);
#elif defined(OUTPUT_SYSLOG)
    syslog(syslog_level(msg->lvl), "%s", msg->msg_b);
#else
    #error Unsupported platform
#endif
}

and with

zf_log_set_output_level(ZF_LOG_VERBOSE);

I can only see logs above ZF_LOG_INFO in the syslog, although Xcode console outputs at the expected VERBOSE level.

Is there another switch for syslog/custom_output?

missing colour cleanup in output_mem

Just stumbled upon this - nothing critical - but I believe that output_mem() is missing a put_color(msg, 0); just before invoking the callback. Works for me.

questions

Hey, man
I have some questions about zf_log.

  1. Is it support rolling ? e.g. RollingFileAppender or DailyRollingFileAppender .
  2. I'm going to port zf_log to iOS and Android platforms, have you tested on these platforms yet? And do you have some scripts to build zf_log on these platforms ?
    Thank you.

Security issues

Your snprintf implementation does not properly zero-terminate buffers, you might want to take a look here: mpaland/printf#7

Just a nice hint for you, since I saw you using the library and just discovered these issues.

Personally identifiable information (PII) support

It would be nice to have some built-in support for PII information in logs. For example PII information must be removed in release builds, but present in debug builds, for example:

ZF_LOGE("Customer credit card is invalid (%s)", ZF_LOG_PII(credit_card_number));

Where ZF_LOG_PII expands to empty string when building release. Or, for example:

ZF_LOGD_PII("Customer credit card: %s", credit_card_number);

Which will not log anything at all.

Better control over source location (func@source:line)

Instead of just relying on NDEBUG, introduce explicit switch to enable or disable source location in log lines (per module).

define ZF_LOG_DEF_SRC 1 /* Force source location in log lines, both debug and release */

define ZF_LOG_DEF_SRC 0 /* Disable source location in log lines, both debug and release */

ZF_LOG_SRC has the same meaning, but has higher priority. If both are undefined, library defaults to old NDEBUG -based mode.

Compatibility with CMake < 3.5 will be removed from a future version of CMake

When configuring with cmake . -Bbuild/, the following warning presents:

CMake Deprecation Warning at CMakeLists.txt:1 (cmake_minimum_required):
  Compatibility with CMake < 3.5 will be removed from a future version of
  CMake.

  Update the VERSION argument <min> value or use a ...<max> suffix to tell
  CMake that the project does not need compatibility with older versions.

This occurs for the CMakeLists.txt file in the root project dir as well as in zf_log/. Updating the minimum version to at least 3.5 might be worth considering in order to keep support with newer CMake versions in the future.

iOS: cannot show pid/tid in syslog?

I noticed that the custom_output sample code removed ZF_LOG_PUT_CTX explicitly for the SYSLOG case, with

	const unsigned put_mask =
#if defined(OUTPUT_SYSLOG)
			ZF_LOG_PUT_STD & !ZF_LOG_PUT_CTX;
#else
			ZF_LOG_PUT_STD;
#endif

Does it mean that we could never see tid/pid in syslog?

I've tried to enable it myself and the sample code crashes at the syslog call in the callback.

CMake instructions use wrong var name

Under the "Embedding with CMake" header in the README is the line

set(ZF_LOG_ANDROID_LOG ON)

The correct variable name is ZF_LOG_USE_ANDROID_LOG.

Happy to submit a PR if that'd be helpful. I'm using this library for a cross-platform project and it's been great so far.

Failed to build under cygwin

zf_log.c#288

#if defined(_WIN32) || defined(_WIN64)
	#include <windows.h>
#else
	#include <unistd.h>
	#include <sys/time.h>
	#if defined(__linux__)
		#include <linux/limits.h>
	#else
		#include <sys/syslimits.h>
	#endif
#endif

It says "error "Do not include sys/syslimits.h from applications0 directly." bash: /usr/include/sys/syslimits.h:15:3:: No such file or directory"

support for embedded cpu´s

Hello,

Do you have any good idea what define I should use for this improvement? You use _WIN32, _WIN64, ANDROID, linux, MACH.
So what do you think should I use for BARE ARM or for an Embedded RTOS like FreeRTOS?

regards,
mathias

Add a possibility to use external snprintf function

Hi,

Do you see any possibility to use some external vsnprintf? I would like to use zf_log in comination with https://github.com/mpaland/printf which is a nice printf / snprintf implementation. So therefore i want that zf_log uses snprintf instead of the vsnprintf.

With the current implementation this is not possible. Can you add any way to change it. I can also add a pull if you can give me a hint how you would like to solve it that i will go main line.

many thanks
cheers
mathias

Create a new release tag

we are using zf-log with git submodule, so help there could be a "stable" tag but not master.

thread safety ?

Hi,
I'm interested in this library but have a few questions regarding thread safety. The readme says it is "thread-safe", but what happens when a thread writes a log message while the output callback is already in progress (called from a another thread) ?
I don't see any explicit locking / queuing in the built-in output callbacks...

  • stderr with WriteFile (win) : I admit I can't find much documentation on using WriteFile with stderr, but how can you tell if FILE_APPEND_DATA or FILE_WRITE_DATA are set ?

  • stderr with write() (*nix); the code comments that the usage is atomic, but POSIX says "A write is atomic if the whole amount written in one operation is not interleaved with data from any other process." -- so, OK for multiple processes, but multiple threads ?

  • OutputDebugString on win32 is probably async safe, I read somewhere that it uses a mutex internally? Not 100% sure about this though, and it's not quite what I'm looking for.

I know there has been some testing with multiple threads, so maybe I'm just missing something ? I'd like to hear more about this.

Thanks!

Nothing logged to syslog on iOS

My setup

  • iOS 13.2
  • macOS 10.14

Problem

  • zf_log does not log to syslog as advertised.

Repro

  • Build and run a test app on an iPhone using zf_log APIs in the same manner as in examples/hello.c, i.e., calling the following
zf_log_set_tag_prefix("MyHeader");
ZF_LOGW("Hello ZF_LOG!!");
  • Then open Console.app on macOS and select the phone in the sidebar

  • Search for keyword such as ZF_LOG in the log.

  • Console returns nothing in the search result.

  • The log is only visible in the Xcode console.

Wireshark like memory dump.

TO enable wireshark like memory dump:
02-24|13:44:38.552|27371|27371|V|TestStub.x|[email protected]:137| 53 6f 6d 65 74 68 69 6e 67 20 69 6d 70 6f 72 74 Something import
02-24|13:44:38.552|27371|27371|V|TestStub.x|[email protected]:137| 61 6e 74 20 69 73 20 68 65 72 65 20 69 6e 20 6d ant is here in m
02-24|13:44:38.552|27371|27371|V|TestStub.x|[email protected]:137| 65 6d 6f 72 79 20 3a 20 61 6b 6a 73 64 6b 6a 61 emory : akjsdkja
02-24|13:44:38.552|27371|27371|V|TestStub.x|[email protected]:137| 68 73 64 6a 61 6a 68 64 68 6a 61 67 73 64 68 67 hsdjajhdhjagsdhg
02-24|13:44:38.552|27371|27371|V|TestStub.x|[email protected]:137| 61 73 68 64 67 68 6a 61 73 64 67 61 67 73 64 6a ashdghjasdgagsdj
02-24|13:44:38.552|27371|27371|V|TestStub.x|[email protected]:137| 68 61 67 73 64 68 6a 61 67 73 6a 64 61 73 64 6a hagsdhjagsjdasdj
02-24|13:44:38.552|27371|27371|V|TestStub.x|[email protected]:137| 61 67 73 64 6a 67 00 agsdjg?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.