Showing preview only (269K chars total). Download the full file or copy to clipboard to get everything.
Repository: wonder-mice/zf_log
Branch: master
Commit: 5a3f2b46c3f6
Files: 44
Total size: 255.2 KB
Directory structure:
gitextract_z8twfn65/
├── .appveyor.yml
├── .gitignore
├── .travis.yml
├── CMakeLists.txt
├── LICENSE
├── README.md
├── TODO.md
├── examples/
│ ├── CMakeLists.txt
│ ├── args_eval.c
│ ├── custom_output.c
│ ├── file_output.c
│ └── hello.c
├── tests/
│ ├── CMakeLists.txt
│ ├── filesize_check.c
│ ├── perf/
│ │ ├── CMakeLists.txt
│ │ ├── run_tests.py
│ │ ├── test_executable_size.cpp
│ │ ├── test_speed.cpp
│ │ ├── test_switch.h
│ │ └── time_it.py
│ ├── test_aux_spec.c
│ ├── test_builtin_output_facilities.c
│ ├── test_call_site_size_censoring.c
│ ├── test_call_site_size_conditional.c
│ ├── test_call_site_size_fmt_args.c
│ ├── test_call_site_size_msg_only.c
│ ├── test_censoring.c
│ ├── test_compilation_cpp.cpp
│ ├── test_conditional.c
│ ├── test_decoration.main.c
│ ├── test_decoration.module.c
│ ├── test_externally_defined_state.c
│ ├── test_externally_defined_state_cpp.cpp
│ ├── test_log_level_override.c
│ ├── test_log_level_switches.c
│ ├── test_log_message_content.c
│ ├── test_private_parts.c
│ ├── test_source_location.c
│ ├── zf_log.h.master
│ └── zf_test.h
├── zf_log/
│ ├── CMakeLists.txt
│ ├── zf_log.c
│ └── zf_log.h
└── zf_log-config.cmake.in
================================================
FILE CONTENTS
================================================
================================================
FILE: .appveyor.yml
================================================
version: 0.3.1-{build}
environment:
matrix:
- GENERATOR: "Visual Studio 12"
CONFIG: Release
OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON
- GENERATOR: "Visual Studio 12"
CONFIG: Debug
OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON
- GENERATOR: "Visual Studio 12 Win64"
CONFIG: Release
OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON
- GENERATOR: "Visual Studio 12 Win64"
CONFIG: Debug
OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON
- GENERATOR: "Visual Studio 14"
CONFIG: Release
OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON
- GENERATOR: "Visual Studio 14"
CONFIG: Debug
OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON
- GENERATOR: "Visual Studio 14 Win64"
CONFIG: Release
OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON
- GENERATOR: "Visual Studio 14 Win64"
CONFIG: Debug
OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON
- GENERATOR: "MinGW Makefiles"
CONFIG: Debug
OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON
- GENERATOR: "MinGW Makefiles"
CONFIG: Release
OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON
build_script:
- if "MinGW Makefiles"=="%GENERATOR%" set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
- if "MinGW Makefiles"=="%GENERATOR%" set PATH=C:\MinGW\bin;%PATH%
- ps: mkdir build.msvc
- ps: cd build.msvc
- cmake "-G%GENERATOR%" %OPTIONS% ..
- cmake --build . --config "%CONFIG%"
test_script:
- ctest --output-on-failure -C "%CONFIG%"
================================================
FILE: .gitignore
================================================
/build.*
/CMakeLists.txt.user
/tags
================================================
FILE: .travis.yml
================================================
language: c++
compiler:
- clang
- gcc
os:
- osx
env:
- OPTIONS="-DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON -DCMAKE_BUILD_TYPE:string=Debug"
- OPTIONS="-DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON -DCMAKE_BUILD_TYPE:string=Release"
matrix:
include:
- os: linux
dist: trusty
sudo: required
compiler: clang
env:
- OPTIONS="-DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON -DCMAKE_BUILD_TYPE:string=Debug"
- os: linux
dist: trusty
sudo: required
compiler: clang
env:
- OPTIONS="-DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON -DCMAKE_BUILD_TYPE:string=Release"
- os: linux
dist: trusty
sudo: required
compiler: gcc
env:
- OPTIONS="-DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON -DCMAKE_BUILD_TYPE:string=Debug"
- os: linux
dist: trusty
sudo: required
compiler: gcc
env:
- OPTIONS="-DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON -DCMAKE_BUILD_TYPE:string=Release"
install: true
script:
- find . -name "CMakeLists.txt" -exec sed -i .bak -e "s/VERSION 3.2/VERSION 2.8/g" {} \;
- mkdir build.make && cd build.make && cmake ${OPTIONS} .. && cmake --build . && ctest --output-on-failure
================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.2)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
if(NOT DEFINED CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type")
endif()
project(zf_log)
set(INSTALL_INCLUDE_DIR include CACHE PATH
"Installation directory for header files")
set(INSTALL_LIB_DIR lib CACHE PATH
"Installation directory for libraries")
set(INSTALL_CMAKE_DIR lib/cmake/zf_log CACHE PATH
"Installation directory for CMake files")
set(ZF_LOG_LIBRARY_PREFIX CACHE STRING
"Prefix for all linker symbols exported by the library")
option(ZF_LOG_CONFIGURE_INSTALL "Generate install target" ON)
option(ZF_LOG_EXAMPLES "Build examples" OFF)
option(ZF_LOG_TESTS "Build tests" OFF)
option(ZF_LOG_PERF_TESTS "Build performance tests (requires Python)" OFF)
option(ZF_LOG_USE_ANDROID_LOG "Use Android log by defaul when available" OFF)
option(ZF_LOG_USE_NSLOG "Use NSLog (Apple System Log) by default when available" OFF)
option(ZF_LOG_USE_DEBUGSTRING "Use OutputDebugString (Windows) by default when available" OFF)
option(ZF_LOG_USE_CONFIG_HEADER "Include zf_log_config.h header file in zf_log compilation untis" OFF)
option(ZF_LOG_OPTIMIZE_SIZE "Optimize for size (prefer size over speed)" OFF)
add_subdirectory(zf_log)
if(ZF_LOG_EXAMPLES)
add_subdirectory(examples)
endif()
if(ZF_LOG_TESTS)
enable_testing()
add_subdirectory(tests)
endif()
if(ZF_LOG_PERF_TESTS)
enable_testing()
add_subdirectory(tests/perf)
endif()
if(ZF_LOG_CONFIGURE_INSTALL)
export(EXPORT zf_log)
install(EXPORT zf_log
DESTINATION ${INSTALL_CMAKE_DIR})
configure_file(zf_log-config.cmake.in zf_log-config.cmake @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/zf_log-config.cmake
DESTINATION ${INSTALL_CMAKE_DIR})
endif()
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2017 wonder-mice
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
[](https://travis-ci.org/wonder-mice/zf_log)
[](https://ci.appveyor.com/project/wonder-mice/zf-log/branch/master)
[](https://gitter.im/wonder-mice/zf_log?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
zf_log
========
### Core logging library for C, Objective-C and C++
Following the [Unix way](https://en.wikipedia.org/wiki/Unix_philosophy), 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:
```c
/* 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:
```c
/* 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:
```c
/* 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:
```c
/* 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:
```c
/* 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):
```c
/* 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:
```c
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 main@hello.c:9 Number of arguments: 1
| | |
| | +- line number
| +- source file name
+- function name
```
It's also possible to dump a memory region. For example:
```c
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](examples) folder. For more details see
comments in [zf_log/zf_log.h](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:
* [zf_log.h](zf_log/zf_log.h)
* [zf_log.c](zf_log/zf_log.c)
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](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](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:
```cmake
target_link_libraries(my_target zf_log)
```
### Installation
Another option is to build and install the library:
```bash
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:
```cmake
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:
```cmake
target_link_libraries(my_target zf_log)
```
To build as a shared library set CMake variable `BUILD_SHARED_LIBS`:
```bash
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:
```c
#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:
```c
#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.
[zf_log/zf_log.c]: zf_log/zf_log.c
[examples/custom_output.c]: examples/custom_output.c
Comparison
--------
This table is work in progress. See [tests/perf](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.
================================================
FILE: TODO.md
================================================
Things to do
------------
* Add callback arg to output callback
* Update README, it sucks now
* Print start address for each line of memory output?
* Introduce private format_callback which probably will replace put_msg
This will provide more modular structure and will point out where to
insert custom code when different format function must be used.
As an exercise, add optional support for CFStringCreateWithFormat().
* Use Cmake GNUInstallDirs for install locations.
Things probably not to do
-------------------------
* Number of parameters in _zf_log_write_xxx() functions could be reduced
by having a separate function for each log level. One way to implement
that is to have a static array of logging functions. Log level will be
an index in that array. This technique reduces the size of code
generated per log statement (e.g. 5 bytes less on x64). But it also
increases the size of the library itself, because all those new
28 functions (7 levels x 2 mem/msg x 2 debug/ndebug) must be defined.
And it also makes implementation more complex. Currently considered
not worth the effort.
* Output some memory even when buffer is too small. Will significantly
increase complexity of output_mem() function, while providing not
much benefits. Memory output line is pretty much limited in length,
so problem could be solved easily by choosing right ZF_LOG_BUF_SZ.
* Debug functions (_zf_log_write.*_d) could also receive the length of
string passed in as a "file" parameter. That will allow to search for
a slash from the end of the string. While it will be up to 30 times
faster, overall performance gain will be too small to notice, because
the biggest offenders right now are localtime() and file io. Also
this will require to push additional argument which will increase the
size of call site which could be very noticable - size of the binary
will go up.
================================================
FILE: examples/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.2)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
if(MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4 /WX")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -pedantic-errors")
endif()
if(ZF_LOG_LIBRARY_PREFIX)
add_definitions("-DZF_LOG_LIBRARY_PREFIX=${ZF_LOG_LIBRARY_PREFIX}")
endif()
add_executable(hello_c hello.c)
target_link_libraries(hello_c zf_log)
add_executable(custom_output custom_output.c)
target_link_libraries(custom_output zf_log)
add_executable(file_output file_output.c)
target_link_libraries(file_output zf_log)
add_executable(args_eval args_eval.c)
target_link_libraries(args_eval zf_log)
================================================
FILE: examples/args_eval.c
================================================
#include <signal.h>
#include <stdlib.h>
#define ZF_LOG_LEVEL ZF_LOG_INFO
#include <zf_log.h>
static int call_exit()
{
exit(1);
}
int main(int argc, char *argv[])
{
(void)argc; (void)argv;
/* Current log level is set to ZF_LOG_INFO by defining ZF_LOG_LEVEL
* before zf_log.h include. All log messages below INFO level will be
* compiled out.
*/
ZF_LOGV("Argument of this VERBOSE message will not be evaluated: %i",
call_exit());
ZF_LOGI("So you will see that INFO message");
/* Output log level is set to WARN and then to INFO. Argument of INFO log
* statement will be evaluated only once (after setting output log level to
* INFO).
*/
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;
}
================================================
FILE: examples/custom_output.c
================================================
#include <assert.h>
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#define OUTPUT_DEBUG_STRING
#else
#include <syslog.h>
#define OUTPUT_SYSLOG
#endif
#include <zf_log.h>
#ifdef OUTPUT_SYSLOG
static int syslog_level(const int lvl)
{
switch (lvl)
{
case ZF_LOG_VERBOSE:
return LOG_DEBUG;
case ZF_LOG_DEBUG:
return LOG_DEBUG;
case ZF_LOG_INFO:
return LOG_INFO;
case ZF_LOG_WARN:
return LOG_WARNING;
case ZF_LOG_ERROR:
return LOG_ERR;
case ZF_LOG_FATAL:
return LOG_EMERG;
default:
assert(!"can't be");
return LOG_EMERG;
}
}
#endif
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->tag_b);
#else
#error Unsupported platform
#endif
}
int main(int argc, char *argv[])
{
#if defined(OUTPUT_SYSLOG)
openlog("custom_output", LOG_CONS|LOG_PERROR|LOG_PID, LOG_USER);
#endif
const unsigned put_mask =
#if defined(OUTPUT_SYSLOG)
ZF_LOG_PUT_STD & !ZF_LOG_PUT_CTX;
#else
ZF_LOG_PUT_STD;
#endif
;
zf_log_set_output_v(put_mask, 0, custom_output_callback);
ZF_LOGI("Number of arguments goes into custom output: %i", argc);
ZF_LOGI_MEM(argv, argc * sizeof(*argv), "and argv pointers as well:");
#if defined(OUTPUT_SYSLOG)
closelog();
#endif
return 0;
}
================================================
FILE: examples/file_output.c
================================================
#if defined(_WIN32) || defined(_WIN64)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <stdlib.h>
#include "zf_log.h"
FILE *g_log_file;
static void file_output_callback(const zf_log_message *msg, void *arg)
{
(void)arg;
*msg->p = '\n';
fwrite(msg->buf, msg->p - msg->buf + 1, 1, g_log_file);
fflush(g_log_file);
}
static void file_output_close(void)
{
fclose(g_log_file);
}
static void file_output_open(const char *const log_path)
{
g_log_file = fopen(log_path, "a");
if (!g_log_file)
{
ZF_LOGW("Failed to open log file %s", log_path);
return;
}
atexit(file_output_close);
zf_log_set_output_v(ZF_LOG_PUT_STD, 0, file_output_callback);
}
int main(int argc, char *argv[])
{
file_output_open("example.log");
ZF_LOGI("Writing number of arguments to log file: %i", argc);
ZF_LOGI_MEM(argv, argc * sizeof(*argv), "argv pointers:");
return 0;
}
================================================
FILE: examples/hello.c
================================================
#define ZF_LOG_LEVEL ZF_LOG_INFO
#define ZF_LOG_TAG "MAIN"
#include <zf_log.h>
int main(int argc, char *argv[])
{
zf_log_set_tag_prefix("hello");
ZF_LOGI("You will see the number of arguments: %i", argc);
ZF_LOGD("You will NOT see the first argument: %s", *argv);
zf_log_set_output_level(ZF_LOG_WARN);
ZF_LOGW("You will see this WARNING message");
ZF_LOGI("You will NOT see this INFO message");
const char data[] =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"Aliquam pharetra orci id velit porttitor tempus.";
ZF_LOGW_MEM(data, sizeof(data), "Lorem ipsum at %p:", (const void *) data);
return 0;
}
================================================
FILE: tests/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.2)
include(CMakeParseArguments)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
if(MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4 /WX")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -pedantic-errors")
endif()
# zf_test
set(HEADERS_DIR ${CMAKE_CURRENT_SOURCE_DIR})
add_library(zf_test INTERFACE)
target_include_directories(zf_test INTERFACE $<BUILD_INTERFACE:${HEADERS_DIR}>)
set(HEADERS zf_test.h)
add_custom_target(zf_test_headers SOURCES ${HEADERS})
function(add_test_target target)
cmake_parse_arguments(arg
"COMPILE_ONLY"
""
"SOURCES;CSTD;CXXSTD;DEFINES"
${ARGN})
if(arg_COMPILE_ONLY)
add_library(${target} STATIC ${arg_SOURCES})
else()
add_executable(${target} ${arg_SOURCES})
target_link_libraries(${target} zf_test)
add_test(NAME ${target} COMMAND ${target})
endif()
if(arg_CSTD)
set_property(TARGET ${target} PROPERTY C_STANDARD "${arg_CSTD}")
endif()
if(arg_CXXSTD)
set_property(TARGET ${target} PROPERTY CXX_STANDARD "${arg_CXXSTD}")
endif()
set_property(TARGET ${target} PROPERTY COMPILE_DEFINITIONS "${arg_DEFINES}")
target_include_directories(${target} PRIVATE "${PROJECT_SOURCE_DIR}/zf_log")
endfunction()
function(add_test_target_group target)
add_test_target(${target}_c99 ${ARGN} CSTD 99)
add_test_target(${target}_c11 ${ARGN} CSTD 11)
endfunction()
add_test_target_group(test_log_level_switches_verbose SOURCES test_log_level_switches.c DEFINES ZF_LOG_LEVEL=ZF_LOG_VERBOSE)
add_test_target_group(test_log_level_switches_debug SOURCES test_log_level_switches.c DEFINES ZF_LOG_LEVEL=ZF_LOG_DEBUG)
add_test_target_group(test_log_level_switches_info SOURCES test_log_level_switches.c DEFINES ZF_LOG_LEVEL=ZF_LOG_INFO)
add_test_target_group(test_log_level_switches_warn SOURCES test_log_level_switches.c DEFINES ZF_LOG_LEVEL=ZF_LOG_WARN)
add_test_target_group(test_log_level_switches_error SOURCES test_log_level_switches.c DEFINES ZF_LOG_LEVEL=ZF_LOG_ERROR)
add_test_target_group(test_log_level_switches_fatal SOURCES test_log_level_switches.c DEFINES ZF_LOG_LEVEL=ZF_LOG_FATAL)
add_test_target_group(test_log_level_switches_none SOURCES test_log_level_switches.c DEFINES ZF_LOG_LEVEL=ZF_LOG_NONE)
add_test_target_group(test_log_level_override SOURCES test_log_level_override.c)
add_test_target_group(test_log_message_content SOURCES test_log_message_content.c)
add_test_target_group(test_log_message_content_Os SOURCES test_log_message_content.c DEFINES ZF_LOG_OPTIMIZE_SIZE=1)
add_test_target_group(test_log_message_content_empty_format SOURCES test_log_message_content.c DEFINES
"ZF_LOG_MESSAGE_CTX_FORMAT=()"
"ZF_LOG_MESSAGE_TAG_FORMAT=()"
"ZF_LOG_MESSAGE_SRC_FORMAT=()")
add_test_target_group(test_log_message_content_empty_format_Os SOURCES test_log_message_content.c DEFINES
"ZF_LOG_OPTIMIZE_SIZE=1"
"ZF_LOG_MESSAGE_CTX_FORMAT=()"
"ZF_LOG_MESSAGE_TAG_FORMAT=()"
"ZF_LOG_MESSAGE_SRC_FORMAT=()")
# Here we use several F_INIT() fields in a row to workaround CMake problem with ";", which acts
# as a list separator in CMake. If not for CMake, context format specification could look like:
# #define ZF_LOG_MESSAGE_CTX_FORMAT \
# (YEAR, S("-ctx:"), F_INIT(( struct { int v; } f_box_a; f_box_a.v = 45; )), F_UINT(4, f_box_a.v))
add_test_target_group(test_log_message_content_custom_fields SOURCES test_log_message_content.c DEFINES
"ZF_LOG_MESSAGE_CTX_FORMAT=(YEAR, S(\"-ctx:\"), F_INIT(( struct { int v )), F_INIT(( } f_box_a )), F_INIT(( f_box_a.v = 45 )), F_UINT(4, f_box_a.v))"
"ZF_LOG_MESSAGE_TAG_FORMAT=(S(\"-tag:\"), F_INIT(( struct { int v )), F_INIT(( } f_box_b )), F_INIT(( f_box_b.v = 36 )), F_UINT(4, f_box_b.v))"
"ZF_LOG_MESSAGE_SRC_FORMAT=(S(\"-src:\"), F_INIT(( struct { int v )), F_INIT(( } f_box_c )), F_INIT(( f_box_c.v = 27 )), F_UINT(4, f_box_c.v))")
add_test_target_group(test_log_message_content_custom_fields_Os SOURCES test_log_message_content.c DEFINES
"ZF_LOG_OPTIMIZE_SIZE=1"
"ZF_LOG_MESSAGE_CTX_FORMAT=(YEAR, S(\"ctx:\"), F_INIT(( struct { int v )), F_INIT(( } f_box_a )), F_INIT(( f_box_a.v = 45 )), F_UINT(4, f_box_a.v))"
"ZF_LOG_MESSAGE_TAG_FORMAT=(S(\"tag:\"), F_INIT(( struct { int v )), F_INIT(( } f_box_b )), F_INIT(( f_box_b.v = 36 )), F_UINT(4, f_box_b.v))"
"ZF_LOG_MESSAGE_SRC_FORMAT=(S(\"src:\"), F_INIT(( struct { int v )), F_INIT(( } f_box_c )), F_INIT(( f_box_c.v = 27 )), F_UINT(4, f_box_c.v))")
add_test_target_group(test_source_location_none SOURCES test_source_location.c
DEFINES ZF_LOG_SRCLOC=ZF_LOG_SRCLOC_NONE TEST_SRCLOC=ZF_LOG_SRCLOC_NONE)
add_test_target_group(test_source_location_short SOURCES test_source_location.c
DEFINES ZF_LOG_SRCLOC=ZF_LOG_SRCLOC_SHORT TEST_SRCLOC=ZF_LOG_SRCLOC_SHORT)
add_test_target_group(test_source_location_long SOURCES test_source_location.c
DEFINES ZF_LOG_SRCLOC=ZF_LOG_SRCLOC_LONG TEST_SRCLOC=ZF_LOG_SRCLOC_LONG)
add_test_target_group(test_source_location_none_Os SOURCES test_source_location.c
DEFINES ZF_LOG_SRCLOC=ZF_LOG_SRCLOC_NONE TEST_SRCLOC=ZF_LOG_SRCLOC_NONE ZF_LOG_OPTIMIZE_SIZE=1)
add_test_target_group(test_source_location_short_Os SOURCES test_source_location.c
DEFINES ZF_LOG_SRCLOC=ZF_LOG_SRCLOC_SHORT TEST_SRCLOC=ZF_LOG_SRCLOC_SHORT ZF_LOG_OPTIMIZE_SIZE=1)
add_test_target_group(test_source_location_long_Os SOURCES test_source_location.c
DEFINES ZF_LOG_SRCLOC=ZF_LOG_SRCLOC_LONG TEST_SRCLOC=ZF_LOG_SRCLOC_LONG ZF_LOG_OPTIMIZE_SIZE=1)
add_test_target_group(test_conditional SOURCES test_conditional.c)
add_test_target_group(test_censoring_off SOURCES test_censoring.c DEFINES ZF_LOG_CENSORING=ZF_LOG_UNCENSORED TEST_LOG_SECRETS=1)
add_test_target_group(test_censoring_on SOURCES test_censoring.c DEFINES ZF_LOG_CENSORING=ZF_LOG_CENSORED TEST_LOG_SECRETS=0)
add_test_target_group(test_private_parts SOURCES test_private_parts.c)
add_test_target_group(test_decoration SOURCES test_decoration.module.c test_decoration.main.c)
add_test_target_group(test_aux_spec SOURCES test_aux_spec.c)
add_test_target_group(test_builtin_output_facilities SOURCES test_builtin_output_facilities.c COMPILE_ONLY)
add_test_target_group(test_externally_defined_state SOURCES test_externally_defined_state.c)
add_test_target(test_externally_defined_state_cpp SOURCES test_externally_defined_state_cpp.cpp CXXSTD 11)
add_test_target(test_compilation_cpp SOURCES test_compilation_cpp.cpp CXXSTD 11)
# generated code size tests
add_executable(filesize_check filesize_check.c)
set(CODE_SIZE_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/code_size_tests")
function(save_preprocessor_output target)
if(MSVC)
# MSVC lacks this feature, /P suppresses compilation.
#target_compile_options(${target} PRIVATE "/P")
else()
target_compile_options(${target} PRIVATE "-save-temps")
endif()
endfunction()
function(add_copy_command src dst)
add_custom_command(OUTPUT "${dst}"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${src}" "${dst}"
DEPENDS "${src}")
set_source_files_properties("${dst}" PROPERTIES GENERATED TRUE)
endfunction()
# copy reference and current versions of zf_log.h
add_copy_command("${CMAKE_CURRENT_SOURCE_DIR}/zf_log.h.master" "${CODE_SIZE_SOURCE_DIR}/prev/zf_log.h")
add_copy_command("${PROJECT_SOURCE_DIR}/zf_log/zf_log.h" "${CODE_SIZE_SOURCE_DIR}/curr/zf_log.h")
function(add_code_size_test target)
cmake_parse_arguments(arg
""
""
"SOURCES;DEFINES"
${ARGN})
set(prev_sources "${CODE_SIZE_SOURCE_DIR}/prev/zf_log.h")
set(curr_sources "${CODE_SIZE_SOURCE_DIR}/curr/zf_log.h")
foreach(src ${arg_SOURCES})
# "-save-temps" will put all ".s" files directly in the "tests" build
# directory which is not specific for the target. Since it's useful to
# examine those files, test sources will be copied with different
# names for *-prev and *-curr targets. That way generated "*.s" files
# will have different names too and will not overwrite each other.
get_filename_component(src_name "${src}" NAME_WE)
get_filename_component(src_ext "${src}" EXT)
get_filename_component(src_path "${src}" ABSOLUTE)
set(src_copy_prev "${CODE_SIZE_SOURCE_DIR}/${target}-${src_name}-prev${src_ext}")
set(src_copy_curr "${CODE_SIZE_SOURCE_DIR}/${target}-${src_name}-curr${src_ext}")
add_copy_command("${src_path}" "${src_copy_prev}")
add_copy_command("${src_path}" "${src_copy_curr}")
list(APPEND prev_sources "${src_copy_prev}")
list(APPEND curr_sources "${src_copy_curr}")
endforeach()
# prev library
add_library(${target}-prev STATIC ${prev_sources})
target_include_directories(${target}-prev PRIVATE "${CODE_SIZE_SOURCE_DIR}/prev")
target_compile_definitions(${target}-prev PRIVATE ${arg_DEFINES})
save_preprocessor_output(${target}-prev)
# curr library
add_library(${target}-curr STATIC ${curr_sources})
target_include_directories(${target}-curr PRIVATE "${CODE_SIZE_SOURCE_DIR}/curr")
target_compile_definitions(${target}-curr PRIVATE ${arg_DEFINES})
save_preprocessor_output(${target}-curr)
# test case
add_dependencies(filesize_check ${target}-prev ${target}-curr)
add_test(NAME ${target}_check
COMMAND filesize_check "$<TARGET_FILE:${target}-prev>" "$<TARGET_FILE:${target}-curr>")
endfunction()
add_code_size_test(test_call_site_size_msg_only SOURCES test_call_site_size_msg_only.c)
add_code_size_test(test_call_site_size_fmt_args SOURCES test_call_site_size_fmt_args.c)
add_code_size_test(test_call_site_size_conditional_true SOURCES test_call_site_size_conditional.c DEFINES TEST_CONDITION=1)
add_code_size_test(test_call_site_size_conditional_false SOURCES test_call_site_size_conditional.c DEFINES TEST_CONDITION=0)
add_code_size_test(test_call_site_size_censoring_on SOURCES test_call_site_size_censoring.c DEFINES ZF_LOG_CENSORING=ZF_LOG_CENSORED)
add_code_size_test(test_call_site_size_censoring_off SOURCES test_call_site_size_censoring.c DEFINES ZF_LOG_CENSORING=ZF_LOG_UNCENSORED)
================================================
FILE: tests/filesize_check.c
================================================
#if defined(_WIN32) || defined(_WIN64)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <stdlib.h>
static long filesize(const char *const path)
{
FILE *const f = fopen(path, "rb");
if (0 == f)
{
fprintf(stderr, "Bad file: %s\n", path);
exit(1);
}
fseek(f, 0, SEEK_END);
const long sz = (unsigned)ftell(f);
fclose(f);
return sz;
}
int main(int argc, const char *argv[])
{
if (2 >= argc)
{
fprintf(stderr, "Usage: prog f1_path f2_path\n");
return 1;
}
const long f1_sz = filesize(argv[1]);
const long f2_sz = filesize(argv[2]);
if (f1_sz < f2_sz)
{
fprintf(stderr, "New size is larger: %li < %li\n", f1_sz, f2_sz);
return 1;
}
return 0;
}
================================================
FILE: tests/perf/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.2)
include(ExternalProject)
include(CMakeParseArguments)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(PythonInterp 2.7 REQUIRED)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
if(MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4 /WX")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -pedantic-errors")
endif()
option(ZF_LOG_PERF_TEST_SAVE_TEMPS "Save preprocessor and disassembler output" OFF)
option(ZF_LOG_PERF_TEST_ZF_LOG_OS "Add zf_log built with ZF_LOG_OPTIMIZE_SIZE to performance tests" OFF)
option(ZF_LOG_PERF_TEST_VERBOSE_3P_BUILD "Enable verbose build output for 3rd party libraries (noisy)" OFF)
# Launch rules are target properties (RULE_LAUNCH_COMPILE, RULE_LAUNCH_LINK)
# that are used to time compilation and linking. Tests that require this
# properties will be disabled if current generator doesn't support launch
# rules. See CMake documentation for up to date list of generators that support
# launch rules.
if(CMAKE_GENERATOR MATCHES "Makefiles" OR
CMAKE_GENERATOR MATCHES "Ninja")
set(LAUNCH_RULES ON)
else()
message(WARNING "Timing compilation and linking is not supported by \"${CMAKE_GENERATOR}\" generator!")
set(LAUNCH_RULES OFF)
endif()
# Since a lot of 3rd party dependencies envolved, it's only so much we can do here.
# Non-Unix support is possible, but not in the scope right now.
if(NOT UNIX)
message(WARNING "Performance tests only maintained for Unix platforms!")
endif()
# For convenience, ZF_LOG_PERF_TEST_VERBOSE_3P_BUILD is inverse of what is
# actually needed. SILENT_3P_BUILD variable will be used instead.
set(SILENT_3P_BUILD ON)
if(ZF_LOG_PERF_TEST_VERBOSE_3P_BUILD)
set(SILENT_3P_BUILD OFF)
endif()
function(add_target target)
cmake_parse_arguments(arg
"STATICLIB;EXECUTABLE;NO_THREADS"
"TIME_COMPILE;TIME_LINK"
"SOURCES;DEFINES;INCLUDES;COMPILE_OPTIONS;LIBRARIES"
${ARGN})
if(ZF_LOG_PERF_TEST_SAVE_TEMPS)
# Clang writes *.s and *.ii files into its current working directory.
# Since the same source files are used in multiple targets, need to
# copy them, so they will have different names for different targets.
set(SOURCES "")
foreach(source ${arg_SOURCES})
if(IS_ABSOLUTE source)
set(src "${source}")
else()
set(src "${CMAKE_CURRENT_SOURCE_DIR}/${source}")
endif()
get_filename_component(src_name "${source}" NAME)
set(dst "${CMAKE_CURRENT_BINARY_DIR}/sources/${target}-${src_name}")
add_custom_command(OUTPUT "${dst}"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${src}" "${dst}"
DEPENDS "${src}")
list(APPEND SOURCES "${dst}")
endforeach()
else()
set(SOURCES ${arg_SOURCES})
endif()
if(arg_STATICLIB)
add_library(${target} STATIC ${SOURCES})
elseif(arg_EXECUTABLE)
add_executable(${target} ${SOURCES})
if(NOT NO_THREADS)
target_link_libraries(${target} Threads::Threads)
endif()
else()
message(FATAL_ERROR "Test target type is not specified.")
endif()
if(ZF_LOG_PERF_SAVE_TEMPS)
target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_options(${target} PRIVATE "-save-temps")
endif()
if(arg_DEFINES)
set_property(TARGET ${target} PROPERTY COMPILE_DEFINITIONS "${arg_DEFINES}")
endif()
if(arg_INCLUDES)
target_include_directories(${target} PRIVATE ${arg_INCLUDES})
endif()
if(arg_COMPILE_OPTIONS)
target_compile_options(${target} PRIVATE ${arg_COMPILE_OPTIONS})
endif()
if(arg_LIBRARIES)
target_link_libraries(${target} ${arg_LIBRARIES})
endif()
if(arg_TIME_COMPILE)
set_property(TARGET ${target} PROPERTY RULE_LAUNCH_COMPILE
"\"${PYTHON_EXECUTABLE}\" \"${CMAKE_CURRENT_SOURCE_DIR}/time_it.py\" \"${arg_TIME_COMPILE}\"")
set_property(TARGET ${target} PROPERTY TIME_COMPILE "${arg_TIME_COMPILE}")
endif()
if(arg_TIME_LINK)
set_property(TARGET ${target} PROPERTY RULE_LAUNCH_LINK
"\"${PYTHON_EXECUTABLE}\" \"${CMAKE_CURRENT_SOURCE_DIR}/time_it.py\" \"${arg_TIME_LINK}\"")
set_property(TARGET ${target} PROPERTY TIME_LINK "${arg_TIME_LINK}")
endif()
endfunction()
# zf_log
set(ZF_LOG_DIR "${PROJECT_SOURCE_DIR}/zf_log")
add_library(zf_log_n STATIC "${ZF_LOG_DIR}/zf_log.h" "${ZF_LOG_DIR}/zf_log.c")
target_include_directories(zf_log_n PUBLIC "${ZF_LOG_DIR}")
add_library(zf_log_Os STATIC "${ZF_LOG_DIR}/zf_log.h" "${ZF_LOG_DIR}/zf_log.c")
target_include_directories(zf_log_Os PUBLIC "${ZF_LOG_DIR}")
set_property(TARGET zf_log_Os PROPERTY COMPILE_DEFINITIONS "ZF_LOG_OPTIMIZE_SIZE")
# spdlog
set(SPDLOG_DIR "${CMAKE_CURRENT_BINARY_DIR}/spdlog")
ExternalProject_Add(spdlog_ep
PREFIX "${SPDLOG_DIR}"
UPDATE_COMMAND ""
GIT_REPOSITORY "https://github.com/gabime/spdlog.git"
GIT_TAG "e91e1b80f9c4332bcef8388ff48ee705128e5519"
CMAKE_GENERATOR "${CMAKE_GENERATOR}"
CMAKE_ARGS
"-DCMAKE_TOOLCHAIN_FILE:filepath=${CMAKE_TOOLCHAIN_FILE}"
"-DCMAKE_INSTALL_PREFIX:path=<INSTALL_DIR>"
"-DCMAKE_BUILD_TYPE:string=${CMAKE_BUILD_TYPE}"
"-DCMAKE_OSX_ARCHITECTURES:string=${CMAKE_OSX_ARCHITECTURES}"
"-DCMAKE_OSX_DEPLOYMENT_TARGET:string=${CMAKE_OSX_DEPLOYMENT_TARGET}"
"-DCMAKE_OSX_SYSROOT:path=${CMAKE_OSX_SYSROOT}"
LOG_DOWNLOAD ${SILENT_3P_BUILD}
LOG_UPDATE ${SILENT_3P_BUILD}
LOG_CONFIGURE ${SILENT_3P_BUILD}
LOG_BUILD ${SILENT_3P_BUILD}
LOG_TEST ${SILENT_3P_BUILD}
LOG_INSTALL ${SILENT_3P_BUILD}
)
add_library(spdlog INTERFACE)
add_dependencies(spdlog spdlog_ep)
set_target_properties(spdlog PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${SPDLOG_DIR}/include")
# easyloggingpp
set(EASYLOG_DIR "${CMAKE_CURRENT_BINARY_DIR}/easyloggingpp")
ExternalProject_Add(easylog_ep
PREFIX "${EASYLOG_DIR}"
UPDATE_COMMAND ""
GIT_REPOSITORY "https://github.com/easylogging/easyloggingpp.git"
GIT_TAG "f926802dfbde716d82b64b8ef3c25b7f0fcfec65"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND "${CMAKE_COMMAND}" -E copy_directory
"<SOURCE_DIR>/src" "<INSTALL_DIR>/include"
LOG_DOWNLOAD ${SILENT_3P_BUILD}
LOG_UPDATE ${SILENT_3P_BUILD}
LOG_CONFIGURE ${SILENT_3P_BUILD}
LOG_BUILD ${SILENT_3P_BUILD}
LOG_TEST ${SILENT_3P_BUILD}
LOG_INSTALL ${SILENT_3P_BUILD}
)
add_library(easylog INTERFACE)
add_dependencies(easylog easylog_ep)
set_target_properties(easylog PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${EASYLOG_DIR}/include")
# g3log
set(G3LOG_DIR "${CMAKE_CURRENT_BINARY_DIR}/g3log")
set(G3LOG_LIBRARY "${CMAKE_STATIC_LIBRARY_PREFIX}g3logger${CMAKE_STATIC_LIBRARY_SUFFIX}")
ExternalProject_Add(g3log_ep
PREFIX "${G3LOG_DIR}"
UPDATE_COMMAND ""
GIT_REPOSITORY "https://github.com/KjellKod/g3log.git"
GIT_TAG "1c6ede6db4fbb12006b61a913de737df56b9dd32"
CMAKE_GENERATOR "${CMAKE_GENERATOR}"
CMAKE_ARGS
"-Wno-dev"
"-DCMAKE_TOOLCHAIN_FILE:filepath=${CMAKE_TOOLCHAIN_FILE}"
"-DCMAKE_INSTALL_PREFIX:path=<INSTALL_DIR>"
"-DCMAKE_BUILD_TYPE:string=${CMAKE_BUILD_TYPE}"
"-DCMAKE_OSX_ARCHITECTURES:string=${CMAKE_OSX_ARCHITECTURES}"
"-DCMAKE_OSX_DEPLOYMENT_TARGET:string=${CMAKE_OSX_DEPLOYMENT_TARGET}"
"-DCMAKE_OSX_SYSROOT:path=${CMAKE_OSX_SYSROOT}"
"-DUSE_DYNAMIC_LOGGING_LEVELS:bool=ON"
INSTALL_COMMAND "${CMAKE_COMMAND}" -E copy_directory
"<SOURCE_DIR>/src/g3log" "<INSTALL_DIR>/include/g3log"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"<BINARY_DIR>/${G3LOG_LIBRARY}" "<INSTALL_DIR>/lib/${G3LOG_LIBRARY}"
LOG_DOWNLOAD ${SILENT_3P_BUILD}
LOG_UPDATE ${SILENT_3P_BUILD}
LOG_CONFIGURE ${SILENT_3P_BUILD}
LOG_BUILD ${SILENT_3P_BUILD}
LOG_TEST ${SILENT_3P_BUILD}
LOG_INSTALL ${SILENT_3P_BUILD}
)
add_library(g3log INTERFACE)
add_dependencies(g3log g3log_ep)
set_target_properties(g3log PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${G3LOG_DIR}/include")
set_target_properties(g3log PROPERTIES INTERFACE_LINK_LIBRARIES "${G3LOG_DIR}/lib/${G3LOG_LIBRARY}")
# glog
set(GLOG_DIR "${CMAKE_CURRENT_BINARY_DIR}/glog")
set(GLOG_LIBRARY "${CMAKE_STATIC_LIBRARY_PREFIX}glog${CMAKE_STATIC_LIBRARY_SUFFIX}")
ExternalProject_Add(glog_ep
PREFIX "${GLOG_DIR}"
UPDATE_COMMAND ""
GIT_REPOSITORY "https://github.com/google/glog.git"
GIT_TAG "4d391fe692ae6b9e0105f473945c415a3ce5a401"
CMAKE_GENERATOR "${CMAKE_GENERATOR}"
CMAKE_ARGS
"-Wno-dev"
"-DCMAKE_TOOLCHAIN_FILE:filepath=${CMAKE_TOOLCHAIN_FILE}"
"-DCMAKE_INSTALL_PREFIX:path=<INSTALL_DIR>"
"-DCMAKE_BUILD_TYPE:string=${CMAKE_BUILD_TYPE}"
"-DCMAKE_OSX_ARCHITECTURES:string=${CMAKE_OSX_ARCHITECTURES}"
"-DCMAKE_OSX_DEPLOYMENT_TARGET:string=${CMAKE_OSX_DEPLOYMENT_TARGET}"
"-DCMAKE_OSX_SYSROOT:path=${CMAKE_OSX_SYSROOT}"
LOG_DOWNLOAD ${SILENT_3P_BUILD}
LOG_UPDATE ${SILENT_3P_BUILD}
LOG_CONFIGURE ${SILENT_3P_BUILD}
LOG_BUILD ${SILENT_3P_BUILD}
LOG_TEST ${SILENT_3P_BUILD}
LOG_INSTALL ${SILENT_3P_BUILD}
)
add_library(glog INTERFACE)
add_dependencies(glog glog_ep)
set_target_properties(glog PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${GLOG_DIR}/include")
set_target_properties(glog PROPERTIES INTERFACE_LINK_LIBRARIES "${GLOG_DIR}/lib/${GLOG_LIBRARY}")
function(get_test_library lib var)
if((lib STREQUAL "zf_log_n") OR (lib STREQUAL "zf_log_Os"))
set(lib "zf_log")
endif()
set(${var} "${lib}" PARENT_SCOPE)
endfunction()
function(get_test_compile_options lib var)
set(compile_options)
if(lib STREQUAL "g3log")
# g3log public headers generate "braced-scalar-init" warnings
set(compile_options "-Wno-braced-scalar-init")
endif()
set(${var} "${compile_options}" PARENT_SCOPE)
endfunction()
function(add_executable_size_test lib)
get_test_library("${lib}" test_library)
get_test_compile_options("${lib}" compile_options)
add_target(test_call_site_size.str.${lib}.1 STATICLIB LIBRARIES "${lib}"
COMPILE_OPTIONS ${compile_options}
TIME_COMPILE "${CMAKE_CURRENT_BINARY_DIR}/compile_time.${lib}.json"
SOURCES test_executable_size.cpp
DEFINES "TEST_LIBRARY=${test_library}"
"TEST_SEVERAL_STATEMENTS")
add_target(test_call_site_size.str.${lib}.2 STATICLIB LIBRARIES "${lib}"
COMPILE_OPTIONS ${compile_options}
SOURCES test_executable_size.cpp
DEFINES "TEST_LIBRARY=${test_library}"
"TEST_SEVERAL_STATEMENTS" "TEST_EXTRA_STATEMENT")
add_target(test_call_site_size.fmti.${lib}.1 STATICLIB LIBRARIES "${lib}"
COMPILE_OPTIONS ${compile_options}
SOURCES test_executable_size.cpp
DEFINES "TEST_LIBRARY=${test_library}"
"TEST_FORMAT_INTS" "TEST_SEVERAL_STATEMENTS")
add_target(test_call_site_size.fmti.${lib}.2 STATICLIB LIBRARIES "${lib}"
COMPILE_OPTIONS ${compile_options}
SOURCES test_executable_size.cpp
DEFINES "TEST_LIBRARY=${test_library}"
"TEST_FORMAT_INTS" "TEST_SEVERAL_STATEMENTS" "TEST_EXTRA_STATEMENT")
add_target(test_executable_size.m1.${lib} EXECUTABLE LIBRARIES "${lib}" NO_THREADS
COMPILE_OPTIONS ${compile_options}
TIME_LINK "${CMAKE_CURRENT_BINARY_DIR}/link_time.${lib}.json"
SOURCES test_executable_size.cpp
DEFINES "TEST_LIBRARY=${test_library}")
list(APPEND PARAMETERS "-p" "call_site_size:str:${lib}:1:$<TARGET_FILE:test_call_site_size.str.${lib}.1>")
list(APPEND PARAMETERS "-p" "call_site_size:str:${lib}:2:$<TARGET_FILE:test_call_site_size.str.${lib}.2>")
list(APPEND PARAMETERS "-p" "call_site_size:fmti:${lib}:1:$<TARGET_FILE:test_call_site_size.fmti.${lib}.1>")
list(APPEND PARAMETERS "-p" "call_site_size:fmti:${lib}:2:$<TARGET_FILE:test_call_site_size.fmti.${lib}.2>")
list(APPEND PARAMETERS "-p" "executable_size:m1:${lib}:$<TARGET_FILE:test_executable_size.m1.${lib}>")
if(LAUNCH_RULES)
list(APPEND PARAMETERS "-p" "compile_time:${lib}:$<TARGET_PROPERTY:test_call_site_size.str.${lib}.1,TIME_COMPILE>")
list(APPEND PARAMETERS "-p" "link_time:${lib}:$<TARGET_PROPERTY:test_executable_size.m1.${lib},TIME_LINK>")
endif()
set(PARAMETERS "${PARAMETERS}" PARENT_SCOPE)
endfunction()
if(ZF_LOG_PERF_TEST_ZF_LOG_OS)
add_executable_size_test(zf_log_Os)
endif()
add_executable_size_test(zf_log_n)
add_executable_size_test(spdlog)
add_executable_size_test(easylog)
add_executable_size_test(g3log)
add_executable_size_test(glog)
function(add_speed_test lib)
get_test_library("${lib}" test_library)
get_test_compile_options("${lib}" compile_options)
add_target(test_speed.str.${lib} EXECUTABLE
COMPILE_OPTIONS ${compile_options}
SOURCES test_speed.cpp
DEFINES "TEST_LIBRARY=${test_library}" "TEST_NULL_SINK"
LIBRARIES "${lib}")
add_target(test_speed.fmti.${lib} EXECUTABLE
COMPILE_OPTIONS ${compile_options}
SOURCES test_speed.cpp
DEFINES "TEST_LIBRARY=${test_library}" "TEST_NULL_SINK" "TEST_FORMAT_INTS"
LIBRARIES "${lib}")
add_target(test_speed.str-off.${lib} EXECUTABLE
COMPILE_OPTIONS ${compile_options}
SOURCES test_speed.cpp
DEFINES "TEST_LIBRARY=${test_library}" "TEST_NULL_SINK" "TEST_LOG_OFF"
LIBRARIES "${lib}")
add_target(test_speed.slowf-off.${lib} EXECUTABLE
COMPILE_OPTIONS ${compile_options}
SOURCES test_speed.cpp
DEFINES "TEST_LIBRARY=${test_library}" "TEST_NULL_SINK" "TEST_FORMAT_SLOW_FUNC" "TEST_LOG_OFF"
LIBRARIES "${lib}")
list(APPEND PARAMETERS "-p" "speed:str:${lib}:$<TARGET_FILE:test_speed.str.${lib}>")
list(APPEND PARAMETERS "-p" "speed:fmti:${lib}:$<TARGET_FILE:test_speed.fmti.${lib}>")
list(APPEND PARAMETERS "-p" "speed:str-off:${lib}:$<TARGET_FILE:test_speed.str-off.${lib}>")
list(APPEND PARAMETERS "-p" "speed:slowf-off:${lib}:$<TARGET_FILE:test_speed.slowf-off.${lib}>")
set(PARAMETERS "${PARAMETERS}" PARENT_SCOPE)
endfunction()
if(ZF_LOG_PERF_TEST_ZF_LOG_OS)
add_speed_test(zf_log_Os)
endif()
add_speed_test(zf_log_n)
add_speed_test(spdlog)
add_speed_test(easylog)
add_speed_test(g3log)
add_speed_test(glog)
# results
add_test(NAME perf_tests COMMAND "${PYTHON_EXECUTABLE}"
"${CMAKE_CURRENT_SOURCE_DIR}/run_tests.py"
-t "${CMAKE_CURRENT_BINARY_DIR}/results.txt"
-m "${CMAKE_CURRENT_BINARY_DIR}/results.md"
-b "${CMAKE_BUILD_TYPE}"
-v
${PARAMETERS})
================================================
FILE: tests/perf/run_tests.py
================================================
#!/usr/bin/python
import sys
import os
import argparse
import subprocess
import multiprocessing
import json
import pprint
def take_first(value):
if type(value) is tuple or type(value) is list:
return value[0]
return value
def take_order(value, order):
for i in range(len(order)):
if value == order[i]:
return i
return len(order)
def take_map(value, keys, vals):
if len(keys) != len(vals):
raise RuntimeError("Length of keys and vals must match")
for i in range(len(keys)):
if value == keys[i]:
return vals[i]
return value
def take_best(values, key, compare, reverse=False):
if 0 == len(values):
return []
values = sorted(values, key=key, reverse=reverse)
for i in range(1, len(values)):
if not compare(values[0], values[i]):
return values[0:i]
return values
def take_plural(count, base, suffix):
if 1 == abs(count):
return base
return base + suffix
def take_threads_variants():
# single thread
variants = [1]
cpus = multiprocessing.cpu_count()
if 1 > cpus:
cpus = 1
# load all CPUs
if 1 < cpus:
variants.append(cpus)
# overcommit
variants.append(2 * cpus)
return variants
def _cmp_percentage(p, key, a, b):
if key(a) == key(b):
return True
if p >= abs((key(a) - key(b)) / float(key(a))):
return True
return False
def cmp_percentage(p, key):
return lambda a, b: _cmp_percentage(p, key, a, b)
def translate_test(test):
name = take_first(test)
if "call_site_size.str" == name:
return 1000, "Call site size: string"
if "call_site_size.fmti" == name:
return 2000, "Call site size: 3 integers"
if "executable_size.m1" == name:
return 3000, "Executable size: 1 module"
if "compile_time" == name:
return 4000, "Module compile time"
if "link_time" == name:
return 5000, "Executable link time"
if "speed" == name:
threads = test[1]
mode = test[2]
mode_keys = ["str", "fmti", "str-off", "slowf-off"]
mode_vals = ["string", "3 integers", "string, off", "slow function, off"]
tr_mode = take_map(mode, mode_keys, mode_vals)
order = 10 * threads + take_order(mode, mode_keys)
return 6000 + order, "Speed: %i %s, %s" % (threads, take_plural(threads, "thread", "s"), tr_mode)
if type(test) is tuple or type(test) is list:
return 31416, ", ".join(test)
return 27183, test
def translate_subj(subj):
if "zf_log_n" == subj:
return 31416, "zf_log"
if "easylog" == subj:
return 31416, "Easylogging++"
return 31416, subj
def translation_sort_key(v):
return "[%04i] %s" % (v[0], v[1])
def translation_value(v):
return v[1]
class data_cell:
def __init__(self):
self.best = False
def set_best(self, best=True):
self.best = best
def ifbest(self, a, b):
if hasattr(self, "best") and self.best:
return a
return b
class data_str(data_cell):
def __init__(self, value):
if type(value) is not str:
raise RuntimeError("Not a string")
self.value = value
def __str__(self):
return self.value
def __repr__(self):
return repr(self.value)
class data_bytes(data_cell):
def __init__(self, value):
if type(value) is not int:
raise RuntimeError("Not an int")
self.value = value
def __str__(self):
if self.value < 1024:
return "%i B" % (self.value)
if self.value < 1024 * 1024:
return "%.2f KB" % (self.value / 1024.0)
return "%.2f MB" % (self.value / 1024.0 / 1024.0)
def __repr__(self):
return repr(self.value)
class data_seconds(data_cell):
def __init__(self, value):
if type(value) is not int and type(value) is not float:
raise RuntimeError("Not an int or float")
self.value = value
def __str__(self):
return "%.3f sec" % (self.value)
def __repr__(self):
return repr(self.value)
class data_freq(data_cell):
def __init__(self, count, seconds):
if type(count) is not int and type(count) is not float:
raise RuntimeError("Not an int or float")
if type(seconds) is not int and type(seconds) is not float:
raise RuntimeError("Not an int or float")
self.count = count
self.seconds = seconds
def __str__(self):
return "{:,}".format(self.count / self.seconds)
def __repr__(self):
return repr((self.count, self.seconds))
def freq(self):
return self.count / self.seconds
def get_table_data(result):
# collect all tests
tests = result.keys()
tests = sorted(tests, key=lambda x: translation_sort_key(translate_test(x)))
# collect all subjects
subjs = set()
for test in tests:
subjs.update(result[test].keys())
subjs = sorted(subjs, key=lambda x: translation_sort_key(translate_subj(x)))
# create table
rows = len(tests) + 1
cols = len(subjs) + 1
table = [[None for _ in range(cols)] for _ in range(rows)]
# put names and captions
for i in range(1, rows):
table[i][0] = data_str(translation_value(translate_test(tests[i - 1])))
for j in range(1, cols):
table[0][j] = data_str(translation_value(translate_subj(subjs[j - 1])))
# put data
for i in range(1, rows):
for j in range(1, cols):
test = tests[i - 1]
subj = subjs[j - 1]
if subj in result[test]:
table[i][j] = result[test][subj]
# gen cells content
for i in range(0, rows):
for j in range(0, cols):
value = table[i][j]
if value is None:
value = data_str("")
elif not isinstance(value, data_cell):
raise RuntimeError("Value \"%s\" is of unsupported type \"%s\"" % (value, type(value)))
table[i][j] = value
# find cols width
widths = [0 for _ in range(cols)]
for j in range(0, cols):
for i in range(0, rows):
s = str(table[i][j])
if widths[j] < len(s):
widths[j] = len(s)
return table, rows, cols, widths
def gen_table_ascii(result):
table, rows, cols, widths = get_table_data(result)
# apply cell format
margin_norm = (" ", " ")
margin_best = ("*", " ")
margins = max(map(len, margin_norm)) + max(map(len, margin_norm))
for i in range(1, rows):
table[i][0] = str(table[i][0]).ljust(widths[0]).join(margin_norm)
for j in range(0, cols):
table[0][j] = str(table[0][j]).center(widths[j]).join(margin_norm)
for i in range(1, rows):
for j in range(1, cols):
data = table[i][j]
margin = data.ifbest(margin_best, margin_norm)
table[i][j] = str(data).rjust(widths[j]).join(margin)
# draw chart
line = "+" + "-" * (sum(widths) + (margins + 1) * len(widths) - 1) + "+\n"
chart = line
for row in table:
chart += "|"
for cell in row:
chart += "%s|" % (cell)
chart += "\n" + line
return chart
def gen_table_markdown(result):
table, rows, cols, widths = get_table_data(result)
# apply cell format
margin_norm = (" ", " ")
margin_best = ("**", "**")
margins = max(map(len, margin_norm)) + max(map(len, margin_norm))
for i in range(1, rows):
table[i][0] = str(table[i][0]).ljust(widths[0]).join(margin_norm)
for j in range(0, cols):
table[0][j] = str(table[0][j]).center(widths[j]).join(margin_norm)
for i in range(1, rows):
for j in range(1, cols):
data = table[i][j]
margin = data.ifbest(margin_best, margin_norm)
table[i][j] = str(data).join(margin).rjust(widths[j] + margins)
# draw chart
chart = ""
if 0 == rows:
return chart
chart += "|"
for cell in table[0]:
chart += "%s|" % (cell)
chart += "\n"
chart += "| " + "-" * (margins + widths[0] - 2) + " |"
for i in range(1, cols):
chart += " " + "-" * (margins + widths[i] - 2) + ":|"
chart += "\n"
for i in range(1, rows):
chart += "|"
for j in range(0, cols):
chart += "%s|" % (table[i][j])
chart += "\n"
return chart
def run_call_site_size(params, result):
if type(result) is not dict:
raise RuntimeError("Not a dictionary")
id = "call_site_size"
params = params[id]
for mode in params:
name = "%s.%s" % (id, mode)
values = dict()
for subj in params[mode]:
data = params[mode][subj]
sz1 = os.path.getsize(data["1"])
sz2 = os.path.getsize(data["2"])
data = data_bytes(sz2 - sz1)
values[subj] = data
result[name] = values
for best in take_best(values.values(),
key=lambda x: x.value,
compare=cmp_percentage(0.0, key=lambda x: x.value)):
best.set_best()
def run_executable_size(params, result):
if type(result) is not dict:
raise RuntimeError("Not a dictionary")
id = "executable_size"
params = params[id]
for mode in params:
name = "%s.%s" % (id, mode)
values = dict()
for subj in params[mode]:
sz = os.path.getsize(params[mode][subj])
values[subj] = data_bytes(sz)
result[name] = values
for best in take_best(values.values(),
key=lambda x: x.value,
compare=cmp_percentage(0.0, key=lambda x: x.value)):
best.set_best()
def run_build_time(params, result, id, optional=False):
if type(result) is not dict:
raise RuntimeError("Not a dictionary")
if optional and id not in params:
return
params = params[id]
values = dict()
for subj in params:
with open(params[subj], "r") as f:
dt = json.load(f)["dt"]
values[subj] = data_seconds(dt)
result[id] = values
for best in take_best(values.values(),
key=lambda x: x.value,
compare=cmp_percentage(0.2, key=lambda x: x.value)):
best.set_best()
def run_speed(params, result, threads_variants, seconds=1):
if type(result) is not dict:
raise RuntimeError("Not a dictionary")
id = "speed"
params = params[id]
for threads in threads_variants:
for mode in params:
name = (id, threads, mode)
values = dict()
for subj in params[mode]:
path = params[mode][subj]
p = subprocess.Popen([path, str(threads), str(seconds)], stdout=subprocess.PIPE)
stdout, stderr = p.communicate()
values[subj] = data_freq(int(stdout), seconds)
result[name] = values
for best in take_best(values.values(),
key=lambda x: x.freq(), reverse=True,
compare=cmp_percentage(0.1, key=lambda x: x.freq())):
best.set_best()
def run_tests(params):
result = dict()
run_call_site_size(params, result)
run_executable_size(params, result)
run_build_time(params, result, "compile_time", optional=True)
run_build_time(params, result, "link_time", optional=True)
run_speed(params, result, take_threads_variants())
return result
def main(argv):
parser = argparse.ArgumentParser()
parser.add_argument("-t", "--text", metavar="PATH", default=None,
help="Text output file path")
parser.add_argument("-m", "--markdown", metavar="PATH", default=None,
help="Markdown output file path")
parser.add_argument("-p", "--parameter", metavar="VALUE", action="append", default=[],
help="Input parameter")
parser.add_argument("-b", "--build", metavar="TYPE",
help="Input parameter")
parser.add_argument("-v", "--verbose", action="store_true",
help="Verbose output")
args = parser.parse_args(argv[1:])
# process parameters
params = dict()
for p in args.parameter:
d = params
vs = p.split(":")
key = None
for i in range(len(vs)):
if i == len(vs) - 1:
d[key] = vs[i]
break
if key is not None:
d = d[key]
key = vs[i]
if key not in d:
d[key] = dict()
if args.verbose:
sys.stderr.write(pprint.pformat(params, indent=4))
sys.stderr.write("\n")
# run, run, run!
result = run_tests(params)
if args.verbose:
sys.stderr.write(pprint.pformat(result, indent=4))
sys.stderr.write("\n")
if args.text is not None:
with open(args.text, "w") as f:
table = gen_table_ascii(result)
f.write(table)
if args.markdown is not None:
with open(args.markdown, "w") as f:
table = gen_table_markdown(result)
f.write(table)
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))
================================================
FILE: tests/perf/test_executable_size.cpp
================================================
#include "test_switch.h"
int main(int argc, char *argv[])
{
(void)argc; (void)argv;
XLOG_INIT();
XLOG_STATEMENT();
#ifdef TEST_SEVERAL_STATEMENTS
XLOG_STATEMENT();
XLOG_STATEMENT();
XLOG_STATEMENT();
XLOG_STATEMENT();
XLOG_STATEMENT();
XLOG_STATEMENT();
#endif
#ifdef TEST_EXTRA_STATEMENT
XLOG_STATEMENT();
#endif
return 0;
}
================================================
FILE: tests/perf/test_speed.cpp
================================================
#include <cstdint>
#include <cinttypes>
#include <atomic>
#include <functional>
#include <memory>
#include <vector>
#include <string>
#include <thread>
#include <condition_variable>
#include "test_switch.h"
namespace
{
class thread_latch
{
public:
thread_latch(): _go(false), _halt(false) {}
void wait() const;
void release();
bool halted() const;
void halt();
private:
mutable std::mutex _m;
mutable std::condition_variable _cv;
bool _go;
std::atomic<bool> _halt;
};
void thread_latch::wait() const
{
std::unique_lock<std::mutex> lock(_m);
while (!_go)
{
_cv.wait(lock);
}
}
void thread_latch::release()
{
const std::lock_guard<std::mutex> lock(_m);
_go = true;
_cv.notify_all();
}
bool thread_latch::halted() const
{
return _halt;
}
void thread_latch::halt()
{
_halt = true;
}
class thread_group
{
public:
thread_group(const thread_latch &latch, const unsigned n);
void start(const std::function<void(void)> f);
uint64_t join();
private:
void run();
const thread_latch &_latch;
const unsigned _n;
std::atomic<uint64_t> _count;
std::function<void(void)> _f;
std::vector<std::thread> _ths;
};
thread_group::thread_group(const thread_latch &latch, const unsigned n):
_latch(latch), _n(n), _count(0)
{
}
void thread_group::start(const std::function<void(void)> f)
{
_f = std::move(f);
for (auto i = _n; 0 < i--;)
{
_ths.push_back(std::thread(&thread_group::run, this));
}
}
uint64_t thread_group::join()
{
for (auto &th : _ths)
{
th.join();
}
_ths.clear();
return _count;
}
void thread_group::run()
{
uint64_t count = 0;
while (!_latch.halted())
{
_f();
++count;
}
_count += count;
}
class bench
{
public:
bench() {}
void setup(const std::function<void(void)> f);
unsigned run(const unsigned n, const unsigned seconds);
private:
std::function<void(void)> _f;
};
void bench::setup(const std::function<void(void)> f)
{
_f = std::move(f);
}
unsigned bench::run(const unsigned n, const unsigned seconds)
{
thread_latch latch;
thread_group tg(latch, n);
tg.start(_f);
latch.release();
std::this_thread::sleep_for(std::chrono::seconds(seconds));
latch.halt();
return tg.join();
}
}
int main(int argc, char *argv[])
{
XLOG_INIT();
unsigned n = 1;
if (1 < argc)
{
n = std::stoi(argv[1]);
if (n <= 0 || 99 < n)
{
fprintf(stderr, "Bad thread count (%u).\n", n);
return -1;
}
}
unsigned seconds = 1;
if (2 < argc)
{
seconds = std::stoi(argv[2]);
if (seconds <= 0 || 60*60 < seconds)
{
fprintf(stderr, "Bad duration (%u).\n", seconds);
return -1;
}
}
bench b;
b.setup([](){
XLOG_STATEMENT();
});
const uint64_t k = b.run(n, seconds);
fprintf(stdout, "%" PRIu64 "\n", static_cast<uint64_t>(k));
return 0;
}
================================================
FILE: tests/perf/test_switch.h
================================================
#pragma once
#define TEST_LIBRARY_ID_zf_log 1
#define TEST_LIBRARY_ID_spdlog 2
#define TEST_LIBRARY_ID_easylog 3
#define TEST_LIBRARY_ID_g3log 4
#define TEST_LIBRARY_ID_glog 5
#define _CONCAT(a, b) a##b
#define CONCAT(a, b) _CONCAT(a, b)
#if TEST_LIBRARY_ID_zf_log == CONCAT(TEST_LIBRARY_ID_, TEST_LIBRARY)
#define TEST_LIBRARY_ZF_LOG
#elif TEST_LIBRARY_ID_spdlog == CONCAT(TEST_LIBRARY_ID_, TEST_LIBRARY)
#define TEST_LIBRARY_SPDLOG
#elif TEST_LIBRARY_ID_easylog == CONCAT(TEST_LIBRARY_ID_, TEST_LIBRARY)
#define TEST_LIBRARY_EASYLOG
#elif TEST_LIBRARY_ID_g3log == CONCAT(TEST_LIBRARY_ID_, TEST_LIBRARY)
#define TEST_LIBRARY_G3LOG
#elif TEST_LIBRARY_ID_glog == CONCAT(TEST_LIBRARY_ID_, TEST_LIBRARY)
#define TEST_LIBRARY_GLOG
#else
#error Unknown test library name
#endif
#define XLOG_STRING_LITERAL "A random string"
#define XLOG_INT_LITERAL 42
/* It's important that values are not const. Otherwise compilers will be able
* to optimize out things that we care about.
*/
extern const char *XLOG_STRING_VALUE;
extern int XLOG_INT_VALUE;
#ifndef TEST_SWITCH_MODULE
const char *XLOG_STRING_VALUE = XLOG_STRING_LITERAL;
int XLOG_INT_VALUE = XLOG_INT_LITERAL;
#endif
#ifdef TEST_FORMAT_SLOW_FUNC
#include <chrono>
#include <thread>
static int XLOG_SLOW_FUNC()
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
return (int)std::hash<std::thread::id>()(std::this_thread::get_id());
}
#endif
#define XLOG_MESSAGE_STR_LITERAL_PRINTF XLOG_STRING_LITERAL
#define XLOG_MESSAGE_STR_LITERAL_CPPFMT XLOG_STRING_LITERAL
#define XLOG_MESSAGE_STR_LITERAL_STREAM XLOG_STRING_LITERAL
#define XLOG_MESSAGE_3INT_VALUES_PRINTF \
"vA: %i, vB: %i, vC: %i", \
XLOG_INT_VALUE, XLOG_INT_VALUE, XLOG_INT_VALUE
#define XLOG_MESSAGE_3INT_VALUES_CPPFMT \
"vA: {}, vB: {}, vC: {}", \
XLOG_INT_VALUE, XLOG_INT_VALUE, XLOG_INT_VALUE
#define XLOG_MESSAGE_3INT_VALUES_STREAM \
"vA: " << XLOG_INT_VALUE << ", vB: " << XLOG_INT_VALUE << \
", vC: " << XLOG_INT_VALUE
#define XLOG_MESSAGE_SLOW_FUNC_PRINTF "%i", XLOG_SLOW_FUNC()
#define XLOG_MESSAGE_SLOW_FUNC_CPPFMT "{}", XLOG_SLOW_FUNC()
#define XLOG_MESSAGE_SLOW_FUNC_STREAM XLOG_SLOW_FUNC()
#ifdef TEST_LIBRARY_ZF_LOG
#include <zf_log.h>
#ifdef TEST_NULL_SINK
#define _XLOG_INIT_SINK() \
zf_log_set_output_v(ZF_LOG_PUT_STD, 0, \
[](const zf_log_message *, void *){})
#else
#define _XLOG_INIT_SINK()
#endif
#ifdef TEST_LOG_OFF
#define _XLOG_INIT_LEVEL() \
zf_log_set_output_level(ZF_LOG_ERROR)
#else
#define _XLOG_INIT_LEVEL()
#endif
static void XLOG_INIT()
{
_XLOG_INIT_SINK();
_XLOG_INIT_LEVEL();
}
#if defined(TEST_FORMAT_INTS)
#define XLOG_STATEMENT() ZF_LOGI(XLOG_MESSAGE_3INT_VALUES_PRINTF)
#elif defined(TEST_FORMAT_SLOW_FUNC)
#define XLOG_STATEMENT() ZF_LOGI(XLOG_MESSAGE_SLOW_FUNC_PRINTF)
#else
#define XLOG_STATEMENT() ZF_LOGI(XLOG_MESSAGE_STR_LITERAL_PRINTF)
#endif
#endif
#ifdef TEST_LIBRARY_SPDLOG
#include <spdlog/spdlog.h>
extern const std::shared_ptr<spdlog::logger> g_logger;
#ifdef TEST_NULL_SINK
class null_sink: public spdlog::sinks::sink
{
public:
void log(const spdlog::details::log_msg &) override {}
void flush() override {}
};
#ifndef TEST_SWITCH_MODULE
const std::shared_ptr<spdlog::logger> g_logger = spdlog::create<null_sink>("null");
#endif
#else
#ifndef TEST_SWITCH_MODULE
const std::shared_ptr<spdlog::logger> g_logger = spdlog::stderr_logger_st("stderr");
#endif
#endif
#ifdef TEST_LOG_OFF
#define _XLOG_INIT_LEVEL() spdlog::set_level(spdlog::level::err)
#else
#define _XLOG_INIT_LEVEL()
#endif
static void XLOG_INIT()
{
_XLOG_INIT_LEVEL();
}
#if defined(TEST_FORMAT_INTS)
#define XLOG_STATEMENT() g_logger->info(XLOG_MESSAGE_3INT_VALUES_CPPFMT)
#elif defined(TEST_FORMAT_SLOW_FUNC)
#define XLOG_STATEMENT() g_logger->info(XLOG_MESSAGE_SLOW_FUNC_CPPFMT)
#else
#define XLOG_STATEMENT() g_logger->info(XLOG_MESSAGE_STR_LITERAL_CPPFMT)
#endif
#endif
#ifdef TEST_LIBRARY_EASYLOG
#ifdef TEST_NULL_SINK
class null_stream {
public:
template<typename T>
null_stream &operator<<(T) { return *this; }
null_stream &operator<<(std::ostream& (*)(std::ostream&)) { return *this; }
};
extern null_stream g_null;
#ifndef TEST_SWITCH_MODULE
null_stream g_null;
#endif
#define ELPP_CUSTOM_COUT g_null
#define _XLOG_INIT_SINK() \
el::Loggers::reconfigureAllLoggers(el::ConfigurationType::ToFile, "false")
#else
#define _XLOG_INIT_SINK()
#endif
#ifdef TEST_LOG_OFF
#define _XLOG_INIT_LEVEL() \
el::Loggers::reconfigureAllLoggers(el::ConfigurationType::Enabled, "false")
#else
#define _XLOG_INIT_LEVEL()
#endif
#define ELPP_THREAD_SAFE
#include <easylogging++.h>
#ifndef TEST_SWITCH_MODULE
INITIALIZE_EASYLOGGINGPP
#endif
static void XLOG_INIT()
{
_XLOG_INIT_SINK();
_XLOG_INIT_LEVEL();
}
#if defined(TEST_FORMAT_INTS)
#define XLOG_STATEMENT() LOG(INFO) << XLOG_MESSAGE_3INT_VALUES_STREAM
#elif defined(TEST_FORMAT_SLOW_FUNC)
#define XLOG_STATEMENT() LOG(INFO) << XLOG_MESSAGE_SLOW_FUNC_STREAM
#else
#define XLOG_STATEMENT() LOG(INFO) << XLOG_MESSAGE_STR_LITERAL_STREAM
#endif
#endif
#ifdef TEST_LIBRARY_G3LOG
#include <g3log/g3log.hpp>
#include <g3log/logworker.hpp>
#ifdef TEST_NULL_SINK
class null_sink
{
public:
void log(const std::string) {}
};
#define _XLOG_INIT_SINK() \
auto worker = g3::LogWorker::createLogWorker(); \
g3::initializeLogging(worker.get()); \
worker->addSink(std::unique_ptr<null_sink>(new null_sink), &null_sink::log);
#else
#define _XLOG_INIT_SINK() \
auto worker = g3::LogWorker::createLogWorker(); \
g3::initializeLogging(worker.get()); \
worker->addDefaultLogger("g3log", "g3log.log");
#endif
#ifdef TEST_LOG_OFF
#ifndef G3_DYNAMIC_LOGGING
#error g3log must be built with G3_DYNAMIC_LOGGING defined
#endif
#define _XLOG_INIT_LEVEL() \
g3::only_change_at_initialization::setLogLevel(INFO, false)
#else
#define _XLOG_INIT_LEVEL()
#endif
static void XLOG_INIT()
{
_XLOG_INIT_SINK();
_XLOG_INIT_LEVEL();
}
#if defined(TEST_FORMAT_INTS)
#define XLOG_STATEMENT() LOGF(INFO, XLOG_MESSAGE_3INT_VALUES_PRINTF)
#elif defined(TEST_FORMAT_SLOW_FUNC)
#define XLOG_STATEMENT() LOGF(INFO, XLOG_MESSAGE_SLOW_FUNC_PRINTF)
#else
#define XLOG_STATEMENT() LOGF(INFO, XLOG_MESSAGE_STR_LITERAL_PRINTF)
#endif
#endif
#ifdef TEST_LIBRARY_GLOG
#include <glog/logging.h>
#ifdef TEST_NULL_SINK
class null_sink: public google::LogSink
{
public:
void send(google::LogSeverity, const char *, const char *, int,
const struct ::tm *, const char *, size_t) override {}
void WaitTillSent() override {}
};
extern null_sink g_sink;
#ifndef TEST_SWITCH_MODULE
null_sink g_sink;
#endif
#define _XLOG_LOG(lvl) LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&g_sink, lvl)
#else
#define _XLOG_LOG(lvl) LOG(lvl)
#endif
#ifdef TEST_LOG_OFF
#define _XLOG_INIT_LEVEL() FLAGS_minloglevel = google::ERROR
#else
#define _XLOG_INIT_LEVEL()
#endif
static void XLOG_INIT()
{
google::InitGoogleLogging("glog");
_XLOG_INIT_LEVEL();
}
#if defined(TEST_FORMAT_INTS)
#define XLOG_STATEMENT() _XLOG_LOG(INFO) << XLOG_MESSAGE_3INT_VALUES_STREAM
#elif defined(TEST_FORMAT_SLOW_FUNC)
#define XLOG_STATEMENT() _XLOG_LOG(INFO) << XLOG_MESSAGE_SLOW_FUNC_STREAM
#else
#define XLOG_STATEMENT() _XLOG_LOG(INFO) << XLOG_MESSAGE_STR_LITERAL_STREAM
#endif
#endif
================================================
FILE: tests/perf/time_it.py
================================================
#!/usr/bin/python
import sys
import time
import subprocess
import json
def usage(f, st):
f.write("Usage:\n")
f.write(" time_it.py file utility [argument ...]\n\n")
f.write("Writes running time of utility into file.\n")
return st
def main(argv):
if 3 > len(argv):
return usage(sys.stderr, -1)
t = time.time()
ret = subprocess.call(argv[2:])
t = time.time() - t
if 0 == ret:
with open(argv[1], "w") as f:
json.dump({"dt":t}, f)
return ret
if __name__ == "__main__":
sys.exit(main(sys.argv))
================================================
FILE: tests/test_aux_spec.c
================================================
#include <zf_log.c>
#include <zf_test.h>
static const zf_log_spec g_spec =
{
ZF_LOG_GLOBAL_FORMAT,
ZF_LOG_GLOBAL_OUTPUT
};
static void mock_output_callback(const zf_log_message *msg, void *arg)
{
(void)msg; (void)arg;
}
int main(int argc, char *argv[])
{
zf_log_set_output_v(ZF_LOG_PUT_STD, 0, mock_output_callback);
ZF_LOGI_AUX(&g_spec, "aux log, argc=%i", argc);
ZF_LOGI_MEM_AUX(&g_spec, argv, argc * sizeof(*argv), "aux log, argv pointers:");
return 0;
}
================================================
FILE: tests/test_builtin_output_facilities.c
================================================
#if defined(_WIN32) || defined(_WIN64)
#define ZF_LOG_USE_DEBUGSTRING
#endif
#if defined(__APPLE__) && defined(__MACH__)
#define ZF_LOG_USE_NSLOG
#endif
#if defined(__ANDROID__)
#define ZF_LOG_USE_ANDROID_LOG
#endif
#include <zf_log.c>
int main(int argc, char *argv[])
{
(void)argc; (void)argv;
/* Testing compilation only for now. */
return 0;
}
================================================
FILE: tests/test_call_site_size_censoring.c
================================================
#define ZF_LOG_LEVEL ZF_LOG_INFO
#include <zf_log.h>
#include <time.h>
#define LOG_SOME_ONCE \
ZF_LOG_SECRET(ZF_LOGI("Lorem ipsum dolor sit amet")); \
time(0); \
static void log_some()
{
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
}
int main(int argc, char *argv[])
{
(void)argc; (void)argv;
log_some();
return 0;
}
================================================
FILE: tests/test_call_site_size_conditional.c
================================================
#define ZF_LOG_LEVEL ZF_LOG_INFO
#include <zf_log.h>
#include <time.h>
#if TEST_CONDITION
#define CONDITION 1 < 2
#else
#define CONDITION 1 > 2
#endif
#define LOG_SOME_ONCE \
ZF_LOG_IF(CONDITION, ZF_LOGI("Lorem ipsum dolor sit amet")); \
time(0); \
static void log_some()
{
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
LOG_SOME_ONCE
}
int main(int argc, char *argv[])
{
(void)argc; (void)argv;
log_some();
return 0;
}
================================================
FILE: tests/test_call_site_size_fmt_args.c
================================================
#define ZF_LOG_LEVEL ZF_LOG_INFO
#include <zf_log.h>
#include <time.h>
int g_int1;
int g_int2;
char *g_str1;
char *g_str2;
void *g_p1;
void *g_p2;
static void log_some()
{
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
ZF_LOGI("%i-%i/%s-%s/%p-%p", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);
time(0);
}
int main(int argc, char *argv[])
{
(void)argc; (void)argv;
log_some();
return 0;
}
================================================
FILE: tests/test_call_site_size_msg_only.c
================================================
#define ZF_LOG_LEVEL ZF_LOG_INFO
#include <zf_log.h>
#include <time.h>
static void log_some()
{
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
ZF_LOGI("Lorem ipsum dolor sit amet");
time(0);
}
int main(int argc, char *argv[])
{
(void)argc; (void)argv;
log_some();
return 0;
}
================================================
FILE: tests/test_censoring.c
================================================
#include <zf_log.c>
#include <zf_test.h>
static unsigned g_logged = 0;
static void mock_output_callback(const zf_log_message *msg, void *arg)
{
(void)msg; (void)arg;
++g_logged;
}
static unsigned was_logged()
{
const unsigned logged = g_logged;
g_logged = 0;
return logged;
}
static void some_function_0()
{
++g_logged;
}
static void some_function_1(const unsigned d)
{
assert(0 < d);
g_logged += d;
}
#if TEST_LOG_SECRETS
#define EXPECTED_LINES(n) TEST_VERIFY_EQUAL(was_logged(), (n))
#else
#define EXPECTED_LINES(n) TEST_VERIFY_EQUAL(was_logged(), 0)
#endif
static void test_censoring()
{
const char name[] = "Orion";
const char address[] = "Space";
const char cipher[] = "Secret";
const zf_log_spec spec = {ZF_LOG_GLOBAL_FORMAT, ZF_LOG_GLOBAL_OUTPUT};
#if ZF_LOG_SECRETS
ZF_LOGI("Customer name: %s", name);
ZF_LOGI("Customer address: %s", address);
#endif
EXPECTED_LINES(2);
ZF_LOG_SECRET(ZF_LOGI("Customer name: %s", name));
EXPECTED_LINES(1);
ZF_LOG_SECRET(ZF_LOGI_MEM(cipher, sizeof(cipher), "Customer cipher:"));
EXPECTED_LINES(2);
ZF_LOG_SECRET(ZF_LOGI_AUX(&spec, "Customer address: %s", address));
EXPECTED_LINES(1);
ZF_LOG_SECRET(ZF_LOGI_MEM_AUX(&spec, cipher, sizeof(cipher), "Customer cipher:"));
EXPECTED_LINES(2);
ZF_LOG_SECRET(some_function_0());
EXPECTED_LINES(1);
ZF_LOG_SECRET(some_function_1(42));
EXPECTED_LINES(42);
ZF_LOGI("Must always log this");
TEST_VERIFY_EQUAL(was_logged(), 1);
}
int main(int argc, char *argv[])
{
zf_log_set_output_v(ZF_LOG_PUT_STD, 0, mock_output_callback);
TEST_RUNNER_CREATE(argc, argv);
TEST_EXECUTE(test_censoring());
return TEST_RUNNER_EXIT_CODE();
}
================================================
FILE: tests/test_compilation_cpp.cpp
================================================
#include <zf_log.c>
namespace
{
void mock_output_callback(const zf_log_message *, void *)
{
}
}
int main(int argc, char *argv[])
{
zf_log_set_output_v(ZF_LOG_PUT_STD, 0, mock_output_callback);
ZF_LOGI("log from cpp, argc=%i", argc);
ZF_LOGI_MEM(argv, argc * sizeof(*argv), "log from cpp, argv pointers:");
return 0;
}
================================================
FILE: tests/test_conditional.c
================================================
#include <zf_log.c>
#include <zf_test.h>
static unsigned g_logged = 0;
/* Keep it extern (non-static), so compiler has less chances to optimize access
* to this variable.
*/
unsigned g_forty_two = 42;
static void mock_output_callback(const zf_log_message *msg, void *arg)
{
(void)msg; (void)arg;
++g_logged;
}
static unsigned was_logged()
{
const unsigned logged = g_logged;
g_logged = 0;
return logged;
}
static unsigned forty_two()
{
return g_forty_two;
}
#define EXPECTED_LINES(n) TEST_VERIFY_EQUAL(was_logged(), (n))
static void test_conditional()
{
ZF_LOG_IF(1 < 2, ZF_LOGI("True"));
EXPECTED_LINES(1);
ZF_LOG_IF(2 < 1, ZF_LOGI("False"));
EXPECTED_LINES(0);
ZF_LOG_IF(g_forty_two == 42, ZF_LOGI("True"));
EXPECTED_LINES(1);
ZF_LOG_IF(g_forty_two != 42, ZF_LOGI("False"));
EXPECTED_LINES(0);
ZF_LOG_IF(g_forty_two == 42, ZF_LOGI("True"));
EXPECTED_LINES(1);
ZF_LOG_IF(g_forty_two != 42, ZF_LOGI("False"));
EXPECTED_LINES(0);
ZF_LOG_IF(forty_two() == 42, ZF_LOGI("True"));
EXPECTED_LINES(1);
ZF_LOG_IF(forty_two() != 42, ZF_LOGI("False"));
EXPECTED_LINES(0);
}
int main(int argc, char *argv[])
{
zf_log_set_output_v(ZF_LOG_PUT_STD, 0, mock_output_callback);
TEST_RUNNER_CREATE(argc, argv);
TEST_EXECUTE(test_conditional());
return TEST_RUNNER_EXIT_CODE();
}
================================================
FILE: tests/test_decoration.main.c
================================================
#define ZF_LOG_LEVEL ZF_LOG_INFO
#include <zf_log.c>
#include <stdlib.h>
#include <stdio.h>
static int main_called;
static void main_output_callback(const zf_log_message *msg, void *arg)
{
(void)arg;
if (strncmp("main", msg->msg_b, (size_t)(msg->p - msg->msg_b)))
{
fprintf(stderr, "incorrect message in main\n");
exit(1);
}
++main_called;
}
void test_module();
void test_main()
{
zf_log_set_output_v(ZF_LOG_PUT_STD, 0, main_output_callback);
ZF_LOGI("main");
if (!main_called)
{
fprintf(stderr, "main callback was not called\n");
exit(1);
}
}
int main(int argc, char *argv[])
{
(void)argc; (void)argv;
zf_log_set_output_v(ZF_LOG_PUT_STD, 0, main_output_callback);
test_module();
test_main();
return 0;
}
================================================
FILE: tests/test_decoration.module.c
================================================
#define ZF_LOG_LEVEL ZF_LOG_INFO
#define ZF_LOG_LIBRARY_PREFIX module
#include <zf_log.c>
#include <stdlib.h>
#include <stdio.h>
static int module_called;
static void module_output_callback(const zf_log_message *msg, void *arg)
{
(void)arg;
if (strncmp("module", msg->msg_b, (size_t)(msg->p - msg->msg_b)))
{
fprintf(stderr, "incorrect message in module\n");
exit(1);
}
++module_called;
}
void test_module()
{
zf_log_set_output_v(ZF_LOG_PUT_STD, 0, module_output_callback);
ZF_LOGI("module");
if (!module_called)
{
fprintf(stderr, "module callback was not called\n");
exit(1);
}
}
================================================
FILE: tests/test_externally_defined_state.c
================================================
#define ZF_LOG_EXTERN_TAG_PREFIX
#define ZF_LOG_EXTERN_GLOBAL_FORMAT
#define ZF_LOG_EXTERN_GLOBAL_OUTPUT
#define ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
#include <zf_log.c>
#include "zf_test.h"
enum { MEM_WIDTH = 8 };
static void mock_output_callback(const zf_log_message *msg, void *arg);
ZF_LOG_DEFINE_TAG_PREFIX = "MOCK_PREFIX";
ZF_LOG_DEFINE_GLOBAL_FORMAT =
{
0xc0defade
};
ZF_LOG_DEFINE_GLOBAL_OUTPUT =
{
0xcafebabe,
(void *)(ptrdiff_t)0xfafacaca,
mock_output_callback
};
ZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = 0xdeadbeef;
static void mock_output_callback(const zf_log_message *msg, void *arg)
{
(void)msg; (void)arg;
}
static void test_static_initialization()
{
TEST_VERIFY_TRUE(0 == strcmp(_zf_log_tag_prefix, "MOCK_PREFIX"));
TEST_VERIFY_EQUAL(_zf_log_global_format.mem_width, 0xc0defade);
TEST_VERIFY_EQUAL(_zf_log_global_output.mask, 0xcafebabe);
TEST_VERIFY_EQUAL(_zf_log_global_output.arg, (void *)(ptrdiff_t)0xfafacaca);
TEST_VERIFY_EQUAL(_zf_log_global_output.callback, mock_output_callback);
TEST_VERIFY_EQUAL(_zf_log_global_output_lvl, (int)0xdeadbeef);
TEST_VERIFY_EQUAL(ZF_LOG_GLOBAL_FORMAT, &_zf_log_global_format);
TEST_VERIFY_EQUAL(ZF_LOG_GLOBAL_OUTPUT, &_zf_log_global_output);
}
int main(int argc, char *argv[])
{
TEST_RUNNER_CREATE(argc, argv);
TEST_EXECUTE(test_static_initialization());
return TEST_RUNNER_EXIT_CODE();
}
================================================
FILE: tests/test_externally_defined_state_cpp.cpp
================================================
#define ZF_LOG_EXTERN_TAG_PREFIX
#define ZF_LOG_EXTERN_GLOBAL_FORMAT
#define ZF_LOG_EXTERN_GLOBAL_OUTPUT
#define ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
#include <zf_log.c>
ZF_LOG_DEFINE_TAG_PREFIX = "MAIN";
ZF_LOG_DEFINE_GLOBAL_FORMAT = {32};
ZF_LOG_DEFINE_GLOBAL_OUTPUT = {ZF_LOG_OUT_STDERR};
ZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = ZF_LOG_INFO;
namespace
{
void mock_output_callback(const zf_log_message *, void *)
{
}
}
int main(int argc, char *argv[])
{
zf_log_set_output_v(ZF_LOG_PUT_STD, 0, mock_output_callback);
ZF_LOGI("log from cpp, argc=%i", argc);
ZF_LOGI_MEM(argv, argc * sizeof(*argv), "log from cpp, argv pointers:");
return 0;
}
================================================
FILE: tests/test_log_level_override.c
================================================
#define ZF_LOG_LEVEL 0
#define ZF_LOG_OUTPUT_LEVEL g_output_level
#include <zf_log.c>
#include <zf_test.h>
static const int c_levels[] =
{
ZF_LOG_VERBOSE,
ZF_LOG_DEBUG,
ZF_LOG_INFO,
ZF_LOG_WARN,
ZF_LOG_ERROR,
ZF_LOG_FATAL,
ZF_LOG_NONE,
};
static int g_output_level = 0;
static void test_level_checks()
{
for (unsigned i = 0; _countof(c_levels) > i; ++i)
{
/* must not effect anything */
zf_log_set_output_level(c_levels[i]);
for (unsigned j = 0; _countof(c_levels) > j; ++j)
{
g_output_level = c_levels[j];
TEST_VERIFY_EQUAL(!!ZF_LOG_ON_VERBOSE, g_output_level <= ZF_LOG_VERBOSE);
TEST_VERIFY_EQUAL(!!ZF_LOG_ON_DEBUG, g_output_level <= ZF_LOG_DEBUG);
TEST_VERIFY_EQUAL(!!ZF_LOG_ON_INFO, g_output_level <= ZF_LOG_INFO);
TEST_VERIFY_EQUAL(!!ZF_LOG_ON_WARN, g_output_level <= ZF_LOG_WARN);
TEST_VERIFY_EQUAL(!!ZF_LOG_ON_ERROR, g_output_level <= ZF_LOG_ERROR);
TEST_VERIFY_EQUAL(!!ZF_LOG_ON_FATAL, g_output_level <= ZF_LOG_FATAL);
}
}
}
int main(int argc, char *argv[])
{
TEST_RUNNER_CREATE(argc, argv);
TEST_EXECUTE(test_level_checks());
return TEST_RUNNER_EXIT_CODE();
}
================================================
FILE: tests/test_log_level_switches.c
================================================
#ifndef ZF_LOG_LEVEL
#error ZF_LOG_LEVEL must be defined for this test
#endif
#include <zf_log.c>
#include <zf_test.h>
#include <string.h>
#include <stdbool.h>
static int g_output_lvl_used;
static unsigned g_output_called;
static unsigned g_arg_called;
static char g_msg[1024];
static unsigned g_msg_len;
static const int c_levels[] =
{
ZF_LOG_VERBOSE,
ZF_LOG_DEBUG,
ZF_LOG_INFO,
ZF_LOG_WARN,
ZF_LOG_ERROR,
ZF_LOG_FATAL,
ZF_LOG_NONE,
};
static void reset()
{
g_output_called = 0;
g_arg_called = 0;
zf_log_set_output_level(0);
}
static void mock_output_callback(const zf_log_message *msg, void *arg)
{
(void)arg;
g_output_lvl_used = msg->lvl;
g_msg_len = (unsigned)(msg->p - msg->buf);
memcpy(g_msg, msg->buf, g_msg_len);
++g_output_called;
}
static int get_arg()
{
++g_arg_called;
return 0;
}
static void test_current_level()
{
reset();
ZF_LOGV("verbose log");
TEST_VERIFY_EQUAL(1 == g_output_called, ZF_LOG_LEVEL <= ZF_LOG_VERBOSE);
TEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_VERBOSE == g_output_lvl_used);
reset();
ZF_LOGD("debug log");
TEST_VERIFY_EQUAL(1 == g_output_called, ZF_LOG_LEVEL <= ZF_LOG_DEBUG);
TEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_DEBUG == g_output_lvl_used);
reset();
ZF_LOGI("info log");
TEST_VERIFY_EQUAL(1 == g_output_called, ZF_LOG_LEVEL <= ZF_LOG_INFO);
TEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_INFO == g_output_lvl_used);
reset();
ZF_LOGW("warning log");
TEST_VERIFY_EQUAL(1 == g_output_called, ZF_LOG_LEVEL <= ZF_LOG_WARN);
TEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_WARN == g_output_lvl_used);
reset();
ZF_LOGE("error log");
TEST_VERIFY_EQUAL(1 == g_output_called, ZF_LOG_LEVEL <= ZF_LOG_ERROR);
TEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_ERROR == g_output_lvl_used);
reset();
ZF_LOGF("fatal log");
TEST_VERIFY_EQUAL(1 == g_output_called, ZF_LOG_LEVEL <= ZF_LOG_FATAL);
TEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_FATAL == g_output_lvl_used);
}
static void test_output_level()
{
for (unsigned i = 0; _countof(c_levels) > i; ++i)
{
const int lvl = c_levels[i];
reset();
zf_log_set_output_level(lvl);
ZF_LOGV("verbose log");
TEST_VERIFY_EQUAL(1 == g_output_called,
ZF_LOG_LEVEL <= ZF_LOG_VERBOSE && lvl <= ZF_LOG_VERBOSE);
TEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_VERBOSE == g_output_lvl_used);
reset();
zf_log_set_output_level(lvl);
ZF_LOGD("debug log");
TEST_VERIFY_EQUAL(1 == g_output_called,
ZF_LOG_LEVEL <= ZF_LOG_DEBUG && lvl <= ZF_LOG_DEBUG);
TEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_DEBUG == g_output_lvl_used);
reset();
zf_log_set_output_level(lvl);
ZF_LOGI("info log");
TEST_VERIFY_EQUAL(1 == g_output_called,
ZF_LOG_LEVEL <= ZF_LOG_INFO && lvl <= ZF_LOG_INFO);
TEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_INFO == g_output_lvl_used);
reset();
zf_log_set_output_level(lvl);
ZF_LOGW("warn log");
TEST_VERIFY_EQUAL(1 == g_output_called,
ZF_LOG_LEVEL <= ZF_LOG_WARN && lvl <= ZF_LOG_WARN);
TEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_WARN == g_output_lvl_used);
reset();
zf_log_set_output_level(lvl);
ZF_LOGE("error log");
TEST_VERIFY_EQUAL(1 == g_output_called,
ZF_LOG_LEVEL <= ZF_LOG_ERROR && lvl <= ZF_LOG_ERROR);
TEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_ERROR == g_output_lvl_used);
reset();
zf_log_set_output_level(lvl);
ZF_LOGF("fatal log");
TEST_VERIFY_EQUAL(1 == g_output_called,
ZF_LOG_LEVEL <= ZF_LOG_FATAL && lvl <= ZF_LOG_FATAL);
TEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_FATAL == g_output_lvl_used);
}
}
static void test_args_evaluation()
{
reset();
ZF_LOGV("verbose log: %i", get_arg());
TEST_VERIFY_EQUAL(1 == g_arg_called, ZF_LOG_LEVEL <= ZF_LOG_VERBOSE);
reset();
ZF_LOGD("debug log: %i", get_arg());
TEST_VERIFY_EQUAL(1 == g_arg_called, ZF_LOG_LEVEL <= ZF_LOG_DEBUG);
reset();
ZF_LOGI("info log: %i", get_arg());
TEST_VERIFY_EQUAL(1 == g_arg_called, ZF_LOG_LEVEL <= ZF_LOG_INFO);
reset();
ZF_LOGW("warning log: %i", get_arg());
TEST_VERIFY_EQUAL(1 == g_arg_called, ZF_LOG_LEVEL <= ZF_LOG_WARN);
reset();
ZF_LOGE("error log: %i", get_arg());
TEST_VERIFY_EQUAL(1 == g_arg_called, ZF_LOG_LEVEL <= ZF_LOG_ERROR);
reset();
ZF_LOGF("fatal log: %i", get_arg());
TEST_VERIFY_EQUAL(1 == g_arg_called, ZF_LOG_LEVEL <= ZF_LOG_FATAL);
for (unsigned i = 0; _countof(c_levels) > i; ++i)
{
const int lvl = c_levels[i];
reset();
zf_log_set_output_level(lvl);
ZF_LOGV("verbose log: %i", get_arg());
TEST_VERIFY_EQUAL(1 == g_arg_called,
ZF_LOG_LEVEL <= ZF_LOG_VERBOSE && lvl <= ZF_LOG_VERBOSE);
reset();
zf_log_set_output_level(lvl);
ZF_LOGD("debug log: %i", get_arg());
TEST_VERIFY_EQUAL(1 == g_arg_called,
ZF_LOG_LEVEL <= ZF_LOG_DEBUG && lvl <= ZF_LOG_DEBUG);
reset();
zf_log_set_output_level(lvl);
ZF_LOGI("info log: %i", get_arg());
TEST_VERIFY_EQUAL(1 == g_arg_called,
ZF_LOG_LEVEL <= ZF_LOG_INFO && lvl <= ZF_LOG_INFO);
reset();
zf_log_set_output_level(lvl);
ZF_LOGW("warn log: %i", get_arg());
TEST_VERIFY_EQUAL(1 == g_arg_called,
ZF_LOG_LEVEL <= ZF_LOG_WARN && lvl <= ZF_LOG_WARN);
reset();
zf_log_set_output_level(lvl);
ZF_LOGE("error log: %i", get_arg());
TEST_VERIFY_EQUAL(1 == g_arg_called,
ZF_LOG_LEVEL <= ZF_LOG_ERROR && lvl <= ZF_LOG_ERROR);
reset();
zf_log_set_output_level(lvl);
ZF_LOGF("fatal log: %i", get_arg());
TEST_VERIFY_EQUAL(1 == g_arg_called,
ZF_LOG_LEVEL <= ZF_LOG_FATAL && lvl <= ZF_LOG_FATAL);
}
}
static void test_level_checks()
{
reset();
TEST_VERIFY_EQUAL(!!ZF_LOG_ENABLED_VERBOSE, ZF_LOG_LEVEL <= ZF_LOG_VERBOSE);
TEST_VERIFY_EQUAL(!!ZF_LOG_ENABLED_DEBUG, ZF_LOG_LEVEL <= ZF_LOG_DEBUG);
TEST_VERIFY_EQUAL(!!ZF_LOG_ENABLED_INFO, ZF_LOG_LEVEL <= ZF_LOG_INFO);
TEST_VERIFY_EQUAL(!!ZF_LOG_ENABLED_WARN, ZF_LOG_LEVEL <= ZF_LOG_WARN);
TEST_VERIFY_EQUAL(!!ZF_LOG_ENABLED_ERROR, ZF_LOG_LEVEL <= ZF_LOG_ERROR);
TEST_VERIFY_EQUAL(!!ZF_LOG_ENABLED_FATAL, ZF_LOG_LEVEL <= ZF_LOG_FATAL);
for (unsigned i = 0; _countof(c_levels) > i; ++i)
{
const int lvl = c_levels[i];
reset();
zf_log_set_output_level(lvl);
TEST_VERIFY_EQUAL(!!ZF_LOG_ON_VERBOSE,
ZF_LOG_LEVEL <= ZF_LOG_VERBOSE && lvl <= ZF_LOG_VERBOSE);
TEST_VERIFY_EQUAL(!!ZF_LOG_ON_DEBUG,
ZF_LOG_LEVEL <= ZF_LOG_DEBUG && lvl <= ZF_LOG_DEBUG);
TEST_VERIFY_EQUAL(!!ZF_LOG_ON_INFO,
ZF_LOG_LEVEL <= ZF_LOG_INFO && lvl <= ZF_LOG_INFO);
TEST_VERIFY_EQUAL(!!ZF_LOG_ON_WARN,
ZF_LOG_LEVEL <= ZF_LOG_WARN && lvl <= ZF_LOG_WARN);
TEST_VERIFY_EQUAL(!!ZF_LOG_ON_ERROR,
ZF_LOG_LEVEL <= ZF_LOG_ERROR && lvl <= ZF_LOG_ERROR);
TEST_VERIFY_EQUAL(!!ZF_LOG_ON_FATAL,
ZF_LOG_LEVEL <= ZF_LOG_FATAL && lvl <= ZF_LOG_FATAL);
}
}
int main(int argc, char *argv[])
{
zf_log_set_output_v(ZF_LOG_PUT_STD, 0, mock_output_callback);
TEST_RUNNER_CREATE(argc, argv);
TEST_EXECUTE(test_current_level());
TEST_EXECUTE(test_output_level());
TEST_EXECUTE(test_args_evaluation());
TEST_EXECUTE(test_level_checks());
return TEST_RUNNER_EXIT_CODE();
}
================================================
FILE: tests/test_log_message_content.c
================================================
#if defined(_WIN32) || defined(_WIN64)
#define _CRT_NONSTDC_NO_WARNINGS
#endif
#define ZF_LOG_ANDROID_LOG 0
#define ZF_LOG_BUF_SZ 128
#define ZF_LOG_MEM_WIDTH 16
#define ZF_LOG_INSTRUMENTED 1
#define ZF_LOG_LEVEL ZF_LOG_INFO
#define ZF_LOG_TAG "TAG"
#include <zf_log.c>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(snprintf)
#define snprintf(buf, len, ...) _snprintf_s(buf, len, _TRUNCATE, __VA_ARGS__)
#endif
#define MESSAGE_EXPECTED_PRINTF_FMT__ ""
#define MESSAGE_EXPECTED_PRINTF_FMT__YEAR "2016"
#define MESSAGE_EXPECTED_PRINTF_FMT__MONTH "12"
#define MESSAGE_EXPECTED_PRINTF_FMT__DAY "23"
#define MESSAGE_EXPECTED_PRINTF_FMT__HOUR "12"
#define MESSAGE_EXPECTED_PRINTF_FMT__MINUTE "34"
#define MESSAGE_EXPECTED_PRINTF_FMT__SECOND "56"
#define MESSAGE_EXPECTED_PRINTF_FMT__MILLISECOND "789"
#define MESSAGE_EXPECTED_PRINTF_FMT__PID " 9876"
#define MESSAGE_EXPECTED_PRINTF_FMT__TID " 5432"
#define MESSAGE_EXPECTED_PRINTF_FMT__LEVEL "I"
#define MESSAGE_EXPECTED_PRINTF_FMT__TAG(ps, ts) "prefix" ps "TAG" ts
#define MESSAGE_EXPECTED_PRINTF_FMT__FUNCTION "function"
#define MESSAGE_EXPECTED_PRINTF_FMT__FILENAME "file"
#define MESSAGE_EXPECTED_PRINTF_FMT__FILELINE "42"
#define MESSAGE_EXPECTED_PRINTF_FMT__S(s) s
#define MESSAGE_EXPECTED_PRINTF_FMT__F_INIT(expr) ""
#define MESSAGE_EXPECTED_PRINTF_FMT__F_UINT(w, v) "%" #w "u"
#define MESSAGE_EXPECTED_PRINTF_FMT(field) \
_PP_CONCAT_3(MESSAGE_EXPECTED_PRINTF_FMT_, _, field)
#define MESSAGE_EXPECTED_PRINTF_VAL__
#define MESSAGE_EXPECTED_PRINTF_VAL__YEAR
#define MESSAGE_EXPECTED_PRINTF_VAL__MONTH
#define MESSAGE_EXPECTED_PRINTF_VAL__DAY
#define MESSAGE_EXPECTED_PRINTF_VAL__HOUR
#define MESSAGE_EXPECTED_PRINTF_VAL__MINUTE
#define MESSAGE_EXPECTED_PRINTF_VAL__SECOND
#define MESSAGE_EXPECTED_PRINTF_VAL__MILLISECOND
#define MESSAGE_EXPECTED_PRINTF_VAL__PID
#define MESSAGE_EXPECTED_PRINTF_VAL__TID
#define MESSAGE_EXPECTED_PRINTF_VAL__LEVEL
#define MESSAGE_EXPECTED_PRINTF_VAL__TAG(ps, ts)
#define MESSAGE_EXPECTED_PRINTF_VAL__FUNCTION
#define MESSAGE_EXPECTED_PRINTF_VAL__FILENAME
#define MESSAGE_EXPECTED_PRINTF_VAL__FILELINE
#define MESSAGE_EXPECTED_PRINTF_VAL__S(s)
#define MESSAGE_EXPECTED_PRINTF_VAL__F_INIT(expr)
#define MESSAGE_EXPECTED_PRINTF_VAL__F_UINT(w, v) ,v
#define MESSAGE_EXPECTED_PRINTF_VAL(field) \
_PP_CONCAT_3(MESSAGE_EXPECTED_PRINTF_VAL_, _, field)
#define MESSAGE_EXPECTED_PRINTF_FMTS \
_PP_MAP(MESSAGE_EXPECTED_PRINTF_FMT, ZF_LOG_MESSAGE_CTX_FORMAT) \
_PP_MAP(MESSAGE_EXPECTED_PRINTF_FMT, ZF_LOG_MESSAGE_TAG_FORMAT) \
_PP_MAP(MESSAGE_EXPECTED_PRINTF_FMT, ZF_LOG_MESSAGE_SRC_FORMAT)
#define MESSAGE_EXPECTED_PRINTF_VALS \
_PP_MAP(MESSAGE_EXPECTED_PRINTF_VAL, ZF_LOG_MESSAGE_CTX_FORMAT) \
_PP_MAP(MESSAGE_EXPECTED_PRINTF_VAL, ZF_LOG_MESSAGE_TAG_FORMAT) \
_PP_MAP(MESSAGE_EXPECTED_PRINTF_VAL, ZF_LOG_MESSAGE_SRC_FORMAT)
static const char c_test_fmt[] =
"Lorem ipsum dolor sit amet.";
static const char c_test_mem[] =
"Here's to the crazy ones.";
static const char *c_msg_expected_lines[1];
static const char *c_mem_expected_lines[3];
#define MAX_LINES 4
static char g_lines[MAX_LINES][ZF_LOG_BUF_SZ];
static size_t g_len[MAX_LINES];
static size_t g_null_pos[MAX_LINES];
static size_t g_line;
static size_t memchk(const void *const b, const int c, const size_t sz)
{
const unsigned char v = (unsigned char)c;
const unsigned char *const s = (const unsigned char *)b;
const unsigned char *const e = s + sz;
const unsigned char *p = s;
for (;p != e && v == *p; ++p) {}
return (size_t)(p - s);
}
static size_t common_prefix(const char *const s1, const size_t s1_len,
const char *const s2, const size_t s2_len)
{
const char *const e1 = s1 + s1_len;
const char *const e2 = s2 + s2_len;
const char *c1 = s1, *c2 = s2;
for (;e1 != c1 && e2 != c2 && *c1 == *c2; ++c1, ++c2) {}
return (size_t)(c1 - s1);
}
static void reset()
{
g_buf_sz = ZF_LOG_BUF_SZ;
for (size_t i = 0; MAX_LINES > i; ++i)
{
memset(g_lines[i], -1, ZF_LOG_BUF_SZ);
g_len[i] = 0;
g_null_pos[i] = 0;
}
g_line = 0;
}
static void mock_time_callback(struct tm *const tm, unsigned *const msec)
{
memset(tm, 0, sizeof(*tm));
tm->tm_sec = 56;
tm->tm_min = 34;
tm->tm_hour = 12;
tm->tm_mday = 23;
tm->tm_mon = 11;
tm->tm_year = 2016 - 1900;
*msec = 789;
}
static void mock_pid_callback(int *const pid, int *const tid)
{
*pid = 9876;
*tid = 5432;
}
static void mock_buffer_callback(zf_log_message *msg, char *buf)
{
memset(buf, -1, ZF_LOG_BUF_SZ);
buffer_callback(msg, buf);
}
static void mock_output_callback(const zf_log_message *msg, void *arg)
{
(void)arg;
const size_t i = g_line++;
if (MAX_LINES <= i)
{
fprintf(stderr, "too many lines produced\n");
exit(1);
}
char *const line = g_lines[i];
memcpy(line, msg->buf, ZF_LOG_BUF_SZ);
const size_t len = (size_t)(msg->p - msg->buf);
size_t null_pos;
for (null_pos = 0; len > null_pos && 0 != line[null_pos]; ++null_pos) {}
g_len[i] = len;
g_null_pos[i] = null_pos;
}
static void verify_log_output(const size_t buf_sz,
const char *const expected[],
const size_t expected_n)
{
const size_t modifiable = buf_sz + 1;
const size_t unmodifiable = ZF_LOG_BUF_SZ - modifiable;
if (g_line > expected_n)
{
fprintf(stderr, "Lines produced: actual=%u, expected=<%u\n",
(unsigned)g_line, (unsigned)expected_n);
exit(1);
}
size_t complete_lines = 0;
for (size_t i = 0; g_line > i; ++i)
{
const char *const line = g_lines[i];
const size_t line_len = strlen(expected[i]);
const size_t untouched = memchk(line + modifiable, -1, unmodifiable);
const size_t match = common_prefix(expected[i], line_len,
line, g_len[i]);
if (untouched != unmodifiable)
{
fprintf(stderr, "Untouched bytes: actual=%u, expected=%u\n",
(unsigned)untouched, (unsigned)unmodifiable);
exit(1);
}
if (g_null_pos[i] != g_len[i])
{
fprintf(stderr, "Null position: actual=%u, expected=%u\n",
(unsigned)g_null_pos[i], (unsigned)g_len[i]);
exit(1);
}
if (match < g_len[i])
{
fprintf(stderr, "Line partial match: actual=%u, expected=>%u\n",
(unsigned)match, (unsigned)g_len[i]);
exit(1);
}
if (line_len <= buf_sz)
{
++complete_lines;
if (line_len <= buf_sz && match != g_len[i])
{
fprintf(stderr, "Line complete match: actual=%u, expected=%u\n",
(unsigned)match, (unsigned)g_len[i]);
exit(1);
}
}
}
if (expected_n == complete_lines && g_line != expected_n)
{
fprintf(stderr, "Complete lines produced: actual=%u, expected=<%u\n",
(unsigned)g_line, (unsigned)expected_n);
exit(1);
}
}
static void test_msg_output()
{
for (unsigned buf_sz = 0; ZF_LOG_BUF_SZ - ZF_LOG_EOL_SZ >= buf_sz; ++buf_sz)
{
reset();
g_buf_sz = buf_sz;
_zf_log_write_d("function", "file", 42, ZF_LOG_INFO, ZF_LOG_TAG,
c_test_fmt);
verify_log_output(buf_sz,
c_msg_expected_lines, _countof(c_msg_expected_lines));
}
}
static void test_mem_output()
{
for (unsigned buf_sz = 0; ZF_LOG_BUF_SZ - ZF_LOG_EOL_SZ >= buf_sz; ++buf_sz)
{
reset();
g_buf_sz = buf_sz;
_zf_log_write_mem_d("function", "file", 42, ZF_LOG_INFO, ZF_LOG_TAG,
c_test_mem, sizeof(c_test_mem),
c_test_fmt);
verify_log_output(buf_sz,
c_mem_expected_lines, _countof(c_mem_expected_lines));
}
}
static void init_expected_lines()
{
char expected_header[256];
char line[512];
_PP_MAP(_ZF_LOG_MESSAGE_FORMAT_INIT, ZF_LOG_MESSAGE_CTX_FORMAT)
_PP_MAP(_ZF_LOG_MESSAGE_FORMAT_INIT, ZF_LOG_MESSAGE_TAG_FORMAT)
_PP_MAP(_ZF_LOG_MESSAGE_FORMAT_INIT, ZF_LOG_MESSAGE_SRC_FORMAT)
#if _ZF_LOG_MESSAGE_FORMAT_FIELDS(ZF_LOG_MESSAGE_CTX_FORMAT) || \
_ZF_LOG_MESSAGE_FORMAT_FIELDS(ZF_LOG_MESSAGE_TAG_FORMAT) || \
_ZF_LOG_MESSAGE_FORMAT_FIELDS(ZF_LOG_MESSAGE_SRC_FORMAT)
snprintf(expected_header, sizeof(expected_header),
MESSAGE_EXPECTED_PRINTF_FMTS
MESSAGE_EXPECTED_PRINTF_VALS);
#else
*expected_header ='\0';
#endif
snprintf(line, sizeof(line), "%s%s", expected_header,
"Lorem ipsum dolor sit amet.");
c_msg_expected_lines[0] = strdup(line);
snprintf(line, sizeof(line), "%s%s", expected_header,
"Lorem ipsum dolor sit amet.");
c_mem_expected_lines[0] = strdup(line);
snprintf(line, sizeof(line), "%s%s", expected_header,
"48657265277320746f20746865206372 Here's to the cr");
c_mem_expected_lines[1] = strdup(line);
snprintf(line, sizeof(line), "%s%s", expected_header,
"617a79206f6e65732e00 azy ones.?");
c_mem_expected_lines[2] = strdup(line);
}
int main(int argc, char *argv[])
{
(void)argc; (void)argv;
g_time_cb = mock_time_callback;
g_pid_cb = mock_pid_callback;
g_buffer_cb = mock_buffer_callback;
zf_log_set_output_v(ZF_LOG_PUT_STD, 0, mock_output_callback);
zf_log_set_tag_prefix("prefix");
init_expected_lines();
test_msg_output();
test_mem_output();
return 0;
}
================================================
FILE: tests/test_private_parts.c
================================================
#include <zf_log.c>
#include <zf_test.h>
static char *strcopy_r(const char *s, char *e)
{
e -= strlen(s) + 1;
for (char *p = e; 0 != (*p++ = *s++);) {}
return e;
}
typedef struct put_padding_r_testcase
{
const char *const s;
const unsigned w;
const char *const p;
}
put_padding_r_testcase;
static const put_padding_r_testcase g_put_padding_r_testcases[] =
{
{"", 0, ""},
{"1", 0, "1"},
{"123", 0, "123"},
{"", 3, "---"},
{"1", 3, "--1"},
{"123", 3, "123"},
{"1234", 3, "1234"},
};
static void test_put_padding_r()
{
char buf[16];
char *const e = buf + _countof(buf) - 1;
char *p;
for (unsigned i = 0; _countof(g_put_padding_r_testcases) > i; ++i)
{
const put_padding_r_testcase *const tc = g_put_padding_r_testcases + i;
p = strcopy_r(tc->s, e + 1);
p = put_padding_r(tc->w, '-', p, e);
TEST_VERIFY_TRUE_MSG(0 == strcmp(p, tc->p), "i=%u", i);
}
}
int main(int argc, char *argv[])
{
TEST_RUNNER_CREATE(argc, argv);
TEST_EXECUTE(test_put_padding_r());
return TEST_RUNNER_EXIT_CODE();
}
================================================
FILE: tests/test_source_location.c
================================================
#include <zf_log.c>
#include <zf_test.h>
#include <stdio.h>
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(snprintf)
#define snprintf(buf, len, ...) _snprintf_s(buf, len, _TRUNCATE, __VA_ARGS__)
#endif
const char *const c_filename = "test_source_location.c";
static char g_srcloc_buf[ZF_LOG_BUF_SZ];
static const char *g_srcloc;
static char *trim(char *s)
{
char *sb;
while (0 != *(sb = s) && ' ' == *s) ++s;
char *se;
while (0 != *(se = s) && ' ' != *s) ++s;
*se = 0;
return sb;
}
static void mock_output_callback(const zf_log_message *msg, void *arg)
{
(void)arg;
const size_t len = msg->msg_b - msg->tag_e;
memcpy(g_srcloc_buf, msg->tag_e, len);
g_srcloc_buf[len] = 0;
g_srcloc = trim(g_srcloc_buf);
}
static void test_function()
{
const unsigned line = __LINE__ + 1;
ZF_LOGI("test message");
char expected[64];
#if ZF_LOG_SRCLOC_NONE==TEST_SRCLOC
(void)line;
*expected = 0;
#endif
#if ZF_LOG_SRCLOC_SHORT==TEST_SRCLOC
snprintf(expected, sizeof(expected), "@%s:%u",
c_filename, line);
#endif
#if ZF_LOG_SRCLOC_LONG==TEST_SRCLOC
snprintf(expected, sizeof(expected), "%s@%s:%u",
_ZF_LOG_FUNCTION, c_filename, line);
#endif
TEST_VERIFY_EQUAL(strcmp(expected, g_srcloc), 0);
}
int main(int argc, char *argv[])
{
zf_log_set_output_v(ZF_LOG_PUT_STD, 0, mock_output_callback);
TEST_RUNNER_CREATE(argc, argv);
TEST_EXECUTE(test_function());
return TEST_RUNNER_EXIT_CODE();
}
================================================
FILE: tests/zf_log.h.master
================================================
#pragma once
#ifndef _ZF_LOG_H_
#define _ZF_LOG_H_
/* To detect incompatible changes you can define ZF_LOG_VERSION_REQUIRED to be
* the current value of ZF_LOG_VERSION before including this file (or via
* compiler command line):
*
* #define ZF_LOG_VERSION_REQUIRED 4
* #include <zf_log.h>
*
* Compilation will fail when included file has different version.
*/
#define ZF_LOG_VERSION 4
#if defined(ZF_LOG_VERSION_REQUIRED)
#if ZF_LOG_VERSION_REQUIRED != ZF_LOG_VERSION
#error different zf_log version required
#endif
#endif
/* Log level guideline:
* - ZF_LOG_FATAL - happened something impossible and absolutely unexpected.
* Process can't continue and must be terminated.
* Example: division by zero, unexpected modifications from other thread.
* - ZF_LOG_ERROR - happened something possible, but highly unexpected. The
* process is able to recover and continue execution.
* Example: out of memory (could also be FATAL if not handled properly).
* - ZF_LOG_WARN - happened something that *usually* should not happen and
* significantly changes application behavior for some period of time.
* Example: configuration file not found, auth error.
* - ZF_LOG_INFO - happened significant life cycle event or major state
* transition.
* Example: app started, user logged in.
* - ZF_LOG_DEBUG - minimal set of events that could help to reconstruct the
* execution path. Usually disabled in release builds.
* - ZF_LOG_VERBOSE - all other events. Usually disabled in release builds.
*
* *Ideally*, log file of debugged, well tested, production ready application
* should be empty or very small. Choosing a right log level is as important as
* providing short and self descriptive log message.
*/
#define ZF_LOG_VERBOSE 1
#define ZF_LOG_DEBUG 2
#define ZF_LOG_INFO 3
#define ZF_LOG_WARN 4
#define ZF_LOG_ERROR 5
#define ZF_LOG_FATAL 6
#define ZF_LOG_NONE 0xFF
/* "Current" log level is a compile time check and has no runtime overhead. Log
* level that is below current log level it said to be "disabled". Otherwise,
* it's "enabled". Log messages that are disabled has no runtime overhead - they
* are converted to no-op by preprocessor and then eliminated by compiler.
* Current log level is configured per compilation module (.c/.cpp/.m file) by
* defining ZF_LOG_DEF_LEVEL or ZF_LOG_LEVEL. ZF_LOG_LEVEL has higer priority
* and when defined overrides value provided by ZF_LOG_DEF_LEVEL.
*
* Common practice is to define default current log level with ZF_LOG_DEF_LEVEL
* in build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire
* project or target:
*
* CC_ARGS := -DZF_LOG_DEF_LEVEL=ZF_LOG_INFO
*
* And when necessary to override it with ZF_LOG_LEVEL in .c/.cpp/.m files
* before including zf_log.h:
*
* #define ZF_LOG_LEVEL ZF_LOG_VERBOSE
* #include <zf_log.h>
*
* If both ZF_LOG_DEF_LEVEL and ZF_LOG_LEVEL are undefined, then ZF_LOG_INFO
* will be used for release builds (NDEBUG is defined) and ZF_LOG_DEBUG
* otherwise (NDEBUG is not defined).
*/
#if defined(ZF_LOG_LEVEL)
#define _ZF_LOG_LEVEL ZF_LOG_LEVEL
#elif defined(ZF_LOG_DEF_LEVEL)
#define _ZF_LOG_LEVEL ZF_LOG_DEF_LEVEL
#else
#ifdef NDEBUG
#define _ZF_LOG_LEVEL ZF_LOG_INFO
#else
#define _ZF_LOG_LEVEL ZF_LOG_DEBUG
#endif
#endif
/* "Output" log level is a runtime check. When log level is below output log
* level it said to be "turned off" (or just "off" for short). Otherwise it's
* "turned on" (or just "on"). Log levels that were "disabled" (see
* ZF_LOG_LEVEL and ZF_LOG_DEF_LEVEL) can't be "turned on", but "enabled" log
* levels could be "turned off". Only messages with log level which is
* "turned on" will reach output facility. All other messages will be ignored
* (and their arguments will not be evaluated). Output log level is a global
* property and configured per process using zf_log_set_output_level() function
* which can be called at any time.
*
* Though in some cases it could be useful to configure output log level per
* compilation module or per library. There are two ways to achieve that:
* - Define ZF_LOG_OUTPUT_LEVEL to expresion that evaluates to desired output
* log level.
* - Copy zf_log.h and zf_log.c files into your library and build it with
* ZF_LOG_LIBRARY_PREFIX defined to library specific prefix. See
* ZF_LOG_LIBRARY_PREFIX for more details.
*
* When defined, ZF_LOG_OUTPUT_LEVEL must evaluate to integral value that
* corresponds to desired output log level. Use it only when compilation module
* is required to have output log level which is different from global output
* log level set by zf_log_set_output_level() function. For other cases,
* consider defining ZF_LOG_LEVEL or using zf_log_set_output_level() function.
*
* Example:
*
* #define ZF_LOG_OUTPUT_LEVEL g_module_log_level
* #include <zf_log.h>
* static int g_module_log_level = ZF_LOG_INFO;
* static void foo() {
* ZF_LOGI("Will check g_module_log_level for output log level");
* }
* void debug_log(bool on) {
* g_module_log_level = on? ZF_LOG_DEBUG: ZF_LOG_INFO;
* }
*
* Note on performance. This expression will be evaluated each time message is
* logged (except when message log level is "disabled" - see ZF_LOG_LEVEL for
* details). Keep this expression as simple as possible, otherwise it will not
* only add runtime overhead, but also will increase size of call site (which
* will result in larger executable). The prefered way is to use integer
* variable (as in example above). If structure must be used, log_level field
* must be the first field in this structure:
*
* #define ZF_LOG_OUTPUT_LEVEL (g_config.log_level)
* #include <zf_log.h>
* struct config {
* int log_level;
* unsigned other_field;
* [...]
* };
* static config g_config = {ZF_LOG_INFO, 0, ...};
*
* This allows compiler to generate more compact load instruction (no need to
* specify offset since it's zero). Calling a function to get output log level
* is generaly a bad idea, since it will increase call site size and runtime
* overhead even further.
*/
#if defined(ZF_LOG_OUTPUT_LEVEL)
#define _ZF_LOG_OUTPUT_LEVEL ZF_LOG_OUTPUT_LEVEL
#else
#define _ZF_LOG_OUTPUT_LEVEL _zf_log_global_output_lvl
#endif
/* "Tag" is a compound string that could be associated with a log message. It
* consists of tag prefix and tag (both are optional).
*
* Tag prefix is a global property and configured per process using
* zf_log_set_tag_prefix() function. Tag prefix identifies context in which
* component or module is running (e.g. process name). For example, the same
* library could be used in both client and server processes that work on the
* same machine. Tag prefix could be used to easily distinguish between them.
* For more details about tag prefix see zf_log_set_tag_prefix() function. Tag
* prefix
*
* Tag identifies component or module. It is configured per compilation module
* (.c/.cpp/.m file) by defining ZF_LOG_TAG or ZF_LOG_DEF_TAG. ZF_LOG_TAG has
* higer priority and when defined overrides value provided by ZF_LOG_DEF_TAG.
* When defined, value must evaluate to (const char *), so for strings double
* quotes must be used.
*
* Default tag could be defined with ZF_LOG_DEF_TAG in build script (e.g.
* Makefile, CMakeLists.txt, gyp, etc.) for the entire project or target:
*
* CC_ARGS := -DZF_LOG_DEF_TAG=\"MISC\"
*
* And when necessary could be overriden with ZF_LOG_TAG in .c/.cpp/.m files
* before including zf_log.h:
*
* #define ZF_LOG_TAG "MAIN"
* #include <zf_log.h>
*
* If both ZF_LOG_DEF_TAG and ZF_LOG_TAG are undefined no tag will be added to
* the log message (tag prefix still could be added though).
*
* Output example:
*
* 04-29 22:43:20.244 40059 1299 I hello.MAIN Number of arguments: 1
* | |
* | +- tag (e.g. module)
* +- tag prefix (e.g. process name)
*/
#if defined(ZF_LOG_TAG)
#define _ZF_LOG_TAG ZF_LOG_TAG
#elif defined(ZF_LOG_DEF_TAG)
#define _ZF_LOG_TAG ZF_LOG_DEF_TAG
#else
#define _ZF_LOG_TAG 0
#endif
/* Source location is part of a log line that describes location (function or
* method name, file name and line number, e.g. "runloop@main.cpp:68") of a
* log statement that produced it.
* Source location formats are:
* - ZF_LOG_SRCLOC_NONE - don't add source location to log line.
* - ZF_LOG_SRCLOC_SHORT - add source location in short form (file and line
* number, e.g. "@main.cpp:68").
* - ZF_LOG_SRCLOC_LONG - add source location in long form (function or method
* name, file and line number, e.g. "runloop@main.cpp:68").
*/
#define ZF_LOG_SRCLOC_NONE 0
#define ZF_LOG_SRCLOC_SHORT 1
#define ZF_LOG_SRCLOC_LONG 2
/* Source location format is configured per compilation module (.c/.cpp/.m
* file) by defining ZF_LOG_DEF_SRCLOC or ZF_LOG_SRCLOC. ZF_LOG_SRCLOC has
* higer priority and when defined overrides value provided by
* ZF_LOG_DEF_SRCLOC.
*
* Common practice is to define default format with ZF_LOG_DEF_SRCLOC in
* build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire
* project or target:
*
* CC_ARGS := -DZF_LOG_DEF_SRCLOC=ZF_LOG_SRCLOC_LONG
*
* And when necessary to override it with ZF_LOG_SRCLOC in .c/.cpp/.m files
* before including zf_log.h:
*
* #define ZF_LOG_SRCLOC ZF_LOG_SRCLOC_NONE
* #include <zf_log.h>
*
* If both ZF_LOG_DEF_SRCLOC and ZF_LOG_SRCLOC are undefined, then
* ZF_LOG_SRCLOC_NONE will be used for release builds (NDEBUG is defined) and
* ZF_LOG_SRCLOC_LONG otherwise (NDEBUG is not defined).
*/
#if defined(ZF_LOG_SRCLOC)
#define _ZF_LOG_SRCLOC ZF_LOG_SRCLOC
#elif defined(ZF_LOG_DEF_SRCLOC)
#define _ZF_LOG_SRCLOC ZF_LOG_DEF_SRCLOC
#else
#ifdef NDEBUG
#define _ZF_LOG_SRCLOC ZF_LOG_SRCLOC_NONE
#else
#define _ZF_LOG_SRCLOC ZF_LOG_SRCLOC_LONG
#endif
#endif
#if ZF_LOG_SRCLOC_LONG == _ZF_LOG_SRCLOC
#define _ZF_LOG_SRCLOC_FUNCTION _ZF_LOG_FUNCTION
#else
#define _ZF_LOG_SRCLOC_FUNCTION 0
#endif
/* Censoring provides conditional logging of secret information, also known as
* Personally Identifiable Information (PII) or Sensitive Personal Information
* (SPI). Censoring can be either enabled (ZF_LOG_CENSORED) or disabled
* (ZF_LOG_UNCENSORED). When censoring is enabled, log statements marked as
* "secrets" will be ignored and will have zero overhead (arguments also will
* not be evaluated).
*/
#define ZF_LOG_CENSORED 1
#define ZF_LOG_UNCENSORED 0
/* Censoring is configured per compilation module (.c/.cpp/.m file) by defining
* ZF_LOG_DEF_CENSORING or ZF_LOG_CENSORING. ZF_LOG_CENSORING has higer priority
* and when defined overrides value provided by ZF_LOG_DEF_CENSORING.
*
* Common practice is to define default censoring with ZF_LOG_DEF_CENSORING in
* build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire
* project or target:
*
* CC_ARGS := -DZF_LOG_DEF_CENSORING=ZF_LOG_CENSORED
*
* And when necessary to override it with ZF_LOG_CENSORING in .c/.cpp/.m files
* before including zf_log.h (consider doing it only for debug purposes and be
* very careful not to push such temporary changes to source control):
*
* #define ZF_LOG_CENSORING ZF_LOG_UNCENSORED
* #include <zf_log.h>
*
* If both ZF_LOG_DEF_CENSORING and ZF_LOG_CENSORING are undefined, then
* ZF_LOG_CENSORED will be used for release builds (NDEBUG is defined) and
* ZF_LOG_UNCENSORED otherwise (NDEBUG is not defined).
*/
#if defined(ZF_LOG_CENSORING)
#define _ZF_LOG_CENSORING ZF_LOG_CENSORING
#elif defined(ZF_LOG_DEF_CENSORING)
#define _ZF_LOG_CENSORING ZF_LOG_DEF_CENSORING
#else
#ifdef NDEBUG
#define _ZF_LOG_CENSORING ZF_LOG_CENSORED
#else
#define _ZF_LOG_CENSORING ZF_LOG_UNCENSORED
#endif
#endif
/* Check censoring at compile time. Evaluates to true when censoring is disabled
* (i.e. when secrets will be logged). For example:
*
* #if ZF_LOG_SECRETS
* char ssn[16];
* getSocialSecurityNumber(ssn);
* ZF_LOGI("Customer ssn: %s", ssn);
* #endif
*
* See ZF_LOG_SECRET() macro for a more convenient way of guarding single log
* statement.
*/
#define ZF_LOG_SECRETS (ZF_LOG_UNCENSORED == _ZF_LOG_CENSORING)
/* Static (compile-time) initialization support allows to configure logging
* before entering main() function. This mostly useful in C++ where functions
* and methods could be called during initialization of global objects. Those
* functions and methods could record log messages too and for that reason
* static initialization of logging configuration is customizable.
*
* Macros below allow to specify values to use for initial configuration:
* - ZF_LOG_EXTERN_TAG_PREFIX - tag prefix (default: none)
* - ZF_LOG_EXTERN_GLOBAL_FORMAT - global format options (default: see
* ZF_LOG_MEM_WIDTH in zf_log.c)
* - ZF_LOG_EXTERN_GLOBAL_OUTPUT - global output facility (default: stderr or
* platform specific, see ZF_LOG_USE_XXX macros in zf_log.c)
* - ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL - global output log level (default: 0 -
* all levals are "turned on")
*
* For example, in log_config.c:
*
* #include <zf_log.h>
* ZF_LOG_DEFINE_TAG_PREFIX = "MyApp";
* ZF_LOG_DEFINE_GLOBAL_FORMAT = {CUSTOM_MEM_WIDTH};
* ZF_LOG_DEFINE_GLOBAL_OUTPUT = {ZF_LOG_PUT_STD, custom_output_callback, 0};
* ZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = ZF_LOG_INFO;
*
* However, to use any of those macros zf_log library must be compiled with
* following macros defined:
* - to use ZF_LOG_DEFINE_TAG_PREFIX define ZF_LOG_EXTERN_TAG_PREFIX
* - to use ZF_LOG_DEFINE_GLOBAL_FORMAT define ZF_LOG_EXTERN_GLOBAL_FORMAT
* - to use ZF_LOG_DEFINE_GLOBAL_OUTPUT define ZF_LOG_EXTERN_GLOBAL_OUTPUT
* - to use ZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL define
* ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
*
* When zf_log library compiled with one of ZF_LOG_EXTERN_XXX macros defined,
* corresponding ZF_LOG_DEFINE_XXX macro MUST be used exactly once somewhere.
* Otherwise build will fail with link error (undefined symbol).
*/
#define ZF_LOG_DEFINE_TAG_PREFIX const char *_zf_log_tag_prefix
#define ZF_LOG_DEFINE_GLOBAL_FORMAT zf_log_format _zf_log_global_format
#define ZF_LOG_DEFINE_GLOBAL_OUTPUT zf_log_output _zf_log_global_output
#define ZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL int _zf_log_global_output_lvl
/* Pointer to global format options. Direct modification is not allowed. Use
* zf_log_set_mem_width() instead. Could be used to initialize zf_log_spec
* structure:
*
* const zf_log_output g_output = {ZF_LOG_PUT_STD, output_callback, 0};
* const zf_log_spec g_spec = {ZF_LOG_GLOBAL_FORMAT, &g_output};
* ZF_LOGI_AUX(&g_spec, "Hello");
*/
#define ZF_LOG_GLOBAL_FORMAT ((const zf_log_format *)&_zf_log_global_format)
/* Pointer to global output variable. Direct modification is not allowed. Use
* zf_log_set_output_v() or zf_log_set_output_p() instead. Could be used to
* initialize zf_log_spec structure:
*
* const zf_log_format g_format = {40};
* const zf_log_spec g_spec = {g_format, ZF_LOG_GLOBAL_OUTPUT};
* ZF_LOGI_AUX(&g_spec, "Hello");
*/
#define ZF_LOG_GLOBAL_OUTPUT ((const zf_log_output *)&_zf_log_global_output)
/* When defined, all library symbols produced by linker will be prefixed with
* provided value. That allows to use zf_log library privately in another
* libraries without exposing zf_log symbols in their original form (to avoid
* possible conflicts with other libraries / components that also could use
* zf_log for logging). Value must be without quotes, for example:
*
* CC_ARGS := -DZF_LOG_LIBRARY_PREFIX=my_lib_
*
* Note, that in this mode ZF_LOG_LIBRARY_PREFIX must be defined when building
* zf_log library AND it also must be defined to the same value when building
* a library that uses it. For example, consider fictional KittyHttp library
* that wants to use zf_log for logging. First approach that could be taken is
* to add zf_log.h and zf_log.c to the KittyHttp's source code tree directly.
* In that case it will be enough just to define ZF_LOG_LIBRARY_PREFIX in
* KittyHttp's build script:
*
* // KittyHttp/CMakeLists.txt
* target_compile_definitions(KittyHttp PRIVATE
* "ZF_LOG_LIBRARY_PREFIX=KittyHttp_")
*
* If KittyHttp doesn't want to include zf_log source code in its source tree
* and wants to build zf_log as a separate library than zf_log library must be
* built with ZF_LOG_LIBRARY_PREFIX defined to KittyHttp_ AND KittyHttp library
* itself also needs to define ZF_LOG_LIBRARY_PREFIX to KittyHttp_. It can do
* so either in its build script, as in example above, or by providing a
* wrapper header that KittyHttp library will need to use instead of zf_log.h:
*
* // KittyHttpLogging.h
* #define ZF_LOG_LIBRARY_PREFIX KittyHttp_
* #include <zf_log.h>
*
* Regardless of the method chosen, the end result is that zf_log symbols will
* be prefixed with "KittyHttp_", so if a user of KittyHttp (say DogeBrowser)
* also uses zf_log for logging, they will not interferer with each other. Both
* will have their own log level, output facility, format options etc.
*/
#ifdef ZF_LOG_LIBRARY_PREFIX
#define _ZF_LOG_DECOR__(prefix, name) prefix ## name
#define _ZF_LOG_DECOR_(prefix, name) _ZF_LOG_DECOR__(prefix, name)
#define _ZF_LOG_DECOR(name) _ZF_LOG_DECOR_(ZF_LOG_LIBRARY_PREFIX, name)
#define zf_log_set_tag_prefix _ZF_LOG_DECOR(zf_log_set_tag_prefix)
#define zf_log_set_mem_width _ZF_LOG_DECOR(zf_log_set_mem_width)
#define zf_log_set_output_level _ZF_LOG_DECOR(zf_log_set_output_level)
#define zf_log_set_output_v _ZF_LOG_DECOR(zf_log_set_output_v)
#define zf_log_set_output_p _ZF_LOG_DECOR(zf_log_set_output_p)
#define zf_log_out_stderr_callback _ZF_LOG_DECOR(zf_log_out_stderr_callback)
#define _zf_log_tag_prefix _ZF_LOG_DECOR(_zf_log_tag_prefix)
#define _zf_log_global_format _ZF_LOG_DECOR(_zf_log_global_format)
#define _zf_log_global_output _ZF_LOG_DECOR(_zf_log_global_output)
#define _zf_log_global_output_lvl _ZF_LOG_DECOR(_zf_log_global_output_lvl)
#define _zf_log_write_d _ZF_LOG_DECOR(_zf_log_write_d)
#define _zf_log_write_aux_d _ZF_LOG_DECOR(_zf_log_write_aux_d)
#define _zf_log_write _ZF_LOG_DECOR(_zf_log_write)
#define _zf_log_write_aux _ZF_LOG_DECOR(_zf_log_write_aux)
#define _zf_log_write_mem_d _ZF_LOG_DECOR(_zf_log_write_mem_d)
#define _zf_log_write_mem_aux_d _ZF_LOG_DECOR(_zf_log_write_mem_aux_d)
#define _zf_log_write_mem _ZF_LOG_DECOR(_zf_log_write_mem)
#define _zf_log_write_mem_aux _ZF_LOG_DECOR(_zf_log_write_mem_aux)
#define _zf_log_stderr_spec _ZF_LOG_DECOR(_zf_log_stderr_spec)
#endif
#if defined(__printflike)
#define _ZF_LOG_PRINTFLIKE(a, b) __printflike(a, b)
#else
#define _ZF_LOG_PRINTFLIKE(a, b)
#endif
#if (defined(_WIN32) || defined(_WIN64)) && !defined(__GNUC__)
#define _ZF_LOG_FUNCTION __FUNCTION__
#else
#define _ZF_LOG_FUNCTION __func__
#endif
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
#define _ZF_LOG_INLINE __inline
#define _ZF_LOG_IF(cond) \
__pragma(warning(push)) \
__pragma(warning(disable:4127)) \
if(cond) \
__pragma(warning(pop))
#define _ZF_LOG_WHILE(cond) \
__pragma(warning(push)) \
__pragma(warning(disable:4127)) \
while(cond) \
__pragma(warning(pop))
#else
#define _ZF_LOG_INLINE inline
#define _ZF_LOG_IF(cond) if(cond)
#define _ZF_LOG_WHILE(cond) while(cond)
#endif
#define _ZF_LOG_NEVER _ZF_LOG_IF(0)
#define _ZF_LOG_ONCE _ZF_LOG_WHILE(0)
#ifdef __cplusplus
extern "C" {
#endif
/* Set tag prefix. Prefix will be separated from the tag with dot ('.').
* Use 0 or empty string to disable (default). Common use is to set it to
* the process (or build target) name (e.g. to separate client and server
* processes). Function will NOT copy provided prefix string, but will store the
* pointer. Hence specified prefix string must remain valid. See
* ZF_LOG_DEFINE_TAG_PREFIX for a way to set it before entering main() function.
* See ZF_LOG_TAG for more information about tag and tag prefix.
*/
void zf_log_set_tag_prefix(const char *const prefix);
/* Set number of bytes per log line in memory (ASCII-HEX) output. Example:
*
* I hello.MAIN 4c6f72656d20697073756d20646f6c6f Lorem ipsum dolo
* |<- w bytes ->| |<- w chars ->|
*
* See ZF_LOGF_MEM and ZF_LOGF_MEM_AUX for more details.
*/
void zf_log_set_mem_width(const unsigned w);
/* Set "output" log level. See ZF_LOG_LEVEL and ZF_LOG_OUTPUT_LEVEL for more
* info about log levels.
*/
void zf_log_set_output_level(const int lvl);
/* Put mask is a set of flags that define what fields will be added to each
* log message. Default value is ZF_LOG_PUT_STD and other flags could be used to
* alter its behavior. See zf_log_set_output_v() for more details.
*
* Note about ZF_LOG_PUT_SRC: it will be added only in debug builds (NDEBUG is
* not defined).
*/
enum
{
ZF_LOG_PUT_CTX = 1 << 0, /* context (time, pid, tid, log level) */
ZF_LOG_PUT_TAG = 1 << 1, /* tag (including tag prefix) */
ZF_LOG_PUT_SRC = 1 << 2, /* source location (file, line, function) */
ZF_LOG_PUT_MSG = 1 << 3, /* message text (formatted string) */
ZF_LOG_PUT_STD = 0xffff, /* everything (default) */
};
typedef struct zf_log_message
{
int lvl; /* Log level of the message */
const char *tag; /* Associated tag (without tag prefix) */
char *buf; /* Buffer start */
char *e; /* Buffer end (last position where EOL with 0 could be written) */
char *p; /* Buffer content end (append position) */
char *tag_b; /* Prefixed tag start */
char *tag_e; /* Prefixed tag end (if != tag_b, points to msg separator) */
char *msg_b; /* Message start (expanded format string) */
}
zf_log_message;
/* Type of output callback function. It will be called for each log line allowed
* by both "current" and "output" log levels ("enabled" and "turned on").
* Callback function is allowed to modify content of the buffers pointed by the
* msg, but it's not allowed to modify any of msg fields. Buffer pointed by msg
* is UTF-8 encoded (no BOM mark).
*/
typedef void (*zf_log_output_cb)(const zf_log_message *msg, void *arg);
/* Format options. For more details see zf_log_set_mem_width().
*/
typedef struct zf_log_format
{
unsigned mem_width; /* Bytes per line in memory (ASCII-HEX) dump */
}
zf_log_format;
/* Output facility.
*/
typedef struct zf_log_output
{
unsigned mask; /* What to put into log line buffer (see ZF_LOG_PUT_XXX) */
void *arg; /* User provided output callback argument */
zf_log_output_cb callback; /* Output callback function */
}
zf_log_output;
/* Set output callback function.
*
* Mask allows to control what information will be added to the log line buffer
* before callback function is invoked. Default mask value is ZF_LOG_PUT_STD.
*/
void zf_log_set_output_v(const unsigned mask, void *const arg,
const zf_log_output_cb callback);
static _ZF_LOG_INLINE void zf_log_set_output_p(const zf_log_output *const output)
{
zf_log_set_output_v(output->mask, output->arg, output->callback);
}
/* Used with _AUX macros and allows to override global format and output
* facility. Use ZF_LOG_GLOBAL_FORMAT and ZF_LOG_GLOBAL_OUTPUT for values from
* global configuration. Example:
*
* static const zf_log_output module_output = {
* ZF_LOG_PUT_STD, 0, custom_output_callback
* };
* static const zf_log_spec module_spec = {
* ZF_LOG_GLOBAL_FORMAT, &module_output
* };
* ZF_LOGI_AUX(&module_spec, "Position: %ix%i", x, y);
*
* See ZF_LOGF_AUX and ZF_LOGF_MEM_AUX for details.
*/
typedef struct zf_log_spec
{
const zf_log_format *format;
const zf_log_output *output;
}
zf_log_spec;
#ifdef __cplusplus
}
#endif
/* Execute log statement if condition is true. Example:
*
* ZF_LOG_IF(1 < 2, ZF_LOGI("Log this"));
* ZF_LOG_IF(1 > 2, ZF_LOGI("Don't log this"));
*
* Keep in mind though, that if condition can't be evaluated at compile time,
* then it will be evaluated at run time. This will increase exectuable size
* and can have noticeable performance overhead. Try to limit conditions to
* expressions that can be evaluated at compile time.
*/
#define ZF_LOG_IF(cond, f) do { _ZF_LOG_IF((cond)) { f; } } _ZF_LOG_ONCE
/* Mark log statement as "secret". Log statements that are marked as secrets
* will NOT be executed when censoring is enabled (see ZF_LOG_CENSORED).
* Example:
*
* ZF_LOG_SECRET(ZF_LOGI("Credit card: %s", credit_card));
* ZF_LOG_SECRET(ZF_LOGD_MEM(cipher, cipher_sz, "Cipher bytes:"));
*/
#define ZF_LOG_SECRET(f) ZF_LOG_IF(ZF_LOG_SECRETS, f)
/* Check "current" log level at compile time (ignoring "output" log level).
* Evaluates to true when specified log level is enabled. For example:
*
* #if ZF_LOG_ENABLED_DEBUG
* const char *const g_enum_strings[] = {
* "enum_value_0", "enum_value_1", "enum_value_2"
* };
* #endif
* // ...
* #if ZF_LOG_ENABLED_DEBUG
* ZF_LOGD("enum value: %s", g_enum_strings[v]);
* #endif
*
* See ZF_LOG_LEVEL for details.
*/
#define ZF_LOG_ENABLED(lvl) ((lvl) >= _ZF_LOG_LEVEL)
#define ZF_LOG_ENABLED_VERBOSE ZF_LOG_ENABLED(ZF_LOG_VERBOSE)
#define ZF_LOG_ENABLED_DEBUG ZF_LOG_ENABLED(ZF_LOG_DEBUG)
#define ZF_LOG_ENABLED_INFO ZF_LOG_ENABLED(ZF_LOG_INFO)
#define ZF_LOG_ENABLED_WARN ZF_LOG_ENABLED(ZF_LOG_WARN)
#define ZF_LOG_ENABLED_ERROR ZF_LOG_ENABLED(ZF_LOG_ERROR)
#define ZF_LOG_ENABLED_FATAL ZF_LOG_ENABLED(ZF_LOG_FATAL)
/* Check "output" log level at run time (taking into account "current" log
* level as well). Evaluates to true when specified log level is turned on AND
* enabled. For example:
*
* if (ZF_LOG_ON_DEBUG)
* {
* char hash[65];
* sha256(data_ptr, data_sz, hash);
* ZF_LOGD("data: len=%u, sha256=%s", data_sz, hash);
* }
*
* See ZF_LOG_OUTPUT_LEVEL for details.
*/
#define ZF_LOG_ON(lvl) \
(ZF_LOG_ENABLED((lvl)) && (lvl) >= _ZF_LOG_OUTPUT_LEVEL)
#define ZF_LOG_ON_VERBOSE ZF_LOG_ON(ZF_LOG_VERBOSE)
#define ZF_LOG_ON_DEBUG ZF_LOG_ON(ZF_LOG_DEBUG)
#define ZF_LOG_ON_INFO ZF_LOG_ON(ZF_LOG_INFO)
#define ZF_LOG_ON_WARN ZF_LOG_ON(ZF_LOG_WARN)
#define ZF_LOG_ON_ERROR ZF_LOG_ON(ZF_LOG_ERROR)
#define ZF_LOG_ON_FATAL ZF_LOG_ON(ZF_LOG_FATAL)
#ifdef __cplusplus
extern "C" {
#endif
extern const char *_zf_log_tag_prefix;
extern zf_log_format _zf_log_global_format;
extern zf_log_output _zf_log_global_output;
extern int _zf_log_global_output_lvl;
extern const zf_log_spec _zf_log_stderr_spec;
void _zf_log_write_d(
const char *const func, const char *const file, const unsigned line,
const int lvl, const char *const tag,
const char *const fmt, ...) _ZF_LOG_PRINTFLIKE(6, 7);
void _zf_log_write_aux_d(
const char *const func, const char *const file, const unsigned line,
const zf_log_spec *const log, const int lvl, const char *const tag,
const char *const fmt, ...) _ZF_LOG_PRINTFLIKE(7, 8);
void _zf_log_write(
const int lvl, const char *const tag,
const char *const fmt, ...) _ZF_LOG_PRINTFLIKE(3, 4);
void _zf_log_write_aux(
const zf_log_spec *const log, const int lvl, const char *const tag,
const char *const fmt, ...) _ZF_LOG_PRINTFLIKE(4, 5);
void _zf_log_write_mem_d(
const char *const func, const char *const file, const unsigned line,
const int lvl, const char *const tag,
const void *const d, const unsigned d_sz,
const char *const fmt, ...) _ZF_LOG_PRINTFLIKE(8, 9);
void _zf_log_write_mem_aux_d(
const char *const func, const char *const file, const unsigned line,
const zf_log_spec *const log, const int lvl, const char *const tag,
const void *const d, const unsigned d_sz,
const char *const fmt, ...) _ZF_LOG_PRINTFLIKE(9, 10);
void _zf_log_write_mem(
const int lvl, const char *const tag,
const void *const d, const unsigned d_sz,
const char *const fmt, ...) _ZF_LOG_PRINTFLIKE(5, 6);
void _zf_log_write_mem_aux(
const zf_log_spec *const log, const int lvl, const char *const tag,
const void *const d, const unsigned d_sz,
const char *const fmt, ...) _ZF_LOG_PRINTFLIKE(6, 7);
#ifdef __cplusplus
}
#endif
/* Message logging macros:
* - ZF_LOGV("format string", args, ...)
* - ZF_LOGD("format string", args, ...)
* - ZF_LOGI("format string", args, ...)
* - ZF_LOGW("format string", args, ...)
* - ZF_LOGE("format string", args, ...)
* - ZF_LOGF("format string", args, ...)
*
* Memory logging macros:
* - ZF_LOGV_MEM(data_ptr, data_sz, "format string", args, ...)
* - ZF_LOGD_MEM(data_ptr, data_sz, "format string", args, ...)
* - ZF_LOGI_MEM(data_ptr, data_sz, "format string", args, ...)
* - ZF_LOGW_MEM(data_ptr, data_sz, "format string", args, ...)
* - ZF_LOGE_MEM(data_ptr, data_sz, "format string", args, ...)
* - ZF_LOGF_MEM(data_ptr, data_sz, "format string", args, ...)
*
* Auxiliary logging macros:
* - ZF_LOGV_AUX(&log_instance, "format string", args, ...)
* - ZF_LOGD_AUX(&log_instance, "format string", args, ...)
* - ZF_LOGI_AUX(&log_instance, "format string", args, ...)
* - ZF_LOGW_AUX(&log_instance, "format string", args, ...)
* - ZF_LOGE_AUX(&log_instance, "format string", args, ...)
* - ZF_LOGF_AUX(&log_instance, "format string", args, ...)
*
* Auxiliary memory logging macros:
* - ZF_LOGV_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
* - ZF_LOGD_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
* - ZF_LOGI_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
* - ZF_LOGW_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
* - ZF_LOGE_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
* - ZF_LOGF_MEM_AUX(&log_instance, data_ptr, data_sz, "format string", args, ...)
*
* Preformatted string logging macros:
* - ZF_LOGV_STR("preformatted string");
* - ZF_LOGD_STR("preformatted string");
* - ZF_LOGI_STR("preformatted string");
* - ZF_LOGW_STR("preformatted string");
* - ZF_LOGE_STR("preformatted string");
* - ZF_LOGF_STR("preformatted string");
*
* Explicit log level and tag macros:
* - ZF_LOG_WRITE(level, tag, "format string", args, ...)
* - ZF_LOG_WRITE_MEM(level, tag, data_ptr, data_sz, "format string", args, ...)
* - ZF_LOG_WRITE_AUX(&log_instance, level, tag, "format string", args, ...)
* - ZF_LOG_WRITE_MEM_AUX(&log_instance, level, tag, data_ptr, data_sz,
* "format string", args, ...)
*
* Format string follows printf() conventions. Both data_ptr and data_sz could
* be 0. Tag can be 0 as well. Most compilers will verify that type of arguments
* match format specifiers in format string.
*
* Library assuming UTF-8 encoding for all strings (char *), including format
* string itself.
*/
#if ZF_LOG_SRCLOC_NONE == _ZF_LOG_SRCLOC
#define ZF_LOG_WRITE(lvl, tag, ...) \
do { \
if (ZF_LOG_ON(lvl)) \
_zf_log_write(lvl, tag, __VA_ARGS__); \
} _ZF_LOG_ONCE
#define ZF_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \
do { \
if (ZF_LOG_ON(lvl)) \
_zf_log_write_mem(lvl, tag, d, d_sz, __VA_ARGS__); \
} _ZF_LOG_ONCE
#define ZF_LOG_WRITE_AUX(log, lvl, tag, ...) \
do { \
if (ZF_LOG_ON(lvl)) \
_zf_log_write_aux(log, lvl, tag, __VA_ARGS__); \
} _ZF_LOG_ONCE
#define ZF_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \
do { \
if (ZF_LOG_ON(lvl)) \
_zf_log_write_mem_aux(log, lvl, tag, d, d_sz, __VA_ARGS__); \
} _ZF_LOG_ONCE
#else
#define ZF_LOG_WRITE(lvl, tag, ...) \
do { \
if (ZF_LOG_ON(lvl)) \
_zf_log_write_d(_ZF_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \
lvl, tag, __VA_ARGS__); \
} _ZF_LOG_ONCE
#define ZF_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \
do { \
if (ZF_LOG_ON(lvl)) \
_zf_log_write_mem_d(_ZF_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \
lvl, tag, d, d_sz, __VA_ARGS__); \
} _ZF_LOG_ONCE
#define ZF_LOG_WRITE_AUX(log, lvl, tag, ...) \
do { \
if (ZF_LOG_ON(lvl)) \
_zf_log_write_aux_d(_ZF_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \
log, lvl, tag, __VA_ARGS__); \
} _ZF_LOG_ONCE
#define ZF_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \
do { \
if (ZF_LOG_ON(lvl)) \
_zf_log_write_mem_aux_d(_ZF_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \
log, lvl, tag, d, d_sz, __VA_ARGS__); \
} _ZF_LOG_ONCE
#endif
static _ZF_LOG_INLINE void _zf_log_unused(const int dummy, ...) {(void)dummy;}
#define _ZF_LOG_UNUSED(...) \
do { _ZF_LOG_NEVER _zf_log_unused(0, __VA_ARGS__); } _ZF_LOG_ONCE
#if ZF_LOG_ENABLED_VERBOSE
#define ZF_LOGV(...) \
ZF_LOG_WRITE(ZF_LOG_VERBOSE, _ZF_LOG_TAG, __VA_ARGS__)
#define ZF_LOGV_AUX(log, ...) \
ZF_LOG_WRITE_AUX(log, ZF_LOG_VERBOSE, _ZF_LOG_TAG, __VA_ARGS__)
#define ZF_LOGV_MEM(d, d_sz, ...) \
ZF_LOG_WRITE_MEM(ZF_LOG_VERBOSE, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)
#define ZF_LOGV_MEM_AUX(log, d, d_sz, ...) \
ZF_LOG_WRITE_MEM(log, ZF_LOG_VERBOSE, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)
#else
#define ZF_LOGV(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGV_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGV_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGV_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#endif
#if ZF_LOG_ENABLED_DEBUG
#define ZF_LOGD(...) \
ZF_LOG_WRITE(ZF_LOG_DEBUG, _ZF_LOG_TAG, __VA_ARGS__)
#define ZF_LOGD_AUX(log, ...) \
ZF_LOG_WRITE_AUX(log, ZF_LOG_DEBUG, _ZF_LOG_TAG, __VA_ARGS__)
#define ZF_LOGD_MEM(d, d_sz, ...) \
ZF_LOG_WRITE_MEM(ZF_LOG_DEBUG, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)
#define ZF_LOGD_MEM_AUX(log, d, d_sz, ...) \
ZF_LOG_WRITE_MEM_AUX(log, ZF_LOG_DEBUG, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)
#else
#define ZF_LOGD(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGD_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGD_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGD_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#endif
#if ZF_LOG_ENABLED_INFO
#define ZF_LOGI(...) \
ZF_LOG_WRITE(ZF_LOG_INFO, _ZF_LOG_TAG, __VA_ARGS__)
#define ZF_LOGI_AUX(log, ...) \
ZF_LOG_WRITE_AUX(log, ZF_LOG_INFO, _ZF_LOG_TAG, __VA_ARGS__)
#define ZF_LOGI_MEM(d, d_sz, ...) \
ZF_LOG_WRITE_MEM(ZF_LOG_INFO, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)
#define ZF_LOGI_MEM_AUX(log, d, d_sz, ...) \
ZF_LOG_WRITE_MEM_AUX(log, ZF_LOG_INFO, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)
#else
#define ZF_LOGI(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGI_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGI_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGI_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#endif
#if ZF_LOG_ENABLED_WARN
#define ZF_LOGW(...) \
ZF_LOG_WRITE(ZF_LOG_WARN, _ZF_LOG_TAG, __VA_ARGS__)
#define ZF_LOGW_AUX(log, ...) \
ZF_LOG_WRITE_AUX(log, ZF_LOG_WARN, _ZF_LOG_TAG, __VA_ARGS__)
#define ZF_LOGW_MEM(d, d_sz, ...) \
ZF_LOG_WRITE_MEM(ZF_LOG_WARN, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)
#define ZF_LOGW_MEM_AUX(log, d, d_sz, ...) \
ZF_LOG_WRITE_MEM_AUX(log, ZF_LOG_WARN, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)
#else
#define ZF_LOGW(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGW_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGW_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGW_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#endif
#if ZF_LOG_ENABLED_ERROR
#define ZF_LOGE(...) \
ZF_LOG_WRITE(ZF_LOG_ERROR, _ZF_LOG_TAG, __VA_ARGS__)
#define ZF_LOGE_AUX(log, ...) \
ZF_LOG_WRITE_AUX(log, ZF_LOG_ERROR, _ZF_LOG_TAG, __VA_ARGS__)
#define ZF_LOGE_MEM(d, d_sz, ...) \
ZF_LOG_WRITE_MEM(ZF_LOG_ERROR, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)
#define ZF_LOGE_MEM_AUX(log, d, d_sz, ...) \
ZF_LOG_WRITE_MEM_AUX(log, ZF_LOG_ERROR, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)
#else
#define ZF_LOGE(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGE_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGE_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGE_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#endif
#if ZF_LOG_ENABLED_FATAL
#define ZF_LOGF(...) \
ZF_LOG_WRITE(ZF_LOG_FATAL, _ZF_LOG_TAG, __VA_ARGS__)
#define ZF_LOGF_AUX(log, ...) \
ZF_LOG_WRITE_AUX(log, ZF_LOG_FATAL, _ZF_LOG_TAG, __VA_ARGS__)
#define ZF_LOGF_MEM(d, d_sz, ...) \
ZF_LOG_WRITE_MEM(ZF_LOG_FATAL, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)
#define ZF_LOGF_MEM_AUX(log, d, d_sz, ...) \
ZF_LOG_WRITE_MEM_AUX(log, ZF_LOG_FATAL, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)
#else
#define ZF_LOGF(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGF_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGF_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#define ZF_LOGF_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)
#endif
#define ZF_LOGV_STR(s) ZF_LOGV("%s", (s))
#define ZF_LOGD_STR(s) ZF_LOGD("%s", (s))
#define ZF_LOGI_STR(s) ZF_LOGI("%s", (s))
#define ZF_LOGW_STR(s) ZF_LOGW("%s", (s))
#define ZF_LOGE_STR(s) ZF_LOGE("%s", (s))
#define ZF_LOGF_STR(s) ZF_LOGF("%s", (s))
#ifdef __cplusplus
extern "C" {
#endif
/* Output to standard error stream. Library uses it by default, though in few
* cases it could be necessary to specify it explicitly. For example, when
* zf_log library is compiled with ZF_LOG_EXTERN_GLOBAL_OUTPUT, application must
* define and initialize global output variable:
*
* ZF_LOG_DEFINE_GLOBAL_OUTPUT = {ZF_LOG_OUT_STDERR};
*
* Another example is when using custom output, stderr could be used as a
* fallback when custom output facility failed to initialize:
*
* zf_log_set_output_v(ZF_LOG_OUT_STDERR);
*/
enum { ZF_LOG_OUT_STDERR_MASK = ZF_LOG_PUT_STD };
void zf_log_out_stderr_callback(const zf_log_message *const msg, void *arg);
#define ZF_LOG_OUT_STDERR ZF_LOG_OUT_STDERR_MASK, 0, zf_log_out_stderr_callback
/* Predefined spec for stderr. Uses global format options (ZF_LOG_GLOBAL_FORMAT)
* and ZF_LOG_OUT_STDERR. Could be used to force output to stderr for a
* particular message. Example:
*
* f = fopen("foo.log", "w");
* if (!f)
* ZF_LOGE_AUX(ZF_LOG_STDERR, "Failed to open log file");
*/
#define ZF_LOG_STDERR (&_zf_log_stderr_spec)
#ifdef __cplusplus
}
#endif
#endif
================================================
FILE: tests/zf_test.h
================================================
#pragma once
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#if !defined(_ZF_TEST_STRINGIFY) && !defined(_ZF_TEST__STRINGIFY)
#define _ZF_TEST__STRINGIFY(x) #x
#define _ZF_TEST_STRINGIFY(x) _ZF_TEST__STRINGIFY(x)
#endif
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
#define _ZF_TEST_INLINE __inline
#else
#define _ZF_TEST_INLINE inline
#endif
/* Workaround for MSVC warning 4127 about constant expression in if condition.
*/
static _ZF_TEST_INLINE bool _zf_test_bool(const bool v)
{
return v;
}
#define TEST_RUNNER_CREATE(argc, argv) \
(void)argc; (void)argv;
#define TEST_SUIT_ARGUMENTS
#define TEST_VERIFY_TRUE(a) \
if (!_zf_test_bool(a)) { \
fprintf(stderr, "%s:%u: %s:\n", __FILE__, __LINE__, "not true"); \
fprintf(stderr, " false: %s\n", _ZF_TEST_STRINGIFY(a)); \
exit(1); \
}
#define TEST_VERIFY_TRUE_MSG(a, ...) \
if (!_zf_test_bool(a)) { \
fprintf(stderr, "%s:%u: %s:\n", __FILE__, __LINE__, "not true"); \
fprintf(stderr, " false: %s\n", _ZF_TEST_STRINGIFY(a)); \
fprintf(stderr, " about: "); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
exit(1); \
}
#define TEST_VERIFY_FALSE(a) \
if (_zf_test_bool(a)) { \
fprintf(stderr, "%s:%u: %s:\n", __FILE__, __LINE__, "not false"); \
fprintf(stderr, " true: %s\n", _ZF_TEST_STRINGIFY(a)); \
exit(1); \
}
#define TEST_VERIFY_EQUAL(a, b) \
if (!_zf_test_bool((a) == (b))) { \
fprintf(stderr, "%s:%u: %s:\n", __FILE__, __LINE__, "not equal"); \
fprintf(stderr, " left: %s\n", _ZF_TEST_STRINGIFY(a)); \
fprintf(stderr, " reight: %s\n", _ZF_TEST_STRINGIFY(b)); \
exit(1); \
}
#define TEST_VERIFY_NOT_EQUAL(a, b) \
if (!_zf_test_bool((a) != (b))) { \
fprintf(stderr, "%s:%u: %s:\n", __FILE__, __LINE__, "equal"); \
fprintf(stderr, " left: %s\n", _ZF_TEST_STRINGIFY(a)); \
fprintf(stderr, " reight: %s\n", _ZF_TEST_STRINGIFY(b)); \
exit(1); \
}
#define TEST_VERIFY_GREATER_OR_EQUAL(a, b) \
if (!_zf_test_bool((a) >= (b))) { \
fprintf(stderr, "%s:%u: %s:\n", __FILE__, __LINE__, "less"); \
fprintf(stderr, " left: %s\n", _ZF_TEST_STRINGIFY(a)); \
fprintf(stderr, " reight: %s\n", _ZF_TEST_STRINGIFY(b)); \
exit(1); \
}
#define TEST_EXECUTE(f) \
f
#define TEST_EXECUTE_SUITE(s) \
s()
#define TEST_RUNNER_EXIT_CODE() \
0
================================================
FILE: zf_log/CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.2)
# zf_log target (required)
set(HEADERS_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(HEADERS zf_log.h)
set(SOURCES zf_log.c)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
if(MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4 /WX")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -pedantic-errors")
endif()
add_library(zf_log ${HEADERS} ${SOURCES})
target_include_directories(zf_log PUBLIC $<BUILD_INTERFACE:${HEADERS_DIR}>)
if(ZF_LOG_LIBRARY_PREFIX)
target_compile_definitions(zf_log PRIVATE "ZF_LOG_LIBRARY_PREFIX=${ZF_LOG_LIBRARY_PREFIX}")
endif()
if(ZF_LOG_USE_ANDROID_LOG)
target_compile_definitions(zf_log PRIVATE "ZF_LOG_USE_ANDROID_LOG")
target_link_libraries(zf_log log)
endif()
if(ZF_LOG_USE_NSLOG)
target_compile_definitions(zf_log PRIVATE "ZF_LOG_USE_NSLOG")
target_link_libraries(zf_log "-framework CoreFoundation")
endif()
if(ZF_LOG_USE_DEBUGSTRING)
target_compile_definitions(zf_log PRIVATE "ZF_LOG_USE_DEBUGSTRING")
endif()
if(ZF_LOG_USE_CONFIG_HEADER)
target_compile_definitions(zf_log PRIVATE "ZF_LOG_USE_CONFIG_HEADER")
endif()
if(ZF_LOG_OPTIMIZE_SIZE)
target_compile_definitions(zf_log PRIVATE "ZF_LOG_OPTIMIZE_SIZE")
endif()
# install (optional)
if(ZF_LOG_CONFIGURE_INSTALL)
if(NOT DEFINED INSTALL_INCLUDE_DIR)
set(INSTALL_INCLUDE_DIR include)
endif()
if(NOT DEFINED INSTALL_LIB_DIR)
set(INSTALL_LIB_DIR lib)
endif()
install(TARGETS zf_log EXPORT zf_log
INCLUDES DESTINATION ${INSTALL_INCLUDE_DIR}
ARCHIVE DESTINATION ${INSTALL_LIB_DIR})
install(DIRECTORY ${HEADERS_DIR}/
DESTINATION ${INSTALL_INCLUDE_DIR}
FILES_MATCHING PATTERN "zf_*.h*")
endif()
================================================
FILE: zf_log/zf_log.c
================================================
#ifdef ZF_LOG_USE_CONFIG_HEADER
#include "zf_log_config.h"
#endif
/* When defined, Android log (android/log.h) will be used by default instead of
* stderr (ignored on non-Android platforms). Date, time, pid and tid (context)
* will be provided by Android log. Android log features will be used to output
* log level and tag.
*/
#ifdef ZF_LOG_USE_ANDROID_LOG
#undef ZF_LOG_USE_ANDROID_LOG
#if defined(__ANDROID__)
#define ZF_LOG_USE_ANDROID_LOG 1
#else
#define ZF_LOG_USE_ANDROID_LOG 0
#endif
#else
#define ZF_LOG_USE_ANDROID_LOG 0
#endif
/* When defined, NSLog (uses Apple System Log) will be used instead of stderr
* (ignored on non-Apple platforms). Date, time, pid and tid (context) will be
* provided by NSLog. Curiously, doesn't use NSLog() directly, but piggybacks on
* non-public CFLog() function. Both use Apple System Log internally, but it's
* easier to call CFLog() from C than NSLog(). Current implementation doesn't
* support "%@" format specifier.
*/
#ifdef ZF_LOG_USE_NSLOG
#undef ZF_LOG_USE_NSLOG
#if defined(__APPLE__) && defined(__MACH__)
#define ZF_LOG_USE_NSLOG 1
#else
#define ZF_LOG_USE_NSLOG 0
#endif
#else
#define ZF_LOG_USE_NSLOG 0
#endif
/* When defined, OutputDebugString() will be used instead of stderr (ignored on
* non-Windows platforms). Uses OutputDebugStringA() variant and feeds it with
* UTF-8 data.
*/
#ifdef ZF_LOG_USE_DEBUGSTRING
#undef ZF_LOG_USE_DEBUGSTRING
#if defined(_WIN32) || defined(_WIN64)
#define ZF_LOG_USE_DEBUGSTRING 1
#else
#define ZF_LOG_USE_DEBUGSTRING 0
#endif
#else
#define ZF_LOG_USE_DEBUGSTRING 0
#endif
/* When defined, zf_log library will not contain definition of tag prefix
* variable. In that case it must be defined elsewhere using
* ZF_LOG_DEFINE_TAG_PREFIX macro, for example:
*
* ZF_LOG_DEFINE_TAG_PREFIX = "ProcessName";
*
* This allows to specify custom value for static initialization and avoid
* overhead of setting this value in runtime.
*/
#ifdef ZF_LOG_EXTERN_TAG_PREFIX
#undef ZF_LOG_EXTERN_TAG_PREFIX
#define ZF_LOG_EXTERN_TAG_PREFIX 1
#else
#define ZF_LOG_EXTERN_TAG_PREFIX 0
#endif
/* When defined, zf_log library will not contain definition of global format
* variable. In that case it must be defined elsewhere using
* ZF_LOG_DEFINE_GLOBAL_FORMAT macro, for example:
*
* ZF_LOG_DEFINE_GLOBAL_FORMAT = {MEM_WIDTH};
*
* This allows to specify custom value for static initialization and avoid
* overhead of setting this value in runtime.
*/
#ifdef ZF_LOG_EXTERN_GLOBAL_FORMAT
#undef ZF_LOG_EXTERN_GLOBAL_FORMAT
#define ZF_LOG_EXTERN_GLOBAL_FORMAT 1
#else
#define ZF_LOG_EXTERN_GLOBAL_FORMAT 0
#endif
/* When defined, zf_log library will not contain definition of global output
* variable. In that case it must be defined elsewhere using
* ZF_LOG_DEFINE_GLOBAL_OUTPUT macro, for example:
*
* ZF_LOG_DEFINE_GLOBAL_OUTPUT = {ZF_LOG_PUT_STD, custom_output_callback};
*
* This allows to specify custom value for static initialization and avoid
* overhead of setting this value in runtime.
*/
#ifdef ZF_LOG_EXTERN_GLOBAL_OUTPUT
#undef ZF_LOG_EXTERN_GLOBAL_OUTPUT
#define ZF_LOG_EXTERN_GLOBAL_OUTPUT 1
#else
#define ZF_LOG_EXTERN_GLOBAL_OUTPUT 0
#endif
/* When defined, zf_log library will not contain definition of global output
* level variable. In that case it must be defined elsewhere using
* ZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL macro, for example:
*
* ZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = ZF_LOG_WARN;
*
* This allows to specify custom value for static initialization and avoid
* overhead of setting this value in runtime.
*/
#ifdef ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
#undef ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL
#define ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 1
#else
#define ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 0
#endif
/* When defined, implementation will prefer smaller code size over speed.
* Very rough estimate is that code will be up to 2x smaller and up to 2x
* slower. Disabled by default.
*/
#ifdef ZF_LOG_OPTIMIZE_SIZE
#undef ZF_LOG_OPTIMIZE_SIZE
#define ZF_LOG_OPTIMIZE_SIZE 1
#else
#define ZF_LOG_OPTIMIZE_SIZE 0
#endif
/* Size of the log line buffer. The buffer is allocated on stack. It limits
* maximum length of a log line.
*/
#ifndef ZF_LOG_BUF_SZ
#define ZF_LOG_BUF_SZ 512
#endif
/* Default number of bytes in one line of memory output. For large values
* ZF_LOG_BUF_SZ also must be increased.
*/
#ifndef ZF_LOG_MEM_WIDTH
#define ZF_LOG_MEM_WIDTH 32
#endif
/* String to put in the end of each log line (can be empty). Its value used by
* stderr output callback. Its size used as a default value for ZF_LOG_EOL_SZ.
*/
#ifndef ZF_LOG_EOL
#define ZF_LOG_EOL "\n"
#endif
/* Default delimiter that separates parts of log message. Can NOT contain '%'
* or '\0'.
*
* Log message format specifications can override (or ignore) this value. For
* more details see ZF_LOG_MESSAGE_CTX_FORMAT, ZF_LOG_MESSAGE_SRC_FORMAT and
* ZF_LOG_MESSAGE_TAG_FORMAT.
*/
#ifndef ZF_LOG_DEF_DELIMITER
#define ZF_LOG_DEF_DELIMITER " "
#endif
/* Specifies log message context format. Log message context includes date,
* time, process id, thread id and message's log level. Custom information can
* be added as well. Supported fields: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND,
* MILLISECOND, PID, TID, LEVEL, S(str), F_INIT(statements),
* F_UINT(width, value).
*
* Must be defined as a tuple, for example:
*
* #define ZF_LOG_MESSAGE_CTX_FORMAT (YEAR, S("."), MONTH, S("."), DAY, S(" > "))
*
* In that case, resulting log message will be:
*
* 2016.12.22 > TAG function@filename.c:line Message text
*
* Note, that tag, source location and message text are not impacted by
* this setting. See ZF_LOG_MESSAGE_TAG_FORMAT and ZF_LOG_MESSAGE_SRC_FORMAT.
*
* If message context must be visually separated from the rest of the message,
* it must be reflected in context format (notice trailing S(" > ") in the
* example above).
*
* S(str) adds constant string str. String can NOT contain '%' or '\0'.
*
* F_INIT(statements) adds initialization statement(s) that will be evaluated
* once for each log message. All statements are evaluated in specified order.
* Several F_INIT() fields can be used in every log message format
* specification. Fields, like F_UINT(width, value), are allowed to use results
* of initialization statements. If statement introduces variables (or other
* names, like structures) they must be prefixed with "f_". Statements must be
* enclosed into additional "()". Example:
*
* #define ZF_LOG_MESSAGE_CTX_FORMAT \
* (F_INIT(( struct rusage f_ru; getrusage(RUSAGE_SELF, &f_ru); )), \
* YEAR, S("."), MONTH, S("."), DAY, S(" "), \
* F_UINT(5, f_ru.ru_nsignals), \
* S(" "))
*
* F_UINT(width, value) adds unsigned integer value extended with up to width
* spaces (for alignment purposes). Value can be any expression that evaluates
* to unsigned integer. If expression contains non-standard functions, they
* must be declared with F_INIT(). Example:
*
* #define ZF_LOG_MESSAGE_CTX_FORMAT \
* (YEAR, S("."), MONTH, S("."), DAY, S(" "), \
* F_INIT(( unsigned tickcount(); )), \
* F_UINT(5, tickcount()), \
* S(" "))
*
* Other log message format specifications follow same rules, but have a
* different set of supported fields.
*/
#ifndef ZF_LOG_MESSAGE_CTX_FORMAT
#define ZF_LOG_MESSAGE_CTX_FORMAT \
(MONTH, S("-"), DAY, S(ZF_LOG_DEF_DELIMITER), \
HOUR, S(":"), MINUTE, S(":"), SECOND, S("."), MILLISECOND, S(ZF_LOG_DEF_DELIMITER), \
PID, S(ZF_LOG_DEF_DELIMITER), TID, S(ZF_LOG_DEF_DELIMITER), \
LEVEL, S(ZF_LOG_DEF_DELIMITER))
#endif
/* Specifies log message tag format. It includes tag prefix and tag. Custom
* information can be added as well. Supported fields:
* TAG(prefix_delimiter, tag_delimiter), S(str), F_INIT(statements),
* F_UINT(width, value).
*
* TAG(prefix_delimiter, tag_delimiter) adds following string to log message:
*
* PREFIX<prefix_delimiter>TAG<tag_delimiter>
*
* Prefix delimiter will be used only when prefix is not empty. Tag delimiter
* will be used only when prefixed tag is not empty. Example:
*
* #define ZF_LOG_TAG_FORMAT (S("["), TAG(".", ""), S("] "))
*
* See ZF_LOG_MESSAGE_CTX_FORMAT for details.
*/
#ifndef ZF_LOG_MESSAGE_TAG_FORMAT
#define ZF_LOG_MESSAGE_TAG_FORMAT \
(TAG(".", ZF_LOG_DEF_DELIMITER))
#endif
/* Specifies log message source location format. It includes function name,
* file name and file line. Custom information can be added as well. Supported
* fields: FUNCTION, FILENAME, FILELINE, S(str), F_INIT(statements),
* F_UINT(width, value).
*
* See ZF_LOG_MESSAGE_CTX_FORMAT for details.
*/
#ifndef ZF_LOG_MESSAGE_SRC_FORMAT
#define ZF_LOG_MESSAGE_SRC_FORMAT \
(FUNCTION, S("@"), FILENAME, S(":"), FILELINE, S(ZF_LOG_DEF_DELIMITER))
#endif
/* Fields that can be used in log message format specifications (see above).
* Mentioning them here explicitly, so we know that nobody else defined them
* before us. See ZF_LOG_MESSAGE_CTX_FORMAT for details.
*/
#define YEAR YEAR
#define MONTH MONTH
#define DAY DAY
#define MINUTE MINUTE
#define SECOND SECOND
#define MILLISECOND MILLISECOND
#define PID PID
#define TID TID
#define LEVEL LEVEL
#define TAG(prefix_delim, tag_delim) TAG(prefix_delim, tag_delim)
#define FUNCTION FUNCTION
#define FILENAME FILENAME
#define FILELINE FILELINE
#define S(str) S(str)
#define F_INIT(statements) F_INIT(statements)
#define F_UINT(width, value) F_UINT(width, value)
/* To use custom `vsnprintf()` function, define `ZF_LOG_CUSTOM_VSNPRINTF` to have its name. Example:
* #define ZF_LOG_CUSTOM_VSNPRINTF my_vsnprintf
*/
#ifdef ZF_LOG_CUSTOM_VSNPRINTF
#define _ZF_LOG_VSNPRINTF ZF_LOG_CUSTOM_VSNPRINTF
#endif
/* To use custom `snprintf()` function, define `ZF_LOG_CUSTOM_SNPRINTF` to have its name. Example:
* #define ZF_LOG_CUSTOM_SNPRINTF my_snprintf
* Note, that it only will be used when `ZF_LOG_OPTIMIZE_SIZE` is enabled.
*/
#ifdef ZF_LOG_CUSTOM_SNPRINTF
#define _ZF_LOG_SNPRINTF ZF_LOG_CUSTOM_SNPRINTF
#endif
/* Number of bytes to reserve for EOL in the log line buffer (must be >0).
* Must be larger than or equal to length of ZF_LOG_EOL with terminating null.
*/
#ifndef ZF_LOG_EOL_SZ
#define ZF_LOG_EOL_SZ sizeof(ZF_LOG_EOL)
#endif
/* Compile instrumented version of the library to facilitate unit testing.
*/
#ifndef ZF_LOG_INSTRUMENTED
#define ZF_LOG_INSTRUMENTED 0
#endif
#if defined(__linux__)
#if !defined(__ANDROID__) && !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
#endif
#if defined(__MINGW32__)
#ifdef __STRICT_ANSI__
#undef __STRICT_ANSI__
#endif
#endif
#include <assert.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include "zf_log.h"
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <unistd.h>
#include <sys/time.h>
#if defined(__linux__)
#include <linux/limits.h>
#elif defined(_AIX) || defined(__CYGWIN__)
#include <limits.h>
#else
#include <sys/syslimits.h>
#endif
#endif
#if defined(__linux__)
#include <sys/prctl.h>
#include <sys/types.h>
#if !defined(__ANDROID__)
#include <sys/syscall.h>
#endif
#endif
#if defined(__MACH__) || defined(_AIX)
#include <pthread.h>
#endif
#define INLINE _ZF_LOG_INLINE
#define VAR_UNUSED(var) (void)var
#define RETVAL_UNUSED(expr) do { while(expr) break; } while(0)
#define STATIC_ASSERT(name, cond) \
typedef char assert_##name[(cond)? 1: -1]
#define ASSERT_UNREACHABLE(why) assert(!sizeof(why))
#ifndef _countof
#define _countof(xs) (sizeof(xs) / sizeof((xs)[0]))
#endif
#if ZF_LOG_INSTRUMENTED
#define INSTRUMENTED_CONST
#else
#define INSTRUMENTED_CONST const
#endif
#define _PP_PASTE_2(a, b) a ## b
#define _PP_CONCAT_2(a, b) _PP_PASTE_2(a, b)
#define _PP_PASTE_3(a, b, c) a ## b ## c
#define _PP_CONCAT_3(a, b, c) _PP_PASTE_3(a, b, c)
/* Microsoft C preprocessor is a piece of shit. This moron treats __VA_ARGS__
* as a single token and requires additional expansion to realize that it's
* actually a list. If not for it, there would be no need in this extra
* expansion.
*/
#define _PP_ID(x) x
#define _PP_NARGS_N(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,...) _24
#define _PP_NARGS(...) _PP_ID(_PP_NARGS_N(__VA_ARGS__,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0))
/* There is a more efficient way to implement this, but it requires
* working C preprocessor. Unfortunately, Microsoft Visual Studio doesn't
* have one.
*/
#define _PP_HEAD__(x, ...) x
#define _PP_HEAD_(...) _PP_ID(_PP_HEAD__(__VA_ARGS__, ~))
#define _PP_HEAD(xs) _PP_HEAD_ xs
#define _PP_TAIL_(x, ...) (__VA_ARGS__)
#define _PP_TAIL(xs) _PP_TAIL_ xs
#define _PP_UNTUPLE_(...) __VA_ARGS__
#define _PP_UNTUPLE(xs) _PP_UNTUPLE_ xs
/* Apply function macro to each element in tuple. Output is not
* enforced to be a tuple.
*/
#define _PP_MAP_1(f, xs) f(_PP_HEAD(xs))
#define _PP_MAP_2(f, xs) f(_PP_HEAD(xs)) _PP_MAP_1(f, _PP_TAIL(xs))
#define _PP_MAP_3(f, xs) f(_PP_HEAD(xs)) _PP_MAP_2(f, _PP_TAIL(xs))
#define _PP_MAP_4(f, xs) f(_PP_HEAD(xs)) _PP_MAP_3(f, _PP_TAIL(xs))
#define _PP_MAP_5(f, xs) f(_PP_HEAD(xs)) _PP_MAP_4(f, _PP_TAIL(xs))
#define _PP_MAP_6(f, xs) f(_PP_HEAD(xs)) _PP_MAP_5(f, _PP_TAIL(xs))
#define _PP_MAP_7(f, xs) f(_PP_HEAD(xs)) _PP_MAP_6(f, _PP_TAIL(xs))
#define _PP_MAP_8(f, xs) f(_PP_HEAD(xs)) _PP_MAP_7(f, _PP_TAIL(xs))
#define _PP_MAP_9(f, xs) f(_PP_HEAD(xs)) _PP_MAP_8(f, _PP_TAIL(xs))
#define _PP_MAP_10(f, xs) f(_PP_HEAD(xs)) _PP_MAP_9(f, _PP_TAIL(xs))
#define _PP_MAP_11(f, xs) f(_PP_HEAD(xs)) _PP_MAP_10(f, _PP_TAIL(xs))
#define _PP_MAP_12(f, xs) f(_PP_HEAD(xs)) _PP_MAP_11(f, _PP_TAIL(xs))
#define _PP_MAP_13(f, xs) f(_PP_HEAD(xs)) _PP_MAP_12(f, _PP_TAIL(xs))
#define _PP_MAP_14(f, xs) f(_PP_HEAD(xs)) _PP_MAP_13(f, _PP_TAIL(xs))
#define _PP_MAP_15(f, xs) f(_PP_HEAD(xs)) _PP_MAP_14(f, _PP_TAIL(xs))
#define _PP_MAP_16(f, xs) f(_PP_HEAD(xs)) _PP_MAP_15(f, _PP_TAIL(xs))
#define _PP_MAP_17(f, xs) f(_PP_HEAD(xs)) _PP_MAP_16(f, _PP_TAIL(xs))
#define _PP_MAP_18(f, xs) f(_PP_HEAD(xs)) _PP_MAP_17(f, _PP_TAIL(xs))
#define _PP_MAP_19(f, xs) f(_PP_HEAD(xs)) _PP_MAP_18(f, _PP_TAIL(xs))
#define _PP_MAP_20(f, xs) f(_PP_HEAD(xs)) _PP_MAP_19(f, _PP_TAIL(xs))
#define _PP_MAP_21(f, xs) f(_PP_HEAD(xs)) _PP_MAP_20(f, _PP_TAIL(xs))
#define _PP_MAP_22(f, xs) f(_PP_HEAD(xs)) _PP_MAP_21(f, _PP_TAIL(xs))
#define _PP_MAP_23(f, xs) f(_PP_HEAD(xs)) _PP_MAP_22(f, _PP_TAIL(xs))
#define _PP_MAP_24(f, xs) f(_PP_HEAD(xs)) _PP_MAP_23(f, _PP_TAIL(xs))
#define _PP_MAP(f, xs) _PP_CONCAT_2(_PP_MAP_, _PP_NARGS xs) (f, xs)
/* Apply function macro to each element in tuple in reverse order.
* Output is not enforced to be a tuple.
*/
#define _PP_RMAP_1(f, xs) f(_PP_HEAD(xs))
#define _PP_RMAP_2(f, xs) _PP_RMAP_1(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_3(f, xs) _PP_RMAP_2(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_4(f, xs) _PP_RMAP_3(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_5(f, xs) _PP_RMAP_4(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_6(f, xs) _PP_RMAP_5(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_7(f, xs) _PP_RMAP_6(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_8(f, xs) _PP_RMAP_7(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_9(f, xs) _PP_RMAP_8(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_10(f, xs) _PP_RMAP_9(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_11(f, xs) _PP_RMAP_10(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_12(f, xs) _PP_RMAP_11(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_13(f, xs) _PP_RMAP_12(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_14(f, xs) _PP_RMAP_13(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_15(f, xs) _PP_RMAP_14(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_16(f, xs) _PP_RMAP_15(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_17(f, xs) _PP_RMAP_16(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_18(f, xs) _PP_RMAP_17(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_19(f, xs) _PP_RMAP_18(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_20(f, xs) _PP_RMAP_19(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_21(f, xs) _PP_RMAP_20(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_22(f, xs) _PP_RMAP_21(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_23(f, xs) _PP_RMAP_22(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP_24(f, xs) _PP_RMAP_23(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))
#define _PP_RMAP(f, xs) _PP_CONCAT_2(_PP_RMAP_, _PP_NARGS xs) (f, xs)
/* Used to implement _ZF_LOG_MESSAGE_FORMAT_CONTAINS() macro. All possible
* fields must be mentioned here. Not counting F_INIT() here because it's
* somewhat special and is handled spearatly (at least for now).
*/
#define _ZF_LOG_MESSAGE_FORMAT_MASK__ (0<<0)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__YEAR (1<<1)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__MONTH (1<<2)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__DAY (1<<3)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__HOUR (1<<4)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__MINUTE (1<<5)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__SECOND (1<<6)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__MILLISECOND (1<<7)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__PID (1<<8)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__TID (1<<9)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__LEVEL (1<<10)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__TAG(ps, ts) (1<<11)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__FUNCTION (1<<12)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__FILENAME (1<<13)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__FILELINE (1<<14)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__S(s) (1<<15)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__F_INIT(expr) (0<<16)
#define _ZF_LOG_MESSAGE_FORMAT_MASK__F_UINT(w, v) (1<<17)
#define _ZF_LOG_MESSAGE_FORMAT_MASK(field) \
_PP_CONCAT_3(_ZF_LOG_MESSAGE_FORMAT_MASK_, _, field)
/* Logical "or" of masks of fields used in specified format specification.
*/
#define _ZF_LOG_MESSAGE_FORMAT_FIELDS(format) \
(0 _PP_MAP(| _ZF_LOG_MESSAGE_FORMAT_MASK, format))
/* Expands to expressions that evaluates to true if field is used in
* specified format specification. Example:
*
* #if _ZF_LOG_MESSAGE_FORMAT_CONTAINS(F_UINT,
gitextract_z8twfn65/ ├── .appveyor.yml ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── TODO.md ├── examples/ │ ├── CMakeLists.txt │ ├── args_eval.c │ ├── custom_output.c │ ├── file_output.c │ └── hello.c ├── tests/ │ ├── CMakeLists.txt │ ├── filesize_check.c │ ├── perf/ │ │ ├── CMakeLists.txt │ │ ├── run_tests.py │ │ ├── test_executable_size.cpp │ │ ├── test_speed.cpp │ │ ├── test_switch.h │ │ └── time_it.py │ ├── test_aux_spec.c │ ├── test_builtin_output_facilities.c │ ├── test_call_site_size_censoring.c │ ├── test_call_site_size_conditional.c │ ├── test_call_site_size_fmt_args.c │ ├── test_call_site_size_msg_only.c │ ├── test_censoring.c │ ├── test_compilation_cpp.cpp │ ├── test_conditional.c │ ├── test_decoration.main.c │ ├── test_decoration.module.c │ ├── test_externally_defined_state.c │ ├── test_externally_defined_state_cpp.cpp │ ├── test_log_level_override.c │ ├── test_log_level_switches.c │ ├── test_log_message_content.c │ ├── test_private_parts.c │ ├── test_source_location.c │ ├── zf_log.h.master │ └── zf_test.h ├── zf_log/ │ ├── CMakeLists.txt │ ├── zf_log.c │ └── zf_log.h └── zf_log-config.cmake.in
SYMBOL INDEX (188 symbols across 31 files)
FILE: examples/args_eval.c
function call_exit (line 6) | static int call_exit()
function main (line 11) | int main(int argc, char *argv[])
FILE: examples/custom_output.c
function syslog_level (line 12) | static int syslog_level(const int lvl)
function custom_output_callback (line 35) | static void custom_output_callback(const zf_log_message *msg, void *arg)
function main (line 53) | int main(int argc, char *argv[])
FILE: examples/file_output.c
function file_output_callback (line 10) | static void file_output_callback(const zf_log_message *msg, void *arg)
function file_output_close (line 18) | static void file_output_close(void)
function file_output_open (line 23) | static void file_output_open(const char *const log_path)
function main (line 35) | int main(int argc, char *argv[])
FILE: examples/hello.c
function main (line 5) | int main(int argc, char *argv[])
FILE: tests/filesize_check.c
function filesize (line 7) | static long filesize(const char *const path)
function main (line 21) | int main(int argc, const char *argv[])
FILE: tests/perf/run_tests.py
function take_first (line 11) | def take_first(value):
function take_order (line 16) | def take_order(value, order):
function take_map (line 22) | def take_map(value, keys, vals):
function take_best (line 30) | def take_best(values, key, compare, reverse=False):
function take_plural (line 39) | def take_plural(count, base, suffix):
function take_threads_variants (line 44) | def take_threads_variants():
function _cmp_percentage (line 57) | def _cmp_percentage(p, key, a, b):
function cmp_percentage (line 64) | def cmp_percentage(p, key):
function translate_test (line 67) | def translate_test(test):
function translate_subj (line 91) | def translate_subj(subj):
function translation_sort_key (line 98) | def translation_sort_key(v):
function translation_value (line 101) | def translation_value(v):
class data_cell (line 104) | class data_cell:
method __init__ (line 105) | def __init__(self):
method set_best (line 107) | def set_best(self, best=True):
method ifbest (line 109) | def ifbest(self, a, b):
class data_str (line 114) | class data_str(data_cell):
method __init__ (line 115) | def __init__(self, value):
method __str__ (line 119) | def __str__(self):
method __repr__ (line 121) | def __repr__(self):
class data_bytes (line 124) | class data_bytes(data_cell):
method __init__ (line 125) | def __init__(self, value):
method __str__ (line 129) | def __str__(self):
method __repr__ (line 135) | def __repr__(self):
class data_seconds (line 138) | class data_seconds(data_cell):
method __init__ (line 139) | def __init__(self, value):
method __str__ (line 143) | def __str__(self):
method __repr__ (line 145) | def __repr__(self):
class data_freq (line 148) | class data_freq(data_cell):
method __init__ (line 149) | def __init__(self, count, seconds):
method __str__ (line 156) | def __str__(self):
method __repr__ (line 158) | def __repr__(self):
method freq (line 160) | def freq(self):
function get_table_data (line 163) | def get_table_data(result):
function gen_table_ascii (line 206) | def gen_table_ascii(result):
function gen_table_markdown (line 231) | def gen_table_markdown(result):
function run_call_site_size (line 265) | def run_call_site_size(params, result):
function run_executable_size (line 285) | def run_executable_size(params, result):
function run_build_time (line 302) | def run_build_time(params, result, id, optional=False):
function run_speed (line 319) | def run_speed(params, result, threads_variants, seconds=1):
function run_tests (line 339) | def run_tests(params):
function main (line 348) | def main(argv):
FILE: tests/perf/test_executable_size.cpp
function main (line 3) | int main(int argc, char *argv[])
FILE: tests/perf/test_speed.cpp
class thread_latch (line 14) | class thread_latch
method thread_latch (line 17) | thread_latch(): _go(false), _halt(false) {}
class thread_group (line 55) | class thread_group
class bench (line 105) | class bench
method bench (line 108) | bench() {}
function main (line 132) | int main(int argc, char *argv[])
FILE: tests/perf/test_switch.h
function XLOG_SLOW_FUNC (line 40) | static int XLOG_SLOW_FUNC()
function XLOG_INIT (line 80) | static void XLOG_INIT()
function class (line 99) | class null_sink: public spdlog::sinks::sink
function XLOG_INIT (line 118) | static void XLOG_INIT()
function class (line 134) | class null_stream {
function XLOG_INIT (line 161) | static void XLOG_INIT()
function class (line 181) | class null_sink
function XLOG_INIT (line 205) | static void XLOG_INIT()
function class (line 223) | class null_sink: public google::LogSink
function XLOG_INIT (line 243) | static void XLOG_INIT()
FILE: tests/perf/time_it.py
function usage (line 8) | def usage(f, st):
function main (line 14) | def main(argv):
FILE: tests/test_aux_spec.c
function mock_output_callback (line 10) | static void mock_output_callback(const zf_log_message *msg, void *arg)
function main (line 15) | int main(int argc, char *argv[])
FILE: tests/test_builtin_output_facilities.c
function main (line 12) | int main(int argc, char *argv[])
FILE: tests/test_call_site_size_censoring.c
function log_some (line 9) | static void log_some()
function main (line 29) | int main(int argc, char *argv[])
FILE: tests/test_call_site_size_conditional.c
function log_some (line 15) | static void log_some()
function main (line 35) | int main(int argc, char *argv[])
FILE: tests/test_call_site_size_fmt_args.c
function log_some (line 12) | static void log_some()
function main (line 528) | int main(int argc, char *argv[])
FILE: tests/test_call_site_size_msg_only.c
function log_some (line 5) | static void log_some()
function main (line 521) | int main(int argc, char *argv[])
FILE: tests/test_censoring.c
function mock_output_callback (line 6) | static void mock_output_callback(const zf_log_message *msg, void *arg)
function was_logged (line 12) | static unsigned was_logged()
function some_function_0 (line 19) | static void some_function_0()
function some_function_1 (line 24) | static void some_function_1(const unsigned d)
function test_censoring (line 36) | static void test_censoring()
function main (line 67) | int main(int argc, char *argv[])
FILE: tests/test_compilation_cpp.cpp
function mock_output_callback (line 5) | void mock_output_callback(const zf_log_message *, void *)
function main (line 10) | int main(int argc, char *argv[])
FILE: tests/test_conditional.c
function mock_output_callback (line 10) | static void mock_output_callback(const zf_log_message *msg, void *arg)
function was_logged (line 16) | static unsigned was_logged()
function forty_two (line 23) | static unsigned forty_two()
function test_conditional (line 30) | static void test_conditional()
function main (line 53) | int main(int argc, char *argv[])
FILE: tests/test_decoration.main.c
function main_output_callback (line 8) | static void main_output_callback(const zf_log_message *msg, void *arg)
function test_main (line 21) | void test_main()
function main (line 32) | int main(int argc, char *argv[])
FILE: tests/test_decoration.module.c
function module_output_callback (line 9) | static void module_output_callback(const zf_log_message *msg, void *arg)
function test_module (line 20) | void test_module()
FILE: tests/test_externally_defined_state.c
function mock_output_callback (line 24) | static void mock_output_callback(const zf_log_message *msg, void *arg)
function test_static_initialization (line 29) | static void test_static_initialization()
function main (line 41) | int main(int argc, char *argv[])
FILE: tests/test_externally_defined_state_cpp.cpp
function mock_output_callback (line 14) | void mock_output_callback(const zf_log_message *, void *)
function main (line 19) | int main(int argc, char *argv[])
FILE: tests/test_log_level_override.c
function test_level_checks (line 19) | static void test_level_checks()
function main (line 38) | int main(int argc, char *argv[])
FILE: tests/test_log_level_switches.c
function reset (line 26) | static void reset()
function mock_output_callback (line 33) | static void mock_output_callback(const zf_log_message *msg, void *arg)
function get_arg (line 42) | static int get_arg()
function test_current_level (line 48) | static void test_current_level()
function test_output_level (line 76) | static void test_output_level()
function test_args_evaluation (line 120) | static void test_args_evaluation()
function test_level_checks (line 177) | static void test_level_checks()
function main (line 207) | int main(int argc, char *argv[])
FILE: tests/test_log_message_content.c
function memchk (line 85) | static size_t memchk(const void *const b, const int c, const size_t sz)
function common_prefix (line 95) | static size_t common_prefix(const char *const s1, const size_t s1_len,
function reset (line 105) | static void reset()
function mock_time_callback (line 117) | static void mock_time_callback(struct tm *const tm, unsigned *const msec)
function mock_pid_callback (line 129) | static void mock_pid_callback(int *const pid, int *const tid)
function mock_buffer_callback (line 135) | static void mock_buffer_callback(zf_log_message *msg, char *buf)
function mock_output_callback (line 141) | static void mock_output_callback(const zf_log_message *msg, void *arg)
function verify_log_output (line 159) | static void verify_log_output(const size_t buf_sz,
function test_msg_output (line 216) | static void test_msg_output()
function test_mem_output (line 229) | static void test_mem_output()
function init_expected_lines (line 243) | static void init_expected_lines()
function main (line 276) | int main(int argc, char *argv[])
FILE: tests/test_private_parts.c
type put_padding_r_testcase (line 11) | typedef struct put_padding_r_testcase
function test_put_padding_r (line 30) | static void test_put_padding_r()
function main (line 44) | int main(int argc, char *argv[])
FILE: tests/test_source_location.c
function mock_output_callback (line 23) | static void mock_output_callback(const zf_log_message *msg, void *arg)
function test_function (line 32) | static void test_function()
function main (line 53) | int main(int argc, char *argv[])
FILE: tests/zf_test.h
function _ZF_TEST_INLINE (line 20) | static _ZF_TEST_INLINE bool _zf_test_bool(const bool v)
FILE: zf_log/zf_log.c
function fake_vsnprintf (line 492) | static int fake_vsnprintf(char *s, size_t sz, const char *fmt, va_list ap)
function fake_snprintf (line 506) | static int fake_snprintf(char *s, size_t sz, const char *fmt, ...)
type tm (line 521) | struct tm
type src_location (line 525) | typedef struct src_location
type mem_block (line 533) | typedef struct mem_block
type tm (line 540) | struct tm
function INLINE (line 560) | static INLINE int android_lvl(const int lvl)
function out_android_callback (line 582) | static void out_android_callback(const zf_log_message *const msg, void *...
function INLINE (line 603) | static INLINE int apple_lvl(const int lvl)
function out_nslog_callback (line 625) | static void out_nslog_callback(const zf_log_message *const msg, void *arg)
function out_debugstring_callback (line 639) | static void out_debugstring_callback(const zf_log_message *const msg, vo...
function zf_log_out_stderr_callback (line 651) | void zf_log_out_stderr_callback(const zf_log_message *const msg, void *arg)
function lvl_char (line 708) | static char lvl_char(const int lvl)
type timeval (line 752) | struct timeval
type tm (line 754) | struct tm
function INLINE (line 756) | static INLINE int tcache_get(const struct timeval *const tv, struct tm *...
function INLINE (line 778) | static INLINE void tcache_set(const struct timeval *const tv, struct tm ...
function time_callback (line 791) | static void time_callback(struct tm *const tm, unsigned *const msec)
function pid_callback (line 825) | static void pid_callback(int *const pid, int *const tid)
function buffer_callback (line 859) | static void buffer_callback(zf_log_message *msg, char *buf)
function INLINE (line 886) | static INLINE size_t nprintf_size(zf_log_message *const msg)
function INLINE (line 898) | static INLINE void put_nprintf(zf_log_message *const msg, const int n)
function INLINE (line 906) | static INLINE char *put_padding_r(const unsigned w, const char wc,
function INLINE (line 931) | static INLINE char *put_uint_r(const unsigned v, const unsigned w, const...
function INLINE (line 937) | static INLINE char *put_int_r(const int v, const unsigned w, const char wc,
function INLINE (line 944) | static INLINE char *put_stringn(const char *const s_p, const char *const...
function INLINE (line 957) | static INLINE char *put_string(const char *s, char *p, char *const e)
function INLINE (line 964) | static INLINE char *put_uint(unsigned v, const unsigned w, const char wc,
function put_ctx (line 1081) | static void put_ctx(zf_log_message *const msg)
function put_tag (line 1156) | static void put_tag(zf_log_message *const msg, const char *const tag)
function put_src (line 1169) | static void put_src(zf_log_message *const msg, const src_location *const...
function put_msg (line 1192) | static void put_msg(zf_log_message *const msg,
function output_mem (line 1201) | static void output_mem(const zf_log_spec *log, zf_log_message *const msg,
function zf_log_set_tag_prefix (line 1240) | void zf_log_set_tag_prefix(const char *const prefix)
function zf_log_set_mem_width (line 1245) | void zf_log_set_mem_width(const unsigned w)
function zf_log_set_output_level (line 1250) | void zf_log_set_output_level(const int lvl)
function zf_log_set_output_v (line 1255) | void zf_log_set_output_v(const unsigned mask, void *const arg,
function _zf_log_write_imp (line 1263) | static void _zf_log_write_imp(
function _zf_log_write_d (line 1297) | void _zf_log_write_d(
function _zf_log_write_aux_d (line 1309) | void _zf_log_write_aux_d(
function _zf_log_write (line 1321) | void _zf_log_write(const int lvl, const char *const tag,
function _zf_log_write_aux (line 1330) | void _zf_log_write_aux(
function _zf_log_write_mem_d (line 1340) | void _zf_log_write_mem_d(
function _zf_log_write_mem_aux_d (line 1354) | void _zf_log_write_mem_aux_d(
function _zf_log_write_mem (line 1368) | void _zf_log_write_mem(const int lvl, const char *const tag,
function _zf_log_write_mem_aux (line 1379) | void _zf_log_write_mem_aux(
FILE: zf_log/zf_log.h
type zf_log_message (line 508) | typedef struct zf_log_message
type zf_log_format (line 531) | typedef struct zf_log_format
type zf_log_output (line 539) | typedef struct zf_log_output
function _ZF_LOG_INLINE (line 554) | static _ZF_LOG_INLINE void zf_log_set_output_p(const zf_log_output *cons...
type zf_log_spec (line 573) | typedef struct zf_log_spec
function _ZF_LOG_INLINE (line 799) | static _ZF_LOG_INLINE void _zf_log_unused(const int dummy, ...) {(void)d...
Condensed preview — 44 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (280K chars).
[
{
"path": ".appveyor.yml",
"chars": 1578,
"preview": "version: 0.3.1-{build}\n\nenvironment:\n matrix:\n - GENERATOR: \"Visual Studio 12\"\n CONFIG: Release\n OPTIONS: -DZF_L"
},
{
"path": ".gitignore",
"chars": 36,
"preview": "/build.*\n/CMakeLists.txt.user\n/tags\n"
},
{
"path": ".travis.yml",
"chars": 1196,
"preview": "language: c++\n\ncompiler:\n- clang\n- gcc\n\nos:\n- osx\n\nenv:\n - OPTIONS=\"-DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON -D"
},
{
"path": "CMakeLists.txt",
"chars": 1750,
"preview": "cmake_minimum_required(VERSION 3.2)\n\nset(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)\nif(NOT DEFINE"
},
{
"path": "LICENSE",
"chars": 1078,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2017 wonder-mice\n\nPermission is hereby granted, free of charge, to any person obtai"
},
{
"path": "README.md",
"chars": 12275,
"preview": "[](https://travis-ci.org/wonder-mice/zf_log)\n"
},
{
"path": "TODO.md",
"chars": 1910,
"preview": "Things to do\n------------\n\n* Add callback arg to output callback\n* Update README, it sucks now\n* Print start address for"
},
{
"path": "examples/CMakeLists.txt",
"chars": 703,
"preview": "cmake_minimum_required(VERSION 3.2)\n\nset(CMAKE_C_STANDARD 99)\nset(CMAKE_C_STANDARD_REQUIRED ON)\nset(CMAKE_C_EXTENSIONS O"
},
{
"path": "examples/args_eval.c",
"chars": 972,
"preview": "#include <signal.h>\n#include <stdlib.h>\n#define ZF_LOG_LEVEL ZF_LOG_INFO\n#include <zf_log.h>\n\nstatic int call_exit()\n{\n\t"
},
{
"path": "examples/custom_output.c",
"chars": 1634,
"preview": "#include <assert.h>\n#if defined(_WIN32) || defined(_WIN64)\n\t#include <windows.h>\n\t#define OUTPUT_DEBUG_STRING\n#else\n\t#in"
},
{
"path": "examples/file_output.c",
"chars": 884,
"preview": "#if defined(_WIN32) || defined(_WIN64)\n\t#define _CRT_SECURE_NO_WARNINGS\n#endif\n#include <stdio.h>\n#include <stdlib.h>\n#i"
},
{
"path": "examples/hello.c",
"chars": 635,
"preview": "#define ZF_LOG_LEVEL ZF_LOG_INFO\n#define ZF_LOG_TAG \"MAIN\"\n#include <zf_log.h>\n\nint main(int argc, char *argv[])\n{\n\tzf_l"
},
{
"path": "tests/CMakeLists.txt",
"chars": 9820,
"preview": "cmake_minimum_required(VERSION 3.2)\n\ninclude(CMakeParseArguments)\n\nset(CMAKE_C_STANDARD 99)\nset(CMAKE_C_STANDARD_REQUIRE"
},
{
"path": "tests/filesize_check.c",
"chars": 688,
"preview": "#if defined(_WIN32) || defined(_WIN64)\n\t#define _CRT_SECURE_NO_WARNINGS\n#endif\n#include <stdio.h>\n#include <stdlib.h>\n\ns"
},
{
"path": "tests/perf/CMakeLists.txt",
"chars": 13759,
"preview": "cmake_minimum_required(VERSION 3.2)\n\ninclude(ExternalProject)\ninclude(CMakeParseArguments)\nset(THREADS_PREFER_PTHREAD_FL"
},
{
"path": "tests/perf/run_tests.py",
"chars": 11365,
"preview": "#!/usr/bin/python\n\nimport sys\nimport os\nimport argparse\nimport subprocess\nimport multiprocessing\nimport json\nimport ppri"
},
{
"path": "tests/perf/test_executable_size.cpp",
"chars": 338,
"preview": "#include \"test_switch.h\"\n\nint main(int argc, char *argv[])\n{\n\t(void)argc; (void)argv;\n\tXLOG_INIT();\n\tXLOG_STATEMENT();\n#"
},
{
"path": "tests/perf/test_speed.cpp",
"chars": 2819,
"preview": "#include <cstdint>\n#include <cinttypes>\n#include <atomic>\n#include <functional>\n#include <memory>\n#include <vector>\n#inc"
},
{
"path": "tests/perf/test_switch.h",
"chars": 7396,
"preview": "#pragma once\n\n#define TEST_LIBRARY_ID_zf_log 1\n#define TEST_LIBRARY_ID_spdlog 2\n#define TEST_LIBRARY_ID_easylog 3\n#defin"
},
{
"path": "tests/perf/time_it.py",
"chars": 514,
"preview": "#!/usr/bin/python\n\nimport sys\nimport time\nimport subprocess\nimport json\n\ndef usage(f, st):\n\tf.write(\"Usage:\\n\")\n\tf.write"
},
{
"path": "tests/test_aux_spec.c",
"chars": 468,
"preview": "#include <zf_log.c>\n#include <zf_test.h>\n\nstatic const zf_log_spec g_spec =\n{\n\tZF_LOG_GLOBAL_FORMAT,\n\tZF_LOG_GLOBAL_OUTP"
},
{
"path": "tests/test_builtin_output_facilities.c",
"chars": 354,
"preview": "#if defined(_WIN32) || defined(_WIN64)\n\t#define ZF_LOG_USE_DEBUGSTRING\n#endif\n#if defined(__APPLE__) && defined(__MACH__"
},
{
"path": "tests/test_call_site_size_censoring.c",
"chars": 520,
"preview": "#define ZF_LOG_LEVEL ZF_LOG_INFO\n#include <zf_log.h>\n#include <time.h>\n\n#define LOG_SOME_ONCE \\\n\tZF_LOG_SECRET(ZF_LOGI(\""
},
{
"path": "tests/test_call_site_size_conditional.c",
"chars": 610,
"preview": "#define ZF_LOG_LEVEL ZF_LOG_INFO\n#include <zf_log.h>\n#include <time.h>\n\n#if TEST_CONDITION\n\t#define CONDITION 1 < 2\n#els"
},
{
"path": "tests/test_call_site_size_fmt_args.c",
"chars": 22023,
"preview": "#define ZF_LOG_LEVEL ZF_LOG_INFO\n#include <zf_log.h>\n#include <time.h>\n\nint g_int1;\nint g_int2;\nchar *g_str1;\nchar *g_st"
},
{
"path": "tests/test_call_site_size_msg_only.c",
"chars": 12986,
"preview": "#define ZF_LOG_LEVEL ZF_LOG_INFO\n#include <zf_log.h>\n#include <time.h>\n\nstatic void log_some()\n{\n\tZF_LOGI(\"Lorem ipsum d"
},
{
"path": "tests/test_censoring.c",
"chars": 1655,
"preview": "#include <zf_log.c>\n#include <zf_test.h>\n\nstatic unsigned g_logged = 0;\n\nstatic void mock_output_callback(const zf_log_m"
},
{
"path": "tests/test_compilation_cpp.cpp",
"chars": 327,
"preview": "#include <zf_log.c>\n\nnamespace\n{\n\tvoid mock_output_callback(const zf_log_message *, void *)\n\t{\n\t}\n}\n\nint main(int argc, "
},
{
"path": "tests/test_conditional.c",
"chars": 1300,
"preview": "#include <zf_log.c>\n#include <zf_test.h>\n\nstatic unsigned g_logged = 0;\n/* Keep it extern (non-static), so compiler has "
},
{
"path": "tests/test_decoration.main.c",
"chars": 735,
"preview": "#define ZF_LOG_LEVEL ZF_LOG_INFO\n#include <zf_log.c>\n#include <stdlib.h>\n#include <stdio.h>\n\nstatic int main_called;\n\nst"
},
{
"path": "tests/test_decoration.module.c",
"chars": 602,
"preview": "#define ZF_LOG_LEVEL ZF_LOG_INFO\n#define ZF_LOG_LIBRARY_PREFIX module\n#include <zf_log.c>\n#include <stdlib.h>\n#include <"
},
{
"path": "tests/test_externally_defined_state.c",
"chars": 1361,
"preview": "#define ZF_LOG_EXTERN_TAG_PREFIX\n#define ZF_LOG_EXTERN_GLOBAL_FORMAT\n#define ZF_LOG_EXTERN_GLOBAL_OUTPUT\n#define ZF_LOG_"
},
{
"path": "tests/test_externally_defined_state_cpp.cpp",
"chars": 646,
"preview": "#define ZF_LOG_EXTERN_TAG_PREFIX\n#define ZF_LOG_EXTERN_GLOBAL_FORMAT\n#define ZF_LOG_EXTERN_GLOBAL_OUTPUT\n#define ZF_LOG_"
},
{
"path": "tests/test_log_level_override.c",
"chars": 1119,
"preview": "#define ZF_LOG_LEVEL 0\n#define ZF_LOG_OUTPUT_LEVEL g_output_level\n#include <zf_log.c>\n#include <zf_test.h>\n\nstatic const"
},
{
"path": "tests/test_log_level_switches.c",
"chars": 7058,
"preview": "#ifndef ZF_LOG_LEVEL\n\t#error ZF_LOG_LEVEL must be defined for this test\n#endif\n#include <zf_log.c>\n#include <zf_test.h>\n"
},
{
"path": "tests/test_log_message_content.c",
"chars": 8957,
"preview": "#if defined(_WIN32) || defined(_WIN64)\n\t#define _CRT_NONSTDC_NO_WARNINGS\n#endif\n#define ZF_LOG_ANDROID_LOG 0\n#define ZF_"
},
{
"path": "tests/test_private_parts.c",
"chars": 1021,
"preview": "#include <zf_log.c>\n#include <zf_test.h>\n\nstatic char *strcopy_r(const char *s, char *e)\n{\n\te -= strlen(s) + 1;\n\tfor (ch"
},
{
"path": "tests/test_source_location.c",
"chars": 1427,
"preview": "#include <zf_log.c>\n#include <zf_test.h>\n#include <stdio.h>\n\n#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !def"
},
{
"path": "tests/zf_log.h.master",
"chars": 37796,
"preview": "#pragma once\n\n#ifndef _ZF_LOG_H_\n#define _ZF_LOG_H_\n\n/* To detect incompatible changes you can define ZF_LOG_VERSION_REQ"
},
{
"path": "tests/zf_test.h",
"chars": 2315,
"preview": "#pragma once\n\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#if !defined(_ZF_TEST_STRINGIFY) && !defined("
},
{
"path": "zf_log/CMakeLists.txt",
"chars": 1681,
"preview": "cmake_minimum_required(VERSION 3.2)\n\n# zf_log target (required)\nset(HEADERS_DIR ${CMAKE_CURRENT_SOURCE_DIR})\nset(HEADERS"
},
{
"path": "zf_log/zf_log.c",
"chars": 46997,
"preview": "#ifdef ZF_LOG_USE_CONFIG_HEADER\n\t#include \"zf_log_config.h\"\n#endif\n\n/* When defined, Android log (android/log.h) will be"
},
{
"path": "zf_log/zf_log.h",
"chars": 38009,
"preview": "#pragma once\n\n#ifndef _ZF_LOG_H_\n#define _ZF_LOG_H_\n\n/* To detect incompatible changes you can define ZF_LOG_VERSION_REQ"
},
{
"path": "zf_log-config.cmake.in",
"chars": 50,
"preview": "include(\"${CMAKE_CURRENT_LIST_DIR}/zf_log.cmake\")\n"
}
]
About this extraction
This page contains the full source code of the wonder-mice/zf_log GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 44 files (255.2 KB), approximately 81.5k tokens, and a symbol index with 188 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.