├── .github └── workflows │ ├── codeql-analysis.yml │ └── main.yml ├── .gitignore ├── API.md ├── CHANGELOG.md ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.md ├── _config.yml ├── cmake-modules ├── CMakeUninstall.cmake.in ├── CTestCustom.cmake.in ├── FindCheck.cmake ├── FindSubunit.cmake ├── FindSystemd.cmake └── YderConfig.cmake.in ├── doc └── doxygen.cfg ├── examples ├── .gitignore ├── Makefile ├── log_callback.c ├── log_combined.c ├── log_console.c ├── log_file.c ├── log_journald.c ├── log_newline.c └── log_syslog.c ├── include ├── yder-cfg.h.in └── yder.h ├── libyder.pc.in ├── src ├── Makefile └── yder.c └── test ├── .gitignore ├── Makefile ├── run_test.sh └── yder_test.c /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [master, ] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: [master] 9 | schedule: 10 | - cron: '0 4 * * 6' 11 | 12 | jobs: 13 | analyse: 14 | name: Analyse 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v3 20 | with: 21 | # We must fetch at least the immediate parents so that if this is 22 | # a pull request then we can checkout the head. 23 | fetch-depth: 2 24 | 25 | # If this run was triggered by a pull request event, then checkout 26 | # the head of the pull request instead of the merge commit. 27 | - run: git checkout HEAD^2 28 | if: ${{ github.event_name == 'pull_request' }} 29 | 30 | # Initializes the CodeQL tools for scanning. 31 | - name: Initialize CodeQL 32 | uses: github/codeql-action/init@v3 33 | # Override language selection by uncommenting this and choosing your languages 34 | # with: 35 | # languages: go, javascript, csharp, python, cpp, java 36 | 37 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 38 | # If this step fails, then you should remove it and run the build manually (see below) 39 | #- name: Autobuild 40 | # uses: github/codeql-action/autobuild@v3 41 | 42 | # ℹ️ Command-line programs to run using the OS shell. 43 | # 📚 https://git.io/JvXDl 44 | 45 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 46 | # and modify them (or add more) to build your code if your project 47 | # uses a compiled language 48 | 49 | - name: dependencies 50 | run: | 51 | sudo apt-get update 52 | sudo apt-get install -y cmake pkg-config libsystemd-dev doxygen 53 | 54 | cd /opt 55 | git clone https://github.com/babelouest/orcania.git 56 | mkdir build 57 | cd build 58 | 59 | cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib ../orcania 60 | make 61 | sudo make install 62 | rm -rf * 63 | - run: | 64 | mkdir build 65 | cd build 66 | cmake -DBUILD_YDER_DOCUMENTATION=on .. 67 | make && make doc 68 | sudo make install 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v3 72 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | jobs: 4 | build: 5 | 6 | runs-on: ubuntu-latest 7 | 8 | steps: 9 | - uses: actions/checkout@v1 10 | - name: install dependencies 11 | run: | 12 | sudo apt-get update 13 | sudo apt-get install -y cmake pkg-config check libsubunit-dev cppcheck libsystemd-dev doxygen 14 | - name: cppcheck 15 | run: cppcheck --force --enable=warning,missingInclude --error-exitcode=1 . 16 | - name: dependencies 17 | run: | 18 | cd /opt 19 | git clone https://github.com/babelouest/orcania.git 20 | mkdir build 21 | cd build 22 | 23 | cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_INSTALL_LIBDIR=lib ../orcania 24 | make 25 | sudo make install 26 | rm -rf * 27 | - name: build 28 | run: | 29 | mkdir build 30 | cd build 31 | cmake -DBUILD_YDER_TESTING=on -DBUILD_YDER_DOCUMENTATION=on .. 32 | make test package doc 33 | sudo make install 34 | sudo ldconfig 35 | cd .. 36 | make 37 | make clean check 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.so.*.* 4 | *.a 5 | *.pc 6 | *.log 7 | yder-cfg.h 8 | -------------------------------------------------------------------------------- /API.md: -------------------------------------------------------------------------------- 1 | # Yder 2 | 3 | Logging library written in C. 4 | 5 | Simple and easy to use logging library. You can log messages to the console, a file, syslog, journald or a callback function. 6 | 7 | Yder is multi-thread, which mean that you can use multiple instances of the function `y_log_message` at the same time in your program. 8 | 9 | Yet, `y_init_logs`, `y_set_logs_callback`, `y_set_date_format`, `y_set_split_message_newline` and `y_close_logs` are mono-thread. You might use those functions in the `main()` routine to ensure safety. 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Yder Changelog 2 | 3 | ## 1.4.21 4 | 5 | - Minor bugfixes 6 | - Build with flag `-Wpedantic` 7 | 8 | ## 1.4.20 9 | 10 | - cmake: remove `DownloadProject` feature, now dependencies must be previously installed 11 | 12 | ## 1.4.19 13 | 14 | - Improve cmake script and MSVC support 15 | - Build with flag `-Wconversion` 16 | 17 | ## 1.4.18 18 | 19 | - Minor bugfixes 20 | 21 | ## 1.4.17 22 | 23 | - Fix `CMAKE_MODULE_PATH` who was used as single value (for real) 24 | 25 | ## 1.4.16 26 | 27 | - Fix pkg-config file with absolute path for `CMAKE_INSTALL_{INCLUDE,LIB}DIR` 28 | - Fix `CMAKE_MODULE_PATH` who was used as single value 29 | - Add `y_set_split_message_newline` to split log messages on newline characters 30 | 31 | ## 1.4.15 32 | 33 | - Use `o_strnullempty` instead of `o_strlen` to check if a `char *` has data 34 | 35 | ## 1.4.14 36 | 37 | - Add ld flags in libyder.pc on static build 38 | 39 | ## 1.4.13 40 | 41 | - Use `gmtime_s` on Windows (Thanks sudhip) 42 | 43 | ## 1.4.12 44 | 45 | - Use `gmtime_r` instead of `localtime` 46 | - Fix documentation typos 47 | 48 | ## 1.4.11 49 | 50 | - Update CI pipelines 51 | - cmake script: Add option `DOWNLOAD_DEPENDENCIES` 52 | - Harmonize licenses 53 | - Fix install pkgconfig by Makefile 54 | 55 | ## 1.4.10 56 | 57 | - Add `y_set_date_format`, closes #17 58 | - Remove generated doc from source package 59 | 60 | ## 1.4.9 61 | 62 | - Fix pkgconfig dependency 63 | - Add doxygen documentation 64 | 65 | ## 1.4.8 66 | 67 | - Avoid running `y_init_logs` without closing between 68 | 69 | ## 1.4.7 70 | 71 | - Fix build for MacOSX (thanks JohnAZoidberg!) 72 | - Clean build process 73 | - Clean static variables if error initializing logs with file 74 | 75 | ## 1.4.6 76 | 77 | - Fix package dependencies in cmake script 78 | 79 | ## 1.4.5 80 | 81 | - Install pkgconfig file when using Makefile 82 | - Update src/Makefile to show more information 83 | - Adapt for MSVC 84 | - Fix pkgconfig bugs 85 | 86 | ## 1.4.4 87 | 88 | - Improve build config file and install headers 89 | 90 | ## 1.4.3 91 | 92 | - Add config file yder-cfg.h dynamically built with the options 93 | 94 | ## 1.4.2 95 | 96 | - Add Travis CI 97 | - Change cmake option BUILD_TESTING to BUILD_YDER_TESTING 98 | - Add RPM in CMake script package 99 | 100 | ## 1.4.1 101 | 102 | - Fix a bug about including time.h in the wrong place 103 | 104 | ## 1.4.0 105 | 106 | - Add y_init_callback_logs to redirect all logs in a callback function 107 | 108 | ## 1.3.4 109 | 110 | - Fix CMake build when /usr/local is not present in default build path 111 | 112 | ## 1.3.3 113 | 114 | - Fix Makefile soname 115 | 116 | ## 1.3.2 117 | 118 | - Fix Debian package build on CMake script 119 | 120 | ## 1.3.1 121 | 122 | - Add Debian hardening patch on Makefile 123 | 124 | ## 1.3 125 | 126 | - Fix Syslog bug 127 | - Add Journald (SystemD) logs with the mode Y_LOG_MODE_JOURNALD 128 | 129 | ## 1.2.1 130 | 131 | - Update Orcania version 132 | - Added flags for building local static libraries 133 | 134 | ## 1.2.0 135 | 136 | - Add CMake installation script 137 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Yder library 3 | # 4 | # CMake file used to build all programs 5 | # 6 | # Copyright 2018 Silvio Clecio 7 | # Copyright 2018-2022 Nicolas Mora 8 | # 9 | # This program is free software; you can redistribute it and/or 10 | # modify it under the terms of the MIT License 11 | # 12 | # This library is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | # 16 | 17 | cmake_minimum_required(VERSION 3.5) 18 | 19 | project(yder C) 20 | 21 | set(CMAKE_C_STANDARD 99) 22 | if (NOT MSVC) 23 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror") 24 | endif() 25 | 26 | # library info 27 | 28 | set(PROJECT_DESCRIPTION "Logging library for C applications") 29 | set(PROJECT_HOMEPAGE_URL "https://github.com/babelouest/yder/") 30 | set(PROJECT_BUGREPORT_PATH "https://github.com/babelouest/yder/issues") 31 | set(LIBRARY_VERSION_MAJOR "1") 32 | set(LIBRARY_VERSION_MINOR "4") 33 | set(LIBRARY_VERSION_PATCH "21") 34 | 35 | set(PROJECT_VERSION "${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}.${LIBRARY_VERSION_PATCH}") 36 | set(PROJECT_VERSION_MAJOR ${LIBRARY_VERSION_MAJOR}) 37 | set(PROJECT_VERSION_MINOR ${LIBRARY_VERSION_MINOR}) 38 | set(PROJECT_VERSION_PATCH ${LIBRARY_VERSION_PATCH}) 39 | 40 | if (${LIBRARY_VERSION_MAJOR} VERSION_LESS 10) 41 | set (LIBRARY_VERSION_MAJOR_PAD "0${LIBRARY_VERSION_MAJOR}") 42 | else () 43 | set (LIBRARY_VERSION_MAJOR_PAD "${LIBRARY_VERSION_MAJOR}") 44 | endif () 45 | if (${LIBRARY_VERSION_MINOR} VERSION_LESS 10) 46 | set (LIBRARY_VERSION_MINOR_PAD "0${LIBRARY_VERSION_MINOR}") 47 | else () 48 | set (LIBRARY_VERSION_MINOR_PAD "${LIBRARY_VERSION_MINOR}") 49 | endif () 50 | if (${LIBRARY_VERSION_PATCH} VERSION_LESS 10) 51 | set (LIBRARY_VERSION_PATCH_PAD "0${LIBRARY_VERSION_PATCH}") 52 | else () 53 | set (LIBRARY_VERSION_PATCH_PAD "${LIBRARY_VERSION_PATCH}") 54 | endif () 55 | set(PROJECT_VERSION_NUMBER "${LIBRARY_VERSION_MAJOR_PAD}${LIBRARY_VERSION_MINOR_PAD}${LIBRARY_VERSION_PATCH_PAD}") 56 | 57 | set(LIBRARY_VERSION "${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}.${LIBRARY_VERSION_PATCH}") 58 | set(LIBRARY_SOVERSION "${LIBRARY_VERSION_MAJOR}.${LIBRARY_VERSION_MINOR}") 59 | set(ORCANIA_VERSION_REQUIRED "2.3.4") 60 | 61 | # cmake modules 62 | 63 | set(Y_CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules) 64 | list(APPEND CMAKE_MODULE_PATH "${Y_CMAKE_MODULE_PATH}") 65 | 66 | include(GNUInstallDirs) 67 | include(CheckSymbolExists) 68 | include(CMakePackageConfigHelpers) 69 | 70 | # check if _GNU_SOURCE is available 71 | 72 | if (NOT _GNU_SOURCE) 73 | check_symbol_exists(__GNU_LIBRARY__ "features.h" _GNU_SOURCE) 74 | 75 | if (NOT _GNU_SOURCE) 76 | unset(_GNU_SOURCE CACHE) 77 | check_symbol_exists(_GNU_SOURCE "features.h" _GNU_SOURCE) 78 | endif () 79 | endif () 80 | 81 | if (_GNU_SOURCE) 82 | add_definitions(-D_GNU_SOURCE) 83 | endif () 84 | 85 | # directories and source 86 | 87 | set(INC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) 88 | set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) 89 | 90 | include_directories(${INC_DIR}) 91 | 92 | set(LIB_SRC 93 | ${INC_DIR}/yder.h # allow many IDEs to find and edit it 94 | ${SRC_DIR}/yder.c) 95 | 96 | # dependencies 97 | 98 | set(WITH_JOURNALD_DEFAULT ON) 99 | if(WIN32) 100 | set(WITH_JOURNALD_DEFAULT OFF) 101 | endif() 102 | option(WITH_JOURNALD "Check journald." ${WITH_JOURNALD_DEFAULT}) 103 | 104 | if (WITH_JOURNALD) 105 | find_package(Systemd REQUIRED) 106 | set(SYSTEMD_LIBRARIES Systemd::Systemd) 107 | set(Y_DISABLE_JOURNALD OFF) 108 | else() 109 | set(Y_DISABLE_JOURNALD ON) 110 | set(SYSTEMD_LIBRARIES ) 111 | endif () 112 | 113 | option(BUILD_SHARED "Build shared library." ON) 114 | option(BUILD_STATIC "Build static library." OFF) 115 | 116 | if (NOT BUILD_SHARED AND NOT BUILD_STATIC) 117 | message(FATAL_ERROR "BUILD_SHARED and BUILD_STATIC cannot be both disabled") 118 | endif () 119 | 120 | # static library 121 | 122 | if (BUILD_STATIC) 123 | add_library(yder_static STATIC ${LIB_SRC}) 124 | add_library(Yder::Yder-static ALIAS yder_static) 125 | target_include_directories(yder_static 126 | PUBLIC "$" 127 | PUBLIC "$" 128 | PUBLIC "$") 129 | target_compile_definitions(yder_static PUBLIC O_STATIC_LIBRARY) 130 | set_target_properties(yder_static PROPERTIES 131 | PUBLIC_HEADER "${INC_DIR}/yder.h;${PROJECT_BINARY_DIR}/yder-cfg.h" 132 | OUTPUT_NAME yder 133 | EXPORT_NAME Yder-static) 134 | if (MSVC) 135 | set_target_properties(yder_static PROPERTIES 136 | OUTPUT_NAME yder-static) 137 | else () 138 | target_compile_options(yder_static PRIVATE -Wextra -Wconversion -Wpedantic) 139 | endif () 140 | set(yder_lib yder_static) 141 | endif () 142 | 143 | # shared library 144 | 145 | if (BUILD_SHARED) 146 | add_library(yder SHARED ${LIB_SRC}) 147 | add_library(Yder::Yder ALIAS yder) 148 | target_include_directories(yder 149 | PUBLIC "$" 150 | PUBLIC "$" 151 | PUBLIC "$") 152 | set_target_properties(yder PROPERTIES 153 | PUBLIC_HEADER "${INC_DIR}/yder.h;${PROJECT_BINARY_DIR}/yder-cfg.h" 154 | VERSION "${LIBRARY_VERSION}" 155 | SOVERSION "${LIBRARY_SOVERSION}" 156 | WINDOWS_EXPORT_ALL_SYMBOLS TRUE 157 | EXPORT_NAME Yder) 158 | if (WIN32) 159 | set_target_properties(yder PROPERTIES 160 | SUFFIX "-${LIBRARY_VERSION_MAJOR}.dll") 161 | endif () 162 | if (NOT MSVC) 163 | target_compile_options(yder PRIVATE -Wextra -Wconversion -Wpedantic) 164 | endif () 165 | set(yder_lib yder) 166 | endif() 167 | 168 | find_package(Orcania ${ORCANIA_VERSION_REQUIRED} REQUIRED) 169 | if ("${ORCANIA_VERSION_STRING}" VERSION_GREATER_EQUAL "${ORCANIA_VERSION_REQUIRED}") 170 | message(STATUS "Orcania found: ${ORCANIA_VERSION_STRING}") 171 | else () 172 | message( FATAL_ERROR "Orcania version required: ${ORCANIA_VERSION_REQUIRED} - version installed: ${ORCANIA_VERSION_STRING}") 173 | endif () 174 | 175 | if (BUILD_SHARED) 176 | target_link_libraries(yder PRIVATE $ ${SYSTEMD_LIBRARIES}) 177 | endif () 178 | if (BUILD_STATIC) 179 | if(TARGET Orcania::Orcania-static) 180 | target_link_libraries(yder_static PRIVATE $ ${SYSTEMD_LIBRARIES}) 181 | else() 182 | target_link_libraries(yder_static PRIVATE $ ${SYSTEMD_LIBRARIES}) 183 | endif() 184 | endif () 185 | 186 | set(PKGCONF_REQ_PRIVATE "liborcania") 187 | set(PKGCONF_REQ "") 188 | if (WITH_JOURNALD) 189 | string(APPEND PKGCONF_REQ_PRIVATE ", libsystemd") 190 | endif () 191 | 192 | # documentation 193 | 194 | option(BUILD_YDER_DOCUMENTATION "Build the documentation." OFF) 195 | if (BUILD_YDER_DOCUMENTATION) 196 | find_package(Doxygen) 197 | if (DOXYGEN_FOUND) 198 | set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/doc/doxygen.cfg) 199 | set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/doxyfile) 200 | 201 | configure_file(${doxyfile_in} ${doxyfile} @ONLY) 202 | 203 | add_custom_target(doc 204 | COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile_in} 205 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 206 | COMMENT "Generating documentation with Doxygen" 207 | VERBATIM) 208 | 209 | else () 210 | message(FATAL_ERROR "Doxygen is needed to build the documentation.") 211 | endif () 212 | endif () 213 | 214 | # build yder-cfg.h file 215 | configure_file(${INC_DIR}/yder-cfg.h.in ${PROJECT_BINARY_DIR}/yder-cfg.h) 216 | set (CMAKE_EXTRA_INCLUDE_FILES ${PROJECT_BINARY_DIR}) 217 | include_directories(${PROJECT_BINARY_DIR}) 218 | 219 | # tests 220 | 221 | option(BUILD_YDER_TESTING "Build the testing tree." OFF) # because we don not use include(CTest) 222 | 223 | if (BUILD_YDER_TESTING) 224 | find_package(Check) 225 | if (CHECK_FOUND) 226 | if (NOT WIN32 AND NOT APPLE) 227 | find_package(Subunit REQUIRED) 228 | endif () 229 | 230 | enable_testing() 231 | 232 | set(CMAKE_CTEST_COMMAND ctest -V) 233 | 234 | set(TST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/test) 235 | set(TEST_LIBS ${yder_lib} Check::Check Orcania::Orcania) 236 | if (NOT WIN32) 237 | find_package(Threads REQUIRED) 238 | list(APPEND TEST_LIBS ${CMAKE_THREAD_LIBS_INIT} m) 239 | endif () 240 | if (NOT APPLE) 241 | list(APPEND TEST_LIBS rt) 242 | endif () 243 | if (NOT WIN32 AND NOT APPLE) 244 | list(APPEND TEST_LIBS Subunit::Subunit) 245 | endif () 246 | 247 | set(TESTS yder_test) 248 | 249 | configure_file( 250 | "${Y_CMAKE_MODULE_PATH}/CTestCustom.cmake.in" 251 | "${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake" 252 | @ONLY) 253 | 254 | foreach (t ${TESTS}) 255 | add_executable(${t} EXCLUDE_FROM_ALL ${TST_DIR}/${t}.c) 256 | target_include_directories(${t} PRIVATE ${TST_DIR}) 257 | target_link_libraries(${t} PUBLIC ${TEST_LIBS}) 258 | add_test(NAME ${t} 259 | WORKING_DIRECTORY ${TST_DIR} 260 | COMMAND ${t}) 261 | endforeach () 262 | endif () 263 | endif () 264 | 265 | # install target 266 | 267 | option(INSTALL_HEADER "Install the header files" ON) # Install yder.h or not 268 | 269 | if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}") 270 | set(PKGCONFIG_TARGET_INCLUDES "${CMAKE_INSTALL_INCLUDEDIR}") 271 | else() 272 | set(PKGCONFIG_TARGET_INCLUDES "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") 273 | endif() 274 | 275 | if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}") 276 | set(PKGCONFIG_TARGET_LIBDIR "${CMAKE_INSTALL_LIBDIR}") 277 | else() 278 | set(PKGCONFIG_TARGET_LIBDIR "\${prefix}/${CMAKE_INSTALL_LIBDIR}") 279 | endif() 280 | 281 | configure_file(libyder.pc.in libyder.pc @ONLY) 282 | 283 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libyder.pc 284 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) 285 | 286 | set(TARGETS ) 287 | if (BUILD_SHARED) 288 | list(APPEND TARGETS yder) 289 | endif () 290 | if (BUILD_STATIC) 291 | list(APPEND TARGETS yder_static) 292 | endif () 293 | 294 | if (INSTALL_HEADER) 295 | install(TARGETS ${TARGETS} EXPORT YderExports 296 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 297 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 298 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 299 | PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 300 | install(DIRECTORY examples/ 301 | DESTINATION ${CMAKE_INSTALL_DOCDIR}/examples/ COMPONENT runtime) 302 | install(FILES README.md 303 | DESTINATION ${CMAKE_INSTALL_DOCDIR} COMPONENT runtime) 304 | else () 305 | install(TARGETS ${TARGETS} EXPORT YderExports 306 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 307 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 308 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) 309 | endif () 310 | 311 | if (INSTALL_HEADER) 312 | set(YDER_INSTALL_CMAKEDIR_DEFAULT "${CMAKE_INSTALL_LIBDIR}/cmake/Yder") 313 | if (WIN32 AND NOT MINGW) 314 | set(YDER_INSTALL_CMAKEDIR_DEFAULT "cmake") 315 | endif () 316 | set(YDER_INSTALL_CMAKEDIR ${YDER_INSTALL_CMAKEDIR_DEFAULT} CACHE STRING "Location where to install the cmake config files") 317 | 318 | install(EXPORT YderExports DESTINATION "${YDER_INSTALL_CMAKEDIR}" 319 | NAMESPACE "Yder::" 320 | FILE "YderTargets.cmake") 321 | 322 | configure_package_config_file(cmake-modules/YderConfig.cmake.in YderConfig.cmake 323 | INSTALL_DESTINATION "${YDER_INSTALL_CMAKEDIR}") 324 | write_basic_package_version_file(YderConfigVersion.cmake 325 | COMPATIBILITY AnyNewerVersion) 326 | 327 | install(FILES 328 | cmake-modules/FindSystemd.cmake 329 | "${PROJECT_BINARY_DIR}/YderConfig.cmake" 330 | "${PROJECT_BINARY_DIR}/YderConfigVersion.cmake" 331 | DESTINATION "${YDER_INSTALL_CMAKEDIR}") 332 | endif () 333 | 334 | # uninstall target 335 | 336 | if (NOT TARGET uninstall) 337 | configure_file( 338 | "${Y_CMAKE_MODULE_PATH}/CMakeUninstall.cmake.in" 339 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" 340 | IMMEDIATE @ONLY) 341 | add_custom_target(uninstall 342 | COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) 343 | endif () 344 | 345 | # packaging 346 | 347 | set(CPACK_PACKAGE_VERSION_MAJOR ${LIBRARY_VERSION_MAJOR}) 348 | set(CPACK_PACKAGE_VERSION_MINOR ${LIBRARY_VERSION_MINOR}) 349 | set(CPACK_PACKAGE_VERSION_PATCH ${LIBRARY_VERSION_PATCH}) 350 | 351 | if (INSTALL_HEADER) 352 | set(PACKAGE_FILE_NAME 353 | "lib${CMAKE_PROJECT_NAME}-dev_${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") 354 | else () 355 | set(PACKAGE_FILE_NAME 356 | "lib${CMAKE_PROJECT_NAME}_${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") 357 | endif () 358 | set(PACKAGE_IGNORED_FILES 359 | "${CMAKE_CURRENT_BINARY_DIR}/;/.git/;.gitignore;~$;${CPACK_SOURCE_IGNORE_FILES}") 360 | 361 | set(CPACK_GENERATOR ) 362 | set(CPACK_PACKAGE_NAME "libyder") 363 | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Logging library for C applications") 364 | set(CPACK_PACKAGE_VERSION_MAJOR ${LIBRARY_VERSION_MAJOR}) 365 | set(CPACK_PACKAGE_VERSION_MINOR ${LIBRARY_VERSION_MINOR}) 366 | set(CPACK_PACKAGE_VERSION_PATCH ${LIBRARY_VERSION_PATCH}) 367 | set(CPACK_PACKAGE_FILE_NAME ${PACKAGE_FILE_NAME}) 368 | 369 | option(BUILD_TGZ "Build a TAR.GZ for your system" OFF) 370 | if (BUILD_TGZ) 371 | list(APPEND CPACK_GENERATOR TGZ) 372 | set(CPACK_SOURCE_GENERATOR "TGZ") 373 | set(CPACK_SOURCE_PACKAGE_FILE_NAME ${PACKAGE_FILE_NAME}) 374 | set(CPACK_SOURCE_IGNORE_FILES ${PACKAGE_IGNORED_FILES}) 375 | endif () 376 | 377 | option(BUILD_DEB "Build a DEB for your system" OFF) 378 | if (BUILD_DEB) 379 | list(APPEND CPACK_GENERATOR DEB) 380 | set(CPACK_DEBIAN_PACKAGE_MAINTAINER "mail@babelouest.org") 381 | set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.4), liborcania (>= ${ORCANIA_VERSION_REQUIRED})") 382 | if (INSTALL_HEADER) 383 | if (WITH_SYSTEMD) 384 | set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}, libsystemd-dev") 385 | endif () 386 | else () 387 | if (WITH_SYSTEMD) 388 | set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}, libsystemd0") 389 | endif () 390 | endif () 391 | endif () 392 | 393 | option(BUILD_RPM "Build a RPM for your system" OFF) 394 | if (BUILD_RPM) 395 | list(APPEND CPACK_GENERATOR RPM) 396 | set(CPACK_RPM_PACKAGE_LICENSE "LGPL") 397 | set(CPACK_RPM_PACKAGE_URL "http://babelouest.github.io/yder/") 398 | endif () 399 | 400 | include(CPack) 401 | 402 | add_custom_target(dist_y 403 | COMMAND ${CMAKE_MAKE_PROGRAM} package_source) 404 | 405 | message(STATUS "Journald support: ${WITH_JOURNALD}") 406 | message(STATUS "Build shared library: ${BUILD_SHARED}") 407 | message(STATUS "Build static library: ${BUILD_STATIC}") 408 | message(STATUS "Build testing tree: ${BUILD_YDER_TESTING}") 409 | message(STATUS "Install the header files: ${INSTALL_HEADER}") 410 | message(STATUS "Build TAR.GZ package: ${BUILD_TGZ}") 411 | message(STATUS "Build DEB package: ${BUILD_DEB}") 412 | message(STATUS "Build RPM package: ${BUILD_RPM}") 413 | message(STATUS "Build documentation: ${BUILD_YDER_DOCUMENTATION}") 414 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | (This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.) 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | {description} 474 | Copyright (C) {year} {fullname} 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 489 | USA 490 | 491 | Also add information on how to contact you by electronic and paper mail. 492 | 493 | You should also get your employer (if you work as a programmer) or your 494 | school, if any, to sign a "copyright disclaimer" for the library, if 495 | necessary. Here is a sample; alter the names: 496 | 497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 498 | library `Frob' (a library for tweaking knobs) written by James Random 499 | Hacker. 500 | 501 | {signature of Ty Coon}, 1 April 1990 502 | Ty Coon, President of Vice 503 | 504 | That's all there is to it! 505 | 506 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Example program 3 | # 4 | # Makefile used to build all programs 5 | # 6 | # Copyright 2014-2022 Nicolas Mora 7 | # 8 | # This program is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public License 10 | # as published by the Free Software Foundation; 11 | # version 2.1 of the License. 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU GENERAL PUBLIC LICENSE for more details. 17 | # 18 | # You should have received a copy of the GNU General Public 19 | # License along with this library. If not, see . 20 | # 21 | 22 | LIBYDER_LOCATION=./src 23 | EXAMPLE_LOCATION=./examples 24 | TEST_LOCATION=./test 25 | 26 | all: release 27 | 28 | debug: 29 | cd $(LIBYDER_LOCATION) && $(MAKE) debug $* 30 | 31 | install: 32 | cd $(LIBYDER_LOCATION) && $(MAKE) install 33 | 34 | clean: 35 | cd $(LIBYDER_LOCATION) && $(MAKE) clean 36 | cd $(EXAMPLE_LOCATION) && $(MAKE) clean 37 | cd $(TEST_LOCATION) && $(MAKE) clean 38 | rm -rf doc/html/ 39 | 40 | check: 41 | cd $(TEST_LOCATION) && $(MAKE) test 42 | 43 | release: 44 | cd $(LIBYDER_LOCATION) && $(MAKE) 45 | 46 | log_console: 47 | cd $(EXAMPLE_LOCATION) && $(MAKE) log_console 48 | 49 | log_file: 50 | cd $(EXAMPLE_LOCATION) && $(MAKE) log_file 51 | 52 | log_syslog: 53 | cd $(EXAMPLE_LOCATION) && $(MAKE) log_syslog 54 | 55 | log_combined: 56 | cd $(EXAMPLE_LOCATION) && $(MAKE) log_combined 57 | 58 | doxygen: 59 | doxygen doc/doxygen.cfg 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Yder 2 | 3 | Logging library written in C. 4 | 5 | ![.github/workflows/main.yml](https://github.com/babelouest/yder/workflows/.github/workflows/main.yml/badge.svg) 6 | 7 | Simple and easy to use logging library. You can log messages to the console, a file, Syslog, journald or a callback function. 8 | 9 | Yder is mono-thread, which mean that you can use only one instance of Yder log at the same time in your program. 10 | 11 | See the [online documentation](https://babelouest.github.io/yder/) for a doxygen format of the API documentation. 12 | 13 | # Installation 14 | 15 | ## Distribution packages 16 | 17 | [![Packaging status](https://repology.org/badge/vertical-allrepos/yder.svg)](https://repology.org/metapackage/yder) 18 | 19 | Yder is available in multiple distributions as official package. Check out your distribution documentation to install the package automatically. 20 | 21 | ```shell 22 | $ # Example for Debian testing 23 | $ sudo apt install libyder-dev # Or apt install libyder2.0 if you don't need the development files 24 | ``` 25 | 26 | ## Pre-compiled packages 27 | 28 | You can install Yder with a pre-compiled package available in the [release pages](https://github.com/babelouest/yder/releases/latest/). Note that you need to install [Orcania](https://github.com/babelouest/orcania/releases/latest/) first. `jansson` development files packages is required to install Yder. 29 | 30 | ## Manual install 31 | 32 | ### Prerequisites 33 | 34 | You must install [Orcania](https://github.com/babelouest/orcania) first before building Yder. Orcania will be automatically installed if missing and you're using CMake. 35 | 36 | ### CMake - Multi architecture 37 | 38 | [CMake](https://cmake.org/download/) minimum 3.5 is required. 39 | 40 | Run the CMake script in a sub-directory, example: 41 | 42 | Last Yder release: [https://github.com/babelouest/yder/releases/latest/](https://github.com/babelouest/yder/releases/latest/) 43 | 44 | ```shell 45 | $ cd 46 | $ mkdir build 47 | $ cd build 48 | $ cmake .. 49 | $ make && sudo make install 50 | ``` 51 | 52 | The available options for CMake are: 53 | - `-DWITH_JOURNALD=[on|off]` (default `on`): Build with journald (SystemD) support 54 | - `-DBUILD_STATIC=[on|off]` (default `off`): Build the static archive in addition to the shared library 55 | - `-DBUILD_YDER_TESTING=[on|off]` (default `off`): Build unit tests 56 | - `-DBUILD_YDER_DOCUMENTATION=[on|off]` (default `off`): Build the documentation, doxygen is required 57 | - `-DINSTALL_HEADER=[on|off]` (default `on`): Install header file `yder.h` 58 | - `-DBUILD_RPM=[on|off]` (default `off`): Build RPM package when running `make package` 59 | - `-DCMAKE_BUILD_TYPE=[Debug|Release]` (default `Release`): Compile with debugging symbols or not 60 | 61 | ### Good ol' Makefile 62 | 63 | Download Yder from GitHub repository, compile and install. 64 | 65 | Last Yder release: [https://github.com/babelouest/yder/releases/latest/](https://github.com/babelouest/yder/releases/latest/) 66 | 67 | ```shell 68 | $ cd yder/src 69 | $ make 70 | $ sudo make install 71 | ``` 72 | 73 | To build Yder without Journald (SystemD) support, add the option Y_DISABLE_JOURNALD=1 to the `make command`: 74 | 75 | ```shell 76 | $ git clone https://github.com/babelouest/yder.git 77 | $ cd yder/src 78 | $ make Y_DISABLE_JOURNALD=1 79 | $ sudo make install 80 | ``` 81 | 82 | By default, the shared library and the header file will be installed in the `/usr/local` location. To change this setting, you can modify the `DESTDIR` value in the `src/Makefile`. 83 | 84 | Example: install Yder in /tmp/lib directory 85 | 86 | ```shell 87 | $ cd src 88 | $ make && make DESTDIR=/tmp install 89 | ``` 90 | 91 | You can install Yder without root permission if your user has write access to `$(DESTDIR)`. 92 | A `ldconfig` command is executed at the end of the install, it will probably fail if you don't have root permission, but this is harmless. 93 | If you choose to install Yder in another directory, you must set your environment variable `LD_LIBRARY_PATH` properly. 94 | 95 | ### Install Yder as a static archive 96 | 97 | Install Yder library as a static archive, `libyder.a`, use the make commands `make static*`: 98 | 99 | ```shell 100 | $ cd src 101 | $ make static && sudo make static-install # or make DESTDIR=/tmp static-install if you want to install in `/tmp/lib` 102 | ``` 103 | 104 | # API Documentation 105 | 106 | ## Header files and compilation 107 | 108 | To use Yder in your code, you must include the file `yder.h`. 109 | 110 | ```c 111 | #include 112 | ``` 113 | 114 | ### Initialization 115 | 116 | Use the `y_init_logs` function to start logging. The prototype of this function is: 117 | 118 | ```c 119 | /** 120 | * Initialize logging with mode and level parameters, specify a log file if needed 121 | * Return true on success, false on error 122 | */ 123 | int y_init_logs(const char * app, const unsigned long init_mode, const unsigned long init_level, const char * init_log_file, const char * message); 124 | ``` 125 | 126 | The parameter `init_mode` is the initial mode for logging. You can specify and combine the following modes available: 127 | 128 | ```c 129 | Y_LOG_MODE_CONSOLE 130 | Y_LOG_MODE_SYSLOG 131 | Y_LOG_MODE_JOURNALD 132 | Y_LOG_MODE_FILE 133 | Y_LOG_MODE_CALLBACK 134 | ``` 135 | 136 | If you use Y_LOG_MODE_FILE in your initial mode, you must specify a valid path for the `init_log_file` parameter. 137 | 138 | The parameter `init_level` is the bottom level of your log messages. The levels available are, by level order: 139 | 140 | ```c 141 | Y_LOG_LEVEL_NONE 142 | Y_LOG_LEVEL_ERROR 143 | Y_LOG_LEVEL_WARNING 144 | Y_LOG_LEVEL_INFO 145 | Y_LOG_LEVEL_DEBUG 146 | ``` 147 | 148 | For example, if you specify `Y_LOG_LEVEL_WARNING` as init_level, you will see in your log output only `Y_LOG_LEVEL_WARNING` and `Y_LOG_LEVEL_ERROR`. If you specify `Y_LOG_LEVEL_DEBUG`, you will see in your log output all log messages. 149 | 150 | ### Redirect log messages to a callback function 151 | 152 | If you need to redirect log messages to a custom callback function, for example if you need to interact with other logging libraries, you must use the init_mode `Y_LOG_MODE_CALLBACK` in the `init_mode` parameter in the `y_init_logs` function, then use the function `y_set_logs_callback` with your callback function as parameter. 153 | 154 | ```C 155 | /** 156 | * Specify a callback function that will catch all log messages 157 | * In addition to other logs output already defined in y_init_logs 158 | */ 159 | int y_set_logs_callback(void (* y_callback_log_message) (void * cls, const char * app_name, const time_t date, const unsigned long level, const char * message), 160 | void * cls, 161 | const char * message); 162 | ``` 163 | 164 | The callback log function must have the following signature: 165 | 166 | ```C 167 | void y_callback_log_message(void * cls, const char * app_name, const time_t date, const unsigned long level, const char * message); 168 | ``` 169 | 170 | The parameters in the callback function are: 171 | ```C 172 | - void * cls // Your specified parameter 173 | - const char * app_name // The value app_name from y_init_logs 174 | - const time_t date // The datestamp when the log message was launched 175 | - const unsigned long level // The log level of the message, values can be: Y_LOG_LEVEL_ERROR, Y_LOG_LEVEL_WARNING, Y_LOG_LEVEL_INFO, Y_LOG_LEVEL_DEBUG 176 | ``` 177 | 178 | ### Close Yder 179 | 180 | To close Yder and free its allocated memory, use the function `y_close_logs`: 181 | 182 | ```c 183 | /** 184 | * Close the logs 185 | */ 186 | int y_close_logs(); 187 | ``` 188 | 189 | ### Log a message 190 | 191 | To log a message, use the function `y_log_message`, defined by: 192 | 193 | ```c 194 | /** 195 | * Log a message using current parameters 196 | */ 197 | void y_log_message(const unsigned long type, const char * message, ...); 198 | ``` 199 | 200 | This function uses `printf` prototype for the message and the log message type. For example: 201 | 202 | ```c 203 | y_log_message(Y_LOG_LEVEL_INFO, "Initializing application"); 204 | y_log_message(Y_LOG_LEVEL_ERROR, "Error in application, you have %d over %d threads in error mode", threads_error, threads_total); 205 | ``` 206 | 207 | ### Example source code 208 | 209 | See `examples` folder for detailed sample source codes. 210 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /cmake-modules/CMakeUninstall.cmake.in: -------------------------------------------------------------------------------- 1 | if (NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") 2 | message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") 3 | endif (NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") 4 | 5 | file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) 6 | string(REGEX REPLACE "\n" ";" files "${files}") 7 | foreach (file ${files}) 8 | message(STATUS "Uninstalling $ENV{DESTDIR}${file}") 9 | if (IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 10 | exec_program( 11 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 12 | OUTPUT_VARIABLE rm_out 13 | RETURN_VALUE rm_retval 14 | ) 15 | if (NOT "${rm_retval}" STREQUAL 0) 16 | message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") 17 | endif (NOT "${rm_retval}" STREQUAL 0) 18 | else (IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 19 | message(STATUS "File $ENV{DESTDIR}${file} does not exist.") 20 | endif (IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") 21 | endforeach (file) 22 | -------------------------------------------------------------------------------- /cmake-modules/CTestCustom.cmake.in: -------------------------------------------------------------------------------- 1 | string(REPLACE ";" " " TESTS "@TESTS@") 2 | set(CTEST_CUSTOM_PRE_TEST "@CMAKE_MAKE_PROGRAM@ ${TESTS}") -------------------------------------------------------------------------------- /cmake-modules/FindCheck.cmake: -------------------------------------------------------------------------------- 1 | #.rst: 2 | # FindCheck 3 | # ----------- 4 | # 5 | # Find Check 6 | # 7 | # Find Check headers and libraries. 8 | # 9 | # :: 10 | # 11 | # CHECK_FOUND - True if Check found. 12 | # CHECK_INCLUDE_DIRS - Where to find check.h. 13 | # CHECK_LIBRARIES - List of libraries when using Check. 14 | # CHECK_VERSION_STRING - The version of Check found. 15 | 16 | #============================================================================= 17 | # Copyright 2018 Silvio Clecio 18 | # 19 | # This program is free software; you can redistribute it and/or 20 | # modify it under the terms of the GNU Lesser General Public License 21 | # as published by the Free Software Foundation; 22 | # version 2.1 of the License. 23 | # 24 | # This library is distributed in the hope that it will be useful, 25 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 | # GNU GENERAL PUBLIC LICENSE for more details. 28 | # 29 | # You should have received a copy of the GNU General Public 30 | # License along with this library. If not, see . 31 | #============================================================================= 32 | 33 | # Sat Jan 20 23:33:47 -03 2018 34 | 35 | find_package(PkgConfig QUIET) 36 | pkg_check_modules(PC_CHECK QUIET check) 37 | 38 | find_path(CHECK_INCLUDE_DIR 39 | NAMES check.h 40 | HINTS ${PC_CHECK_INCLUDEDIR} ${PC_CHECK_INCLUDE_DIRS}) 41 | 42 | find_library(CHECK_LIBRARY 43 | NAMES check libcheck 44 | HINTS ${PC_CHECK_LIBDIR} ${PC_CHECK_LIBRARY_DIRS}) 45 | 46 | if (PC_CHECK_VERSION) 47 | set(CHECK_VERSION_STRING ${PC_CHECK_VERSION}) 48 | elseif (CHECK_INCLUDE_DIR AND EXISTS "${CHECK_INCLUDE_DIR}/check.h") 49 | set(check_version_list MAJOR MINOR MICRO) 50 | foreach (v ${check_version_list}) 51 | set(regex_check_version "^#define CHECK_${v}_VERSION +\\(?([0-9]+)\\)?$") 52 | file(STRINGS "${CHECK_INCLUDE_DIR}/check.h" check_version_${v} REGEX "${regex_check_version}") 53 | string(REGEX REPLACE "${regex_check_version}" "\\1" check_version_${v} "${check_version_${v}}") 54 | unset(regex_check_version) 55 | endforeach () 56 | set(CHECK_VERSION_STRING "${check_version_MAJOR}.${check_version_MINOR}.${check_version_MICRO}") 57 | foreach (v check_version_list) 58 | unset(check_version_${v}) 59 | endforeach () 60 | unset(check_version_list) 61 | endif () 62 | 63 | include(FindPackageHandleStandardArgs) 64 | find_package_handle_standard_args(Check 65 | REQUIRED_VARS CHECK_LIBRARY CHECK_INCLUDE_DIR 66 | VERSION_VAR CHECK_VERSION_STRING) 67 | 68 | if (CHECK_FOUND) 69 | set(CHECK_LIBRARIES ${CHECK_LIBRARY}) 70 | set(CHECK_INCLUDE_DIRS ${CHECK_INCLUDE_DIR}) 71 | if (NOT TARGET Check::Check) 72 | add_library(Check::Check UNKNOWN IMPORTED) 73 | set_target_properties(Check::Check PROPERTIES 74 | IMPORTED_LOCATION "${CHECK_LIBRARY}" 75 | INTERFACE_INCLUDE_DIRECTORIES "${CHECK_INCLUDE_DIR}") 76 | endif () 77 | endif () 78 | 79 | mark_as_advanced(CHECK_INCLUDE_DIR CHECK_LIBRARY) 80 | -------------------------------------------------------------------------------- /cmake-modules/FindSubunit.cmake: -------------------------------------------------------------------------------- 1 | #.rst: 2 | # FindSubunit 3 | # ----------- 4 | # 5 | # Find Subunit 6 | # 7 | # Find Subunit headers and libraries. 8 | # 9 | # :: 10 | # 11 | # SUBUNIT_FOUND - True if Subunit found. 12 | # SUBUNIT_INCLUDE_DIRS - Where to find subunit/child.h. 13 | # SUBUNIT_LIBRARIES - List of libraries when using Subunit. 14 | # SUBUNIT_VERSION_STRING - The version of Subunit found. 15 | 16 | #============================================================================= 17 | # Copyright 2018 Silvio Clecio 18 | # 19 | # This program is free software; you can redistribute it and/or 20 | # modify it under the terms of the GNU Lesser General Public License 21 | # as published by the Free Software Foundation; 22 | # version 2.1 of the License. 23 | # 24 | # This library is distributed in the hope that it will be useful, 25 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 | # GNU GENERAL PUBLIC LICENSE for more details. 28 | # 29 | # You should have received a copy of the GNU General Public 30 | # License along with this library. If not, see . 31 | #============================================================================= 32 | 33 | # Fri Jan 19 22:27:51 -03 2018 34 | 35 | find_package(PkgConfig QUIET) 36 | pkg_check_modules(PC_SUBUNIT QUIET libsubunit) 37 | 38 | set(SUBUNIT_VERSION_STRING "${PC_SUBUNIT_VERSION}") 39 | 40 | find_path(SUBUNIT_INCLUDE_DIR 41 | NAMES child.h 42 | HINTS ${PC_SUBUNIT_INCLUDEDIR} ${PC_SUBUNIT_INCLUDE_DIRS} 43 | PATH_SUFFIXES subunit) 44 | 45 | find_library(SUBUNIT_LIBRARY 46 | NAMES subunit libsubunit 47 | HINTS ${PC_SUBUNIT_LIBDIR} ${PC_SUBUNIT_LIBRARY_DIRS}) 48 | 49 | include(FindPackageHandleStandardArgs) 50 | find_package_handle_standard_args(Subunit 51 | REQUIRED_VARS SUBUNIT_LIBRARY SUBUNIT_INCLUDE_DIR 52 | VERSION_VAR SUBUNIT_VERSION_STRING) 53 | 54 | if (SUBUNIT_FOUND) 55 | set(SUBUNIT_LIBRARIES ${SUBUNIT_LIBRARY}) 56 | set(SUBUNIT_INCLUDE_DIRS ${SUBUNIT_INCLUDE_DIR}) 57 | if (NOT TARGET Subunit::Subunit) 58 | add_library(Subunit::Subunit UNKNOWN IMPORTED) 59 | set_target_properties(Subunit::Subunit PROPERTIES 60 | IMPORTED_LOCATION "${SUBUNIT_LIBRARY}" 61 | INTERFACE_INCLUDE_DIRECTORIES "${SUBUNIT_INCLUDE_DIR}") 62 | endif () 63 | endif () 64 | 65 | mark_as_advanced(SUBUNIT_INCLUDE_DIR SUBUNIT_LIBRARY) -------------------------------------------------------------------------------- /cmake-modules/FindSystemd.cmake: -------------------------------------------------------------------------------- 1 | #.rst: 2 | # FindSystemd 3 | # ----------- 4 | # 5 | # Find Systemd 6 | # 7 | # Find Systemd headers and libraries. 8 | # 9 | # :: 10 | # 11 | # SYSTEMD_FOUND - True if Systemd found. 12 | # SYSTEMD_INCLUDE_DIRS - Where to find orcania.h. 13 | # SYSTEMD_LIBRARIES - List of libraries when using Systemd. 14 | 15 | #============================================================================= 16 | # Copyright 2018 Silvio Clecio 17 | # Copyright 2018 Nicolas Mora 18 | # 19 | # This program is free software; you can redistribute it and/or 20 | # modify it under the terms of the GNU Lesser General Public License 21 | # as published by the Free Software Foundation; 22 | # version 2.1 of the License. 23 | # 24 | # This library is distributed in the hope that it will be useful, 25 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 | # GNU GENERAL PUBLIC LICENSE for more details. 28 | # 29 | # You should have received a copy of the GNU General Public 30 | # License along with this library. If not, see . 31 | #============================================================================= 32 | 33 | # Sat Jan 27 15:57:36 -03 2018 34 | 35 | find_package(PkgConfig QUIET) 36 | pkg_check_modules(PC_SYSTEMD QUIET systemd) 37 | 38 | find_path(SYSTEMD_INCLUDE_DIR 39 | NAMES systemd/_sd-common.h 40 | HINTS ${PC_SYSTEMD_INCLUDEDIR} ${PC_SYSTEMD_INCLUDE_DIRS}) 41 | 42 | find_library(SYSTEMD_LIBRARY 43 | NAMES systemd libsystemd 44 | HINTS ${PC_SYSTEMD_LIBDIR} ${PC_SYSTEMD_LIBRARY_DIRS}) 45 | 46 | include(FindPackageHandleStandardArgs) 47 | find_package_handle_standard_args(Systemd 48 | REQUIRED_VARS SYSTEMD_LIBRARY SYSTEMD_INCLUDE_DIR) 49 | 50 | if (SYSTEMD_FOUND) 51 | set(SYSTEMD_LIBRARIES ${SYSTEMD_LIBRARY}) 52 | set(SYSTEMD_INCLUDE_DIRS ${SYSTEMD_INCLUDE_DIR}) 53 | if (NOT TARGET Systemd:Systemd) 54 | add_library(Systemd::Systemd IMPORTED UNKNOWN) 55 | set_target_properties(Systemd::Systemd PROPERTIES 56 | IMPORTED_LOCATION "${SYSTEMD_LIBRARY}" 57 | INTERFACE_INCLUDE_DIRECTORIES "${SYSTEMD_INCLUDE_DIR}") 58 | endif () 59 | endif () 60 | mark_as_advanced(SYSTEMD_INCLUDE_DIR SYSTEMD_LIBRARY) 61 | -------------------------------------------------------------------------------- /cmake-modules/YderConfig.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include("${CMAKE_CURRENT_LIST_DIR}/YderTargets.cmake") 4 | 5 | set(YDER_JOURNALD @WITH_JOURNALD@) 6 | 7 | set(CMAKE_CURRENT_LIST_DIR ${_original_cmake_module_path}) 8 | 9 | if(TARGET Yder::Yder-static) 10 | set(ORCANIA_INCLUDE_DIRS $) 11 | set(ORCANIA_LIBRARIES Yder::Yder-static) 12 | endif() 13 | 14 | if(TARGET Yder::Yder) 15 | set(ORCANIA_INCLUDE_DIRS $) 16 | set(ORCANIA_LIBRARIES Yder::Yder) 17 | endif() 18 | 19 | include(CMakeFindDependencyMacro) 20 | 21 | set(_original_cmake_module_path ${CMAKE_MODULE_PATH}) 22 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") 23 | 24 | find_dependency(Orcania) 25 | 26 | if(TARGET Yder::Yder-static) 27 | if(YDER_JOURNALD) 28 | find_dependency(Systemd) 29 | endif() 30 | endif() 31 | 32 | set(CMAKE_MODULE_PATH ${_original_cmake_module_path}) 33 | 34 | set(YDER_VERSION_STRING "@PROJECT_VERSION@") 35 | set(Yder_FOUND TRUE) 36 | -------------------------------------------------------------------------------- /doc/doxygen.cfg: -------------------------------------------------------------------------------- 1 | # Doxyfile 1.9.1 2 | PROJECT_NAME = "Yder" 3 | PROJECT_BRIEF = "Logging library written in C" 4 | INPUT = API.md \ 5 | ./src/ \ 6 | ./include/ 7 | USE_MDFILE_AS_MAINPAGE = API.md 8 | 9 | #--------------------------------------------------------------------------- 10 | # Project related configuration options 11 | #--------------------------------------------------------------------------- 12 | DOXYFILE_ENCODING = UTF-8 13 | OUTPUT_DIRECTORY = doc 14 | CREATE_SUBDIRS = NO 15 | ALLOW_UNICODE_NAMES = NO 16 | OUTPUT_LANGUAGE = English 17 | BRIEF_MEMBER_DESC = YES 18 | REPEAT_BRIEF = YES 19 | ABBREVIATE_BRIEF = "The $name class" \ 20 | "The $name widget" \ 21 | "The $name file" \ 22 | is \ 23 | provides \ 24 | specifies \ 25 | contains \ 26 | represents \ 27 | a \ 28 | an \ 29 | the 30 | TAB_SIZE = 4 31 | OPTIMIZE_OUTPUT_FOR_C = YES 32 | OPTIMIZE_OUTPUT_JAVA = NO 33 | OPTIMIZE_FOR_FORTRAN = NO 34 | OPTIMIZE_OUTPUT_VHDL = NO 35 | OPTIMIZE_OUTPUT_SLICE = NO 36 | #--------------------------------------------------------------------------- 37 | # Build related configuration options 38 | #--------------------------------------------------------------------------- 39 | EXTRACT_ALL = YES 40 | EXTRACT_PRIVATE = NO 41 | #--------------------------------------------------------------------------- 42 | # Configuration options related to the input files 43 | #--------------------------------------------------------------------------- 44 | INPUT_ENCODING = UTF-8 45 | FILE_PATTERNS = *.c \ 46 | *.h \ 47 | *.md 48 | RECURSIVE = YES 49 | #--------------------------------------------------------------------------- 50 | # Configuration options related to the HTML output 51 | #--------------------------------------------------------------------------- 52 | GENERATE_HTML = YES 53 | HTML_OUTPUT = html 54 | HTML_FILE_EXTENSION = .html 55 | HTML_COLORSTYLE_HUE = 220 56 | HTML_COLORSTYLE_SAT = 100 57 | HTML_COLORSTYLE_GAMMA = 80 58 | HTML_DYNAMIC_MENUS = YES 59 | HTML_DYNAMIC_SECTIONS = NO 60 | GENERATE_LATEX = NO 61 | GENERATE_RTF = NO 62 | GENERATE_MAN = NO 63 | GENERATE_XML = NO 64 | GENERATE_DOCBOOK = NO 65 | GENERATE_AUTOGEN_DEF = NO 66 | GENERATE_PERLMOD = NO 67 | ENABLE_PREPROCESSING = YES 68 | MACRO_EXPANSION = NO 69 | EXPAND_ONLY_PREDEF = NO 70 | SEARCH_INCLUDES = YES 71 | HAVE_DOT = NO 72 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | log_combined 2 | log_console 3 | log_file 4 | log_syslog 5 | log_journald 6 | log_callback 7 | log_newline 8 | valgrind.txt 9 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Example program 3 | # 4 | # Makefile used to build the software 5 | # 6 | # Copyright 2014-2020 Nicolas Mora 7 | # 8 | # This program is free software; you can redistribute it and/or 9 | # modify it under the terms of the MIT License 10 | # 11 | # This library is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU GENERAL PUBLIC LICENSE for more details. 15 | # 16 | CC=gcc 17 | CFLAGS=-c -Wall -D_REENTRANT $(ADDITIONALFLAGS) -I$(INCLUDE_LOCATION) 18 | YDER_LOCATION=../src 19 | INCLUDE_LOCATION=../include 20 | LIBS=-lc -lyder -L$(YDER_LOCATION) 21 | ADDITIONALFLAGS=-O3 22 | TARGET=log_console log_syslog log_file log_combined log_callback log_newline 23 | 24 | ifndef Y_DISABLE_JOURNALD 25 | TARGET+= log_journald 26 | endif 27 | 28 | all: libyder.so $(TARGET) 29 | 30 | clean: 31 | rm -f *.o valgrind.txt log_console log_syslog log_file log_combined log_journald log_callback log_newline 32 | 33 | debug: ADDITIONALFLAGS=-DDEBUG -g -O0 34 | 35 | debug: libyder.so $(TARGET) 36 | 37 | libyder.so: 38 | cd $(YDER_LOCATION) && $(MAKE) 39 | 40 | log_console: log_console.c 41 | $(CC) -c $(CFLAGS) log_console.c 42 | $(CC) -o log_console log_console.o $(LIBS) 43 | 44 | log_syslog: log_syslog.c 45 | $(CC) -c $(CFLAGS) log_syslog.c 46 | $(CC) -o log_syslog log_syslog.o $(LIBS) 47 | 48 | log_journald: log_journald.c 49 | $(CC) -c $(CFLAGS) log_journald.c 50 | $(CC) -o log_journald log_journald.o $(LIBS) 51 | 52 | log_file: log_file.c 53 | $(CC) -c $(CFLAGS) log_file.c 54 | $(CC) -o log_file log_file.o $(LIBS) 55 | 56 | log_combined: log_combined.c 57 | $(CC) -c $(CFLAGS) log_combined.c 58 | $(CC) -o log_combined log_combined.o $(LIBS) 59 | 60 | log_callback: log_callback.c 61 | $(CC) -c $(CFLAGS) log_callback.c 62 | $(CC) -o log_callback log_callback.o $(LIBS) 63 | 64 | log_newline: log_newline.c 65 | $(CC) -c $(CFLAGS) log_newline.c 66 | $(CC) -o log_newline log_newline.o $(LIBS) 67 | 68 | test_console: libyder.so log_console 69 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_console 70 | 71 | test_syslog: libyder.so log_syslog 72 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_syslog 73 | 74 | test_file: libyder.so log_file 75 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_file 76 | 77 | test_combined: libyder.so log_combined 78 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_combined 79 | 80 | test_journald: libyder.so log_journald 81 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_journald 82 | 83 | test_callback: libyder.so log_callback 84 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_callback 85 | 86 | test_newline: libyder.so log_newline 87 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_newline 88 | 89 | ifndef Y_DISABLE_JOURNALD 90 | test: libyder.so $(TARGET) 91 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_console 92 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_syslog 93 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_file 94 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_combined 95 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_journald 96 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_callback 97 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_newline 98 | else 99 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_console 100 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_syslog 101 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_file 102 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_combined 103 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_callback 104 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./log_newline 105 | endif 106 | 107 | ifndef Y_DISABLE_JOURNALD 108 | memcheck: libyder.so $(TARGET) 109 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./log_console 2>valgrind.txt 110 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./log_syslog 2>>valgrind.txt 111 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./log_file 2>>valgrind.txt 112 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./log_combined 2>>valgrind.txt 113 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./log_journald 2>>valgrind.txt 114 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./log_callback 2>>valgrind.txt 115 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./log_newline 2>>valgrind.txt 116 | else 117 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./log_console 2>valgrind.txt 118 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./log_syslog 2>>valgrind.txt 119 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./log_file 2>>valgrind.txt 120 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./log_combined 2>>valgrind.txt 121 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./log_callback 2>>valgrind.txt 122 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./log_newline 2>>valgrind.txt 123 | endif 124 | -------------------------------------------------------------------------------- /examples/log_callback.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Yder example program 4 | * 5 | * This example program describes the main features 6 | * that are available in a callback function 7 | * 8 | * Copyright 2014-2020 Nicolas Mora 9 | * 10 | * License MIT 11 | * 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "yder.h" 19 | 20 | void y_callback_log_message(void * cls, const char * app_name, const time_t date, const unsigned long level, const char * message) { 21 | char *level_name, date_stamp[20]; 22 | struct tm * tm_stamp; 23 | 24 | tm_stamp = localtime (&date); 25 | 26 | #ifndef _WIN32 27 | strftime (date_stamp, sizeof(date_stamp), "%FT%TZ", tm_stamp); 28 | #else 29 | strftime (date_stamp, sizeof(date_stamp), "%Y-%m-%dT%H:%M:%S", tm_stamp); 30 | #endif 31 | switch (level) { 32 | case Y_LOG_LEVEL_ERROR: 33 | level_name = "ERROR"; 34 | break; 35 | case Y_LOG_LEVEL_WARNING: 36 | level_name = "WARNING"; 37 | break; 38 | case Y_LOG_LEVEL_INFO: 39 | level_name = "INFO"; 40 | break; 41 | case Y_LOG_LEVEL_DEBUG: 42 | level_name = "DEBUG"; 43 | break; 44 | default: 45 | level_name = "NONE"; 46 | break; 47 | } 48 | printf("Here is my callback log function\n- cls is %s\n- app_name is %s\n- date is %s\n- level is %s\n- message is '%s'\n\n", (char *)cls, app_name, date_stamp, level_name, message); 49 | } 50 | 51 | void write_logs(const char * level) { 52 | y_log_message(Y_LOG_LEVEL_ERROR, "This is an error message while level is %s", level); 53 | y_log_message(Y_LOG_LEVEL_WARNING, "This is a warning message while level is %s", level); 54 | y_log_message(Y_LOG_LEVEL_INFO, "This is an information message while level is %s", level); 55 | y_log_message(Y_LOG_LEVEL_DEBUG, "This is a debug message while level is %s", level); 56 | } 57 | 58 | int main(int argc, char ** argv) { 59 | char * level = NULL; 60 | char * cls = "my cls"; 61 | 62 | y_log_message(Y_LOG_LEVEL_ERROR, "This is an test error message without initialized logs"); 63 | 64 | if (y_init_logs("Yder Tests", Y_LOG_MODE_CALLBACK, Y_LOG_LEVEL_ERROR, NULL, "Initializing logs mode: callback, logs level: error") && y_set_logs_callback(&y_callback_log_message, cls, "callback init")) { 65 | level = "error"; 66 | write_logs(level); 67 | y_close_logs(); 68 | } 69 | 70 | if (y_init_logs("Yder Tests", Y_LOG_MODE_CALLBACK, Y_LOG_LEVEL_WARNING, NULL, "Initializing logs mode: callback, logs level: warning") && y_set_logs_callback(&y_callback_log_message, cls, "callback init")) { 71 | level = "warning"; 72 | write_logs(level); 73 | y_close_logs(); 74 | } 75 | 76 | if (y_init_logs("Yder Tests", Y_LOG_MODE_CALLBACK, Y_LOG_LEVEL_INFO, NULL, "Initializing logs mode: callback, logs level: info") && y_set_logs_callback(&y_callback_log_message, cls, "callback init")) { 77 | level = "info"; 78 | write_logs(level); 79 | y_close_logs(); 80 | } 81 | 82 | if (y_init_logs("Yder Tests", Y_LOG_MODE_CALLBACK, Y_LOG_LEVEL_DEBUG, NULL, "Initializing logs mode: callback, logs level: debug") && y_set_logs_callback(&y_callback_log_message, cls, "callback init")) { 83 | level = "debug"; 84 | write_logs(level); 85 | y_close_logs(); 86 | } 87 | 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /examples/log_combined.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Yder example program 4 | * 5 | * This example program describes the main features 6 | * that are available in a callback function 7 | * 8 | * Copyright 2014-2020 Nicolas Mora 9 | * 10 | * License MIT 11 | * 12 | */ 13 | 14 | #include 15 | #include 16 | #include "yder.h" 17 | 18 | void write_logs(const char * level) { 19 | y_log_message(Y_LOG_LEVEL_ERROR, "This is an error message while level is %s", level); 20 | y_log_message(Y_LOG_LEVEL_WARNING, "This is a warning message while level is %s", level); 21 | y_log_message(Y_LOG_LEVEL_INFO, "This is an information message while level is %s", level); 22 | y_log_message(Y_LOG_LEVEL_DEBUG, "This is a debug message while level is %s", level); 23 | } 24 | 25 | int main(int argc, char ** argv) { 26 | 27 | if (y_init_logs("Yder Tests", Y_LOG_MODE_FILE | Y_LOG_MODE_CONSOLE | Y_LOG_MODE_SYSLOG, Y_LOG_LEVEL_ERROR, "/tmp/yder_log_error_combined.log", "Initializing logs mode: console, logs level: error")) { 28 | write_logs("error"); 29 | y_close_logs(); 30 | } 31 | 32 | if (y_init_logs("Yder Tests", Y_LOG_MODE_FILE | Y_LOG_MODE_CONSOLE | Y_LOG_MODE_SYSLOG, Y_LOG_LEVEL_WARNING, "/tmp/yder_log_warning_combined.log", "Initializing logs mode: console, logs level: warning")) { 33 | write_logs("warning"); 34 | y_close_logs(); 35 | } 36 | 37 | if (y_init_logs("Yder Tests", Y_LOG_MODE_FILE | Y_LOG_MODE_CONSOLE | Y_LOG_MODE_SYSLOG, Y_LOG_LEVEL_INFO, "/tmp/yder_log_info_combined.log", "Initializing logs mode: console, logs level: info")) { 38 | write_logs("info"); 39 | y_close_logs(); 40 | } 41 | 42 | if (y_init_logs("Yder Tests", Y_LOG_MODE_FILE | Y_LOG_MODE_CONSOLE | Y_LOG_MODE_SYSLOG, Y_LOG_LEVEL_DEBUG, "/tmp/yder_log_debug_combined.log", "Initializing logs mode: console, logs level: debug")) { 43 | write_logs("debug"); 44 | y_close_logs(); 45 | } 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /examples/log_console.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Yder example program 4 | * 5 | * This example program describes the main features 6 | * that are available in a callback function 7 | * 8 | * Copyright 2014-2020 Nicolas Mora 9 | * 10 | * License MIT 11 | * 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include "yder.h" 18 | 19 | void write_logs(const char * level) { 20 | y_log_message(Y_LOG_LEVEL_ERROR, "This is an error message while level is %s", level); 21 | y_log_message(Y_LOG_LEVEL_WARNING, "This is a warning message while level is %s", level); 22 | y_log_message(Y_LOG_LEVEL_INFO, "This is an information message while level is %s", level); 23 | y_log_message(Y_LOG_LEVEL_DEBUG, "This is a debug message while level is %s", level); 24 | } 25 | 26 | int main(int argc, char ** argv) { 27 | char * level = NULL; 28 | 29 | y_log_message(Y_LOG_LEVEL_ERROR, "This is an test error message without initialized logs"); 30 | 31 | if (y_init_logs("Yder Tests", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_ERROR, NULL, "Initializing logs mode: console, logs level: error")) { 32 | level = "error"; 33 | write_logs(level); 34 | y_close_logs(); 35 | } 36 | 37 | if (y_init_logs("Yder Tests", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_WARNING, NULL, "Initializing logs mode: console, logs level: warning")) { 38 | level = "warning"; 39 | write_logs(level); 40 | y_close_logs(); 41 | } 42 | 43 | if (y_init_logs("Yder Tests", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_INFO, NULL, "Initializing logs mode: console, logs level: info")) { 44 | level = "info"; 45 | write_logs(level); 46 | y_close_logs(); 47 | } 48 | 49 | if (y_init_logs("Yder Tests", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG, NULL, "Initializing logs mode: console, logs level: debug")) { 50 | level = "debug"; 51 | write_logs(level); 52 | y_close_logs(); 53 | } 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /examples/log_file.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Yder example program 4 | * 5 | * This example program describes the main features 6 | * that are available in a callback function 7 | * 8 | * Copyright 2014-2020 Nicolas Mora 9 | * 10 | * License MIT 11 | * 12 | */ 13 | 14 | #include 15 | #include 16 | #include "yder.h" 17 | 18 | void write_logs(const char * level) { 19 | y_log_message(Y_LOG_LEVEL_ERROR, "This is an error message while level is %s", level); 20 | y_log_message(Y_LOG_LEVEL_WARNING, "This is a warning message while level is %s", level); 21 | y_log_message(Y_LOG_LEVEL_INFO, "This is an information message while level is %s", level); 22 | y_log_message(Y_LOG_LEVEL_DEBUG, "This is a debug message while level is %s", level); 23 | } 24 | 25 | int main(int argc, char ** argv) { 26 | 27 | if (y_init_logs("Yder Tests", Y_LOG_MODE_FILE, Y_LOG_LEVEL_ERROR, "/tmp/yder_log_error.log", "Initializing logs mode: file, logs level: error")) { 28 | write_logs("error"); 29 | y_close_logs(); 30 | } 31 | 32 | if (y_init_logs("Yder Tests", Y_LOG_MODE_FILE, Y_LOG_LEVEL_WARNING, "/tmp/yder_log_warning.log", "Initializing logs mode: file, logs level: warning")) { 33 | write_logs("warning"); 34 | y_close_logs(); 35 | } 36 | 37 | if (y_init_logs("Yder Tests", Y_LOG_MODE_FILE, Y_LOG_LEVEL_INFO, "/tmp/yder_log_info.log", "Initializing logs mode: file, logs level: info")) { 38 | write_logs("info"); 39 | y_close_logs(); 40 | } 41 | 42 | if (y_init_logs("Yder Tests", Y_LOG_MODE_FILE, Y_LOG_LEVEL_DEBUG, "/tmp/yder_log_debug.log", "Initializing logs mode: file, logs level: debug")) { 43 | write_logs("debug"); 44 | y_close_logs(); 45 | } 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /examples/log_journald.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Yder example program 4 | * 5 | * This example program describes the main features 6 | * that are available in a callback function 7 | * 8 | * Copyright 2014-2020 Nicolas Mora 9 | * 10 | * License MIT 11 | * 12 | */ 13 | 14 | #include 15 | #include 16 | #include "yder.h" 17 | 18 | #ifdef Y_DISABLE_JOURNALD 19 | #error "Journald log disabled" 20 | #endif 21 | 22 | void write_logs(const char * level) { 23 | y_log_message(Y_LOG_LEVEL_ERROR, "This is an error message while level is %s", level); 24 | y_log_message(Y_LOG_LEVEL_WARNING, "This is a warning message while level is %s", level); 25 | y_log_message(Y_LOG_LEVEL_INFO, "This is an information message while level is %s", level); 26 | y_log_message(Y_LOG_LEVEL_DEBUG, "This is a debug message while level is %s", level); 27 | } 28 | 29 | int main(int argc, char ** argv) { 30 | 31 | if (y_init_logs("Yder Tests", Y_LOG_MODE_JOURNALD, Y_LOG_LEVEL_ERROR, NULL, "Initializing logs mode: journald, logs level: error")) { 32 | write_logs("error"); 33 | y_close_logs(); 34 | } 35 | 36 | if (y_init_logs("Yder Tests", Y_LOG_MODE_JOURNALD, Y_LOG_LEVEL_WARNING, NULL, "Initializing logs mode: journald, logs level: warning")) { 37 | write_logs("warning"); 38 | y_close_logs(); 39 | } 40 | 41 | if (y_init_logs("Yder Tests", Y_LOG_MODE_JOURNALD, Y_LOG_LEVEL_INFO, NULL, "Initializing logs mode: journald, logs level: info")) { 42 | write_logs("info"); 43 | y_close_logs(); 44 | } 45 | 46 | if (y_init_logs("Yder Tests", Y_LOG_MODE_JOURNALD, Y_LOG_LEVEL_DEBUG, NULL, "Initializing logs mode: journald, logs level: debug")) { 47 | write_logs("debug"); 48 | y_close_logs(); 49 | } 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /examples/log_newline.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Yder example program 4 | * 5 | * This example program describes the main features 6 | * that are available in a callback function 7 | * 8 | * Copyright 2014-2020 Nicolas Mora 9 | * 10 | * License MIT 11 | * 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include "yder.h" 18 | 19 | void y_callback_log_message(void * cls, const char * app_name, const time_t date, const unsigned long level, const char * message) { 20 | char *level_name, date_stamp[20]; 21 | struct tm * tm_stamp; 22 | 23 | tm_stamp = localtime (&date); 24 | 25 | #ifndef _WIN32 26 | strftime (date_stamp, sizeof(date_stamp), "%FT%TZ", tm_stamp); 27 | #else 28 | strftime (date_stamp, sizeof(date_stamp), "%Y-%m-%dT%H:%M:%S", tm_stamp); 29 | #endif 30 | switch (level) { 31 | case Y_LOG_LEVEL_ERROR: 32 | level_name = "ERROR"; 33 | break; 34 | case Y_LOG_LEVEL_WARNING: 35 | level_name = "WARNING"; 36 | break; 37 | case Y_LOG_LEVEL_INFO: 38 | level_name = "INFO"; 39 | break; 40 | case Y_LOG_LEVEL_DEBUG: 41 | level_name = "DEBUG"; 42 | break; 43 | default: 44 | level_name = "NONE"; 45 | break; 46 | } 47 | printf("Here is my callback log function\n- cls is %s\n- app_name is %s\n- date is %s\n- level is %s\n- message is '%s'\n\n", (char *)cls, app_name, date_stamp, level_name, message); 48 | } 49 | 50 | int main(int argc, char ** argv) { 51 | char * cls = "my cls"; 52 | 53 | if (y_init_logs("Yder Tests", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG, NULL, "Initializing logs mode: console, logs level: debug")) { 54 | y_set_split_message_newline(1, "Set newline"); 55 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message in one line"); 56 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message in\ntwo lines"); 57 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message\nin\nfour\nlines"); 58 | y_close_logs(); 59 | } 60 | 61 | if (y_init_logs("Yder Tests", Y_LOG_MODE_FILE, Y_LOG_LEVEL_DEBUG, "/tmp/log_newline.log", "Initializing logs mode: file, logs level: debug")) { 62 | y_set_split_message_newline(1, "Set newline"); 63 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message in one line"); 64 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message in\ntwo lines"); 65 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message\nin\nfour\nlines"); 66 | y_close_logs(); 67 | } 68 | 69 | if (y_init_logs("Yder Tests", Y_LOG_MODE_JOURNALD, Y_LOG_LEVEL_DEBUG, NULL, "Initializing logs mode: journald, logs level: debug")) { 70 | y_set_split_message_newline(1, "Set newline"); 71 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message in one line"); 72 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message in\ntwo lines"); 73 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message\nin\nfour\nlines"); 74 | y_close_logs(); 75 | } 76 | 77 | if (y_init_logs("Yder Tests", Y_LOG_MODE_SYSLOG, Y_LOG_LEVEL_DEBUG, NULL, "Initializing logs mode: syslog, logs level: debug")) { 78 | y_set_split_message_newline(1, "Set newline"); 79 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message in one line"); 80 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message in\ntwo lines"); 81 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message\nin\nfour\nlines"); 82 | y_close_logs(); 83 | } 84 | 85 | if (y_init_logs("Yder Tests", Y_LOG_MODE_CALLBACK, Y_LOG_LEVEL_DEBUG, NULL, "Initializing logs mode: callback, logs level: warning") && y_set_logs_callback(&y_callback_log_message, cls, "callback init")) { 86 | y_set_split_message_newline(1, "Set newline"); 87 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message in one line"); 88 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message in\ntwo lines"); 89 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message\nin\nfour\nlines"); 90 | y_close_logs(); 91 | } 92 | 93 | if (y_init_logs("Yder Tests", Y_LOG_MODE_CONSOLE|Y_LOG_MODE_FILE|Y_LOG_MODE_CALLBACK, Y_LOG_LEVEL_DEBUG, "/tmp/log_newline_combined.log", "Initializing logs mode: file, logs level: debug") && y_set_logs_callback(&y_callback_log_message, cls, "callback init")) { 94 | y_set_split_message_newline(1, "Set newline"); 95 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message in one line"); 96 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message in\ntwo lines"); 97 | y_log_message(Y_LOG_LEVEL_DEBUG, "A message\nin\nfour\nlines"); 98 | y_close_logs(); 99 | } 100 | 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /examples/log_syslog.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Yder example program 4 | * 5 | * This example program describes the main features 6 | * that are available in a callback function 7 | * 8 | * Copyright 2014-2020 Nicolas Mora 9 | * 10 | * License MIT 11 | * 12 | */ 13 | 14 | #include 15 | #include 16 | #include "yder.h" 17 | 18 | void write_logs(const char * level) { 19 | y_log_message(Y_LOG_LEVEL_ERROR, "This is an error message while level is %s", level); 20 | y_log_message(Y_LOG_LEVEL_WARNING, "This is a warning message while level is %s", level); 21 | y_log_message(Y_LOG_LEVEL_INFO, "This is an information message while level is %s", level); 22 | y_log_message(Y_LOG_LEVEL_DEBUG, "This is a debug message while level is %s", level); 23 | } 24 | 25 | int main(int argc, char ** argv) { 26 | 27 | if (y_init_logs("Yder Tests", Y_LOG_MODE_SYSLOG, Y_LOG_LEVEL_ERROR, NULL, "Initializing logs mode: syslog, logs level: error")) { 28 | write_logs("error"); 29 | y_close_logs(); 30 | } 31 | 32 | if (y_init_logs("Yder Tests", Y_LOG_MODE_SYSLOG, Y_LOG_LEVEL_WARNING, NULL, "Initializing logs mode: syslog, logs level: warning")) { 33 | write_logs("warning"); 34 | y_close_logs(); 35 | } 36 | 37 | if (y_init_logs("Yder Tests", Y_LOG_MODE_SYSLOG, Y_LOG_LEVEL_INFO, NULL, "Initializing logs mode: syslog, logs level: info")) { 38 | write_logs("info"); 39 | y_close_logs(); 40 | } 41 | 42 | if (y_init_logs("Yder Tests", Y_LOG_MODE_SYSLOG, Y_LOG_LEVEL_DEBUG, NULL, "Initializing logs mode: syslog, logs level: debug")) { 43 | write_logs("debug"); 44 | y_close_logs(); 45 | } 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /include/yder-cfg.h.in: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Yder Framework 4 | * 5 | * Logging framework library 6 | * 7 | * yder-cfg.h: configuration file 8 | * 9 | * Copyright 2018-2022 Nicolas Mora 10 | * 11 | * This program is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public License 13 | * as published by the Free Software Foundation; 14 | * version 2.1 of the License. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU GENERAL PUBLIC LICENSE for more details. 20 | * 21 | * You should have received a copy of the GNU General Public 22 | * License along with this library. If not, see . 23 | * 24 | */ 25 | 26 | #ifndef _YDER_CFG_H_ 27 | #define _YDER_CFG_H_ 28 | 29 | #define YDER_VERSION ${PROJECT_VERSION} 30 | #define YDER_VERSION_STR "${PROJECT_VERSION}" 31 | 32 | #define YDER_VERSION_MAJOR ${PROJECT_VERSION_MAJOR} 33 | #define YDER_VERSION_MINOR ${PROJECT_VERSION_MINOR} 34 | #define YDER_VERSION_PATCH ${PROJECT_VERSION_PATCH} 35 | 36 | #define YDER_VERSION_NUMBER ((YDER_VERSION_MAJOR << 16) | (YDER_VERSION_MINOR << 8) | (YDER_VERSION_PATCH << 0)) 37 | 38 | #cmakedefine Y_DISABLE_JOURNALD 39 | 40 | #endif /* _YDER_CFG_H_ */ 41 | -------------------------------------------------------------------------------- /include/yder.h: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @file yder.h 4 | * @brief Yder framework 5 | * 6 | * Logging framework library 7 | * 8 | * yder.h: structures and functions declarations 9 | * 10 | * Copyright 2015-2022 Nicolas Mora 11 | * 12 | * This program is free software; you can redistribute it and/or 13 | * modify it under the terms of the GNU Lesser General Public License 14 | * as published by the Free Software Foundation; 15 | * version 2.1 of the License. 16 | * 17 | * This library is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU GENERAL PUBLIC LICENSE for more details. 21 | * 22 | * You should have received a copy of the GNU General Public 23 | * License along with this library. If not, see . 24 | * 25 | */ 26 | 27 | #ifndef __YDER_H__ 28 | #define __YDER_H__ 29 | 30 | #ifdef __cplusplus 31 | extern "C" 32 | { 33 | #endif 34 | 35 | #include "yder-cfg.h" 36 | 37 | #include 38 | 39 | /** 40 | * @defgroup const Constants 41 | * @{ 42 | */ 43 | 44 | #define Y_LOG_MODE_NONE 0x00000000 45 | #define Y_LOG_MODE_CONSOLE 0x000000F0 46 | #define Y_LOG_MODE_SYSLOG 0x00000F00 47 | #define Y_LOG_MODE_FILE 0x0000F000 48 | #define Y_LOG_MODE_JOURNALD 0x000F0000 49 | #define Y_LOG_MODE_CALLBACK 0x00F00000 50 | #define Y_LOG_MODE_CURRENT 0xFFFFFFFF 51 | 52 | #define Y_LOG_LEVEL_NONE 0x0000 53 | #define Y_LOG_LEVEL_ERROR 0x000F 54 | #define Y_LOG_LEVEL_WARNING 0x00F0 55 | #define Y_LOG_LEVEL_INFO 0x0F00 56 | #define Y_LOG_LEVEL_DEBUG 0xF000 57 | #define Y_LOG_LEVEL_CURRENT 0xFFFF 58 | 59 | #define Y_SPLIT_CURRENT -1 60 | /** 61 | * @} 62 | */ 63 | 64 | /** 65 | * @defgroup init Initialization and closing functions 66 | * @{ 67 | */ 68 | 69 | /** 70 | * Initialize logging with mode and level parameters, specify a log file if needed 71 | * @param app: the name of the application that will be included in all log messages 72 | * @param init_mode: log mode, values available are 73 | * Y_LOG_MODE_NONE, Y_LOG_MODE_CONSOLE, Y_LOG_MODE_SYSLOG, Y_LOG_MODE_FILE, Y_LOG_MODE_JOURNALD 74 | * Multiple log modes are possible, values must be stacked, ex: Y_LOG_MODE_SYSLOG|Y_LOG_MODE_JOURNALD 75 | * @param init_level: minimum level of the log messages 76 | * Values available are Y_LOG_LEVEL_NONE, Y_LOG_LEVEL_ERROR, Y_LOG_LEVEL_WARNING, Y_LOG_LEVEL_INFO or Y_LOG_LEVEL_DEBUG 77 | * @param init_log_file: path to the file that will contain the log messages if log mode Y_LOG_MODE_FILE is selected 78 | * @param message: first message that will be appear in the logs 79 | * @return 1 on success, 0 on error 80 | */ 81 | int y_init_logs(const char * app, const unsigned long init_mode, const unsigned long init_level, const char * init_log_file, const char * message); 82 | 83 | /** 84 | * Specify a callback function that will catch all log messages 85 | * In addition to other logs output already defined in y_init_logs 86 | * @param y_callback_log_message a pointer to a user-defined callback function 87 | * @param cls a user-defined pointer that will be available on y_callback_log_message 88 | * @param message message that will be appear in the logs 89 | * @return 1 on success, 0 on error 90 | */ 91 | int y_set_logs_callback(void (* y_callback_log_message) (void * cls, const char * app_name, const time_t date, const unsigned long level, const char * message), 92 | void * cls, 93 | const char * message); 94 | 95 | /** 96 | * Specify a date format for console and file logging 97 | * Uses strftime syntax 98 | * @param format date format using strftime syntax 99 | * @param message message that will be appear in the logs 100 | * @return 1 on success, 0 on error 101 | */ 102 | int y_set_date_format(const char * format, const char * message); 103 | 104 | /** 105 | * Specify if the log messages must be splitted when a newline is in it 106 | * This function may have incidence on the application speed, 107 | * because it adds more memory allocations on each log message. 108 | * I recommend to use it only if relevant 109 | * @param split 0 to disable splitted logs, 1 to enable 110 | * @param message message that will be appear in the logs 111 | * @return 1 on success, 0 on error 112 | */ 113 | int y_set_split_message_newline(int split, const char * message); 114 | 115 | /** 116 | * Close the logs 117 | * @return 1 on success, 0 on error 118 | */ 119 | int y_close_logs(void); 120 | 121 | /** 122 | * @} 123 | */ 124 | 125 | /** 126 | * @defgroup log Logging function 127 | * @{ 128 | */ 129 | 130 | /** 131 | * Log a message using current parameters 132 | * @param type type of the log message 133 | * Values available are Y_LOG_LEVEL_ERROR, Y_LOG_LEVEL_WARNING, Y_LOG_LEVEL_INFO or Y_LOG_LEVEL_DEBUG 134 | * @param message the message to log, using printf format 135 | */ 136 | void y_log_message(const unsigned long type, const char * message, ...); 137 | 138 | /** 139 | * @} 140 | */ 141 | 142 | #ifdef __cplusplus 143 | } 144 | #endif 145 | 146 | #endif // __YDER_H__ 147 | -------------------------------------------------------------------------------- /libyder.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=@CMAKE_INSTALL_PREFIX@ 3 | libdir=@PKGCONFIG_TARGET_LIBDIR@ 4 | includedir=@PKGCONFIG_TARGET_INCLUDES@ 5 | 6 | Name: @PROJECT_NAME@ 7 | Description: @PROJECT_DESCRIPTION@ 8 | URL: @PROJECT_BUGREPORT_PATH@ 9 | Version: @LIBRARY_VERSION@ 10 | Requires: @PKGCONF_REQ@ 11 | Requires.private: @PKGCONF_REQ_PRIVATE@ 12 | Libs: -L${libdir} -lyder -lorcania @LIB_STATIC@ 13 | Cflags: -I${includedir} 14 | 15 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Yder Framework 3 | # 4 | # Makefile used to build the software 5 | # 6 | # Copyright 2015-2022 Nicolas Mora 7 | # 8 | # This program is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public License 10 | # as published by the Free Software Foundation; 11 | # version 2.1 of the License. 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU GENERAL PUBLIC LICENSE for more details. 17 | # 18 | # You should have received a copy of the GNU General Public 19 | # License along with this library. If not, see . 20 | # 21 | PROJECT_NAME=yder 22 | PROJECT_DESCRIPTION=Logging library for C applications 23 | PROJECT_BUGREPORT_PATH=https://github.com/babelouest/yder/issues 24 | PKGCONF_REQ= 25 | PKGCONF_REQ_PRIVATE= 26 | DESTDIR=/usr/local 27 | YDER_INCLUDE=../include 28 | CONFIG_TEMPLATE=$(YDER_INCLUDE)/yder-cfg.h.in 29 | CONFIG_FILE=$(YDER_INCLUDE)/yder-cfg.h 30 | PKGCONFIG_FILE=../libyder.pc 31 | PKGCONFIG_TEMPLATE=../libyder.pc.in 32 | CC=gcc 33 | CFLAGS+=-c -fPIC -Wall -Werror -Wextra -Wconversion -Wpedantic -D_REENTRANT -I$(YDER_INCLUDE) $(ADDITIONALFLAGS) $(CPPFLAGS) 34 | LIBS=-lc -lorcania 35 | OUTPUT=libyder.so 36 | VERSION_MAJOR=1 37 | VERSION_MINOR=4 38 | VERSION_PATCH=21 39 | 40 | SONAME = -soname 41 | ifeq ($(shell uname -s),Darwin) 42 | SONAME = -install_name 43 | endif 44 | 45 | ifndef Y_DISABLE_JOURNALD 46 | DISABLE_JOURNALD=0 47 | LIBSYSTEMD=-lsystemd 48 | else 49 | DISABLE_JOURNALD=1 50 | endif 51 | 52 | all: release 53 | 54 | $(CONFIG_FILE): 55 | @cp $(CONFIG_TEMPLATE) $(CONFIG_FILE) 56 | @echo Config file $(CONFIG_FILE) generated 57 | @sed -i -e 's/$${PROJECT_VERSION}/$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH)/g' $(CONFIG_FILE) 58 | @sed -i -e 's/$${PROJECT_VERSION_MAJOR}/$(VERSION_MAJOR)/g' $(CONFIG_FILE) 59 | @sed -i -e 's/$${PROJECT_VERSION_MINOR}/$(VERSION_MINOR)/g' $(CONFIG_FILE) 60 | @sed -i -e 's/$${PROJECT_VERSION_PATCH}/$(VERSION_PATCH)/g' $(CONFIG_FILE) 61 | @sed -i -e 's/$${PROJECT_VERSION_NUMBER}/$(shell printf '%02d' $(VERSION_MAJOR))$(shell printf '%02d' $(VERSION_MINOR))$(shell printf '%02d' $(VERSION_PATCH))/g' $(CONFIG_FILE) 62 | @if [ "$(DISABLE_JOURNALD)" = "1" ]; then \ 63 | echo "JOURNALD SUPPORT DISABLED"; \ 64 | sed -i -e 's/\#cmakedefine Y_DISABLE_JOURNALD/\#define Y_DISABLE_JOURNALD/g' $(CONFIG_FILE); \ 65 | else \ 66 | echo "JOURNALD SUPPORT ENABLED"; \ 67 | sed -i -e 's/\#cmakedefine Y_DISABLE_JOURNALD/\/* #undef Y_DISABLE_JOURNALD *\//g' $(CONFIG_FILE); \ 68 | fi 69 | 70 | $(PKGCONFIG_FILE): 71 | @cp $(PKGCONFIG_TEMPLATE) $(PKGCONFIG_FILE) 72 | @echo Pkgconfig file $(PKGCONFIG_FILE) generated 73 | @sed -i -e 's#@CMAKE_INSTALL_PREFIX@#$(DESTDIR)#g' $(PKGCONFIG_FILE) 74 | @sed -i -e 's#@PKGCONFIG_TARGET_LIBDIR@#$${prefix}/lib#g' $(PKGCONFIG_FILE) 75 | @sed -i -e 's#@PKGCONFIG_TARGET_INCLUDES@#$${prefix}/include#g' $(PKGCONFIG_FILE) 76 | @sed -i -e 's/@PROJECT_NAME@/$(PROJECT_NAME)/g' $(PKGCONFIG_FILE) 77 | @sed -i -e 's/@PROJECT_DESCRIPTION@/$(PROJECT_DESCRIPTION)/g' $(PKGCONFIG_FILE) 78 | @sed -i -e 's|@PROJECT_BUGREPORT_PATH@|$(PROJECT_BUGREPORT_PATH)|g' $(PKGCONFIG_FILE) 79 | @sed -i -e 's/@LIBRARY_VERSION@/$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH)/g' $(PKGCONFIG_FILE) 80 | @sed -i -e 's/@PKGCONF_REQ@/$(PKGCONF_REQ)/g' $(PKGCONFIG_FILE) 81 | @sed -i -e 's/@PKGCONF_REQ_PRIVATE@/$(PKGCONF_REQ_PRIVATE)/g' $(PKGCONFIG_FILE) 82 | @sed -i -e 's/@LIB_STATIC@/$(LIB_STATIC)/g' $(PKGCONFIG_FILE) 83 | 84 | libyder.so: yder.o $(PKGCONFIG_FILE) 85 | $(CC) -shared -fPIC -Wl,$(SONAME),$(OUTPUT) -o $(OUTPUT).$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH) yder.o $(LIBS) $(LIBSYSTEMD) $(LDFLAGS) 86 | ln -sf $(OUTPUT).$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH) $(OUTPUT) 87 | 88 | libyder.a: yder.o $(PKGCONFIG_FILE) 89 | ar rcs libyder.a yder.o 90 | 91 | yder.o: $(CONFIG_FILE) $(YDER_INCLUDE)/yder.h yder.c 92 | $(CC) $(CFLAGS) yder.c 93 | 94 | clean: 95 | rm -f *.o *.so *.a $(OUTPUT) $(PKGCONFIG_FILE) $(OUTPUT).* $(YDER_INCLUDE)/yder-cfg.h 96 | 97 | install: all 98 | install $(OUTPUT).$(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_PATCH) $(DESTDIR)/lib 99 | mkdir -p $(DESTDIR)/lib/pkgconfig/ $(DESTDIR)/include 100 | install -m644 $(PKGCONFIG_FILE) $(DESTDIR)/lib/pkgconfig/ 101 | install -m644 $(YDER_INCLUDE)/yder.h $(DESTDIR)/include 102 | install -m644 $(CONFIG_FILE) $(DESTDIR)/include 103 | -ldconfig $(DESTDIR)/lib 104 | 105 | static-install: static 106 | install libyder.a $(DESTDIR)/lib 107 | mkdir -p $(DESTDIR)/lib/pkgconfig/ $(DESTDIR)/include 108 | install -m644 $(PKGCONFIG_FILE) $(DESTDIR)/lib/pkgconfig 109 | install -m644 $(YDER_INCLUDE)/yder.h $(DESTDIR)/include 110 | install -m644 $(CONFIG_FILE) $(DESTDIR)/include 111 | 112 | uninstall: 113 | rm -f $(DESTDIR)/lib/$(OUTPUT) $(DESTDIR)/lib/libyder.a 114 | rm -f $(DESTDIR)/lib/$(OUTPUT).* 115 | rm -f $(DESTDIR)/include/yder.h 116 | rm -f $(DESTDIR)/include/$(CONFIG_FILE) 117 | rm -f $(DESTDIR)/lib/pkgconfig/$(PKGCONFIG_FILE) 118 | 119 | debug: ADDITIONALFLAGS=-DDEBUG -g -O0 120 | 121 | debug: libyder.so 122 | 123 | release: ADDITIONALFLAGS=-O3 124 | 125 | release: libyder.so 126 | 127 | static-debug: ADDITIONALFLAGS=-DDEBUG -g -O0 128 | 129 | static-debug: libyder.a 130 | 131 | static: ADDITIONALFLAGS=-O3 132 | 133 | static: libyder.a 134 | 135 | static: LIB_STATIC=$(LIBSYSTEMD) 136 | 137 | -------------------------------------------------------------------------------- /src/yder.c: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Yder Framework 4 | * 5 | * Logging framework library 6 | * 7 | * yder.h: structures and functions declarations 8 | * 9 | * Copyright 2015-2022 Nicolas Mora 10 | * 11 | * This program is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU Lesser General Public License 13 | * as published by the Free Software Foundation; 14 | * version 2.1 of the License. 15 | * 16 | * This library is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU GENERAL PUBLIC LICENSE for more details. 20 | * 21 | * You should have received a copy of the GNU General Public 22 | * License along with this library. If not, see . 23 | * 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include "yder.h" 33 | 34 | #ifndef _WIN32 35 | #include 36 | #ifndef Y_DISABLE_JOURNALD 37 | #include 38 | #endif 39 | #endif 40 | 41 | /** 42 | * Write log message to console output (stdout or stderr) 43 | */ 44 | static void y_write_log_console(const char * app_name, const char * date_format, const time_t date, const unsigned long level, const char * message, int split) { 45 | char * level_name = NULL, date_stamp[64], ** message_split = NULL; 46 | FILE * output = NULL; 47 | struct tm tm_stamp; 48 | size_t i; 49 | 50 | #ifdef _WIN32 51 | gmtime_s(&tm_stamp, &date); 52 | #else 53 | gmtime_r(&date, &tm_stamp); 54 | #endif 55 | 56 | if (date_format == NULL) { 57 | #ifndef _WIN32 58 | strftime (date_stamp, sizeof(date_stamp), "%FT%TZ", &tm_stamp); 59 | #else 60 | strftime (date_stamp, sizeof(date_stamp), "%Y-%m-%dT%H:%M:%S", &tm_stamp); 61 | #endif 62 | } else { 63 | strftime (date_stamp, sizeof(date_stamp), date_format, &tm_stamp); 64 | } 65 | switch (level) { 66 | case Y_LOG_LEVEL_ERROR: 67 | level_name = "ERROR"; 68 | break; 69 | case Y_LOG_LEVEL_WARNING: 70 | level_name = "WARNING"; 71 | break; 72 | case Y_LOG_LEVEL_INFO: 73 | level_name = "INFO"; 74 | break; 75 | case Y_LOG_LEVEL_DEBUG: 76 | level_name = "DEBUG"; 77 | break; 78 | default: 79 | level_name = "NONE"; 80 | break; 81 | } 82 | if (level & Y_LOG_LEVEL_WARNING || level & Y_LOG_LEVEL_ERROR) { 83 | // Write to stderr 84 | output = stderr; 85 | } else { 86 | // Write to stdout 87 | output = stdout; 88 | } 89 | if (split == 1) { 90 | if (split_string(message, "\n", &message_split)) { 91 | for (i=0; message_split[i] != NULL; i++) { 92 | fprintf(output, "%s - %s %s: %s\n", date_stamp, app_name, level_name, message_split[i]); 93 | } 94 | free_string_array(message_split); 95 | } 96 | } else { 97 | fprintf(output, "%s - %s %s: %s\n", date_stamp, app_name, level_name, message); 98 | } 99 | fflush(output); 100 | } 101 | 102 | #ifndef _WIN32 103 | /** 104 | * Write log message to syslog 105 | */ 106 | static void y_write_log_syslog(const char * app_name, const unsigned long level, const char * message) { 107 | openlog(app_name, LOG_PID|LOG_CONS, LOG_USER); 108 | switch (level) { 109 | case Y_LOG_LEVEL_ERROR: 110 | syslog( LOG_ERR, "%s", message ); 111 | break; 112 | case Y_LOG_LEVEL_WARNING: 113 | syslog( LOG_WARNING, "%s", message ); 114 | break; 115 | case Y_LOG_LEVEL_INFO: 116 | syslog( LOG_INFO, "%s", message ); 117 | break; 118 | case Y_LOG_LEVEL_DEBUG: 119 | syslog( LOG_DEBUG, "%s", message ); 120 | break; 121 | } 122 | closelog(); 123 | } 124 | 125 | #ifndef Y_DISABLE_JOURNALD 126 | /** 127 | * Write log message to journald 128 | */ 129 | static void y_write_log_journald(const char * app_name, const unsigned long level, const char * message) { 130 | switch (level) { 131 | case Y_LOG_LEVEL_ERROR: 132 | sd_journal_print( LOG_ERR, "%s - %s", app_name, message ); 133 | break; 134 | case Y_LOG_LEVEL_WARNING: 135 | sd_journal_print( LOG_WARNING, "%s - %s", app_name, message ); 136 | break; 137 | case Y_LOG_LEVEL_INFO: 138 | sd_journal_print( LOG_INFO, "%s - %s", app_name, message ); 139 | break; 140 | case Y_LOG_LEVEL_DEBUG: 141 | sd_journal_print( LOG_DEBUG, "%s - %s", app_name, message ); 142 | break; 143 | } 144 | } 145 | #endif 146 | #endif 147 | 148 | /** 149 | * Append log message to the log file 150 | */ 151 | static void y_write_log_file(const char * app_name, const char * date_format, const time_t date, FILE * log_file, const unsigned long level, const char * message, int split) { 152 | char * level_name = NULL, date_stamp[64], ** message_split = NULL; 153 | struct tm tm_stamp; 154 | size_t i; 155 | 156 | if (log_file != NULL) { 157 | #ifdef _WIN32 158 | gmtime_s(&tm_stamp, &date); 159 | #else 160 | gmtime_r(&date, &tm_stamp); 161 | #endif 162 | if (date_format == NULL) { 163 | #ifndef _WIN32 164 | strftime (date_stamp, sizeof(date_stamp), "%FT%TZ", &tm_stamp); 165 | #else 166 | strftime (date_stamp, sizeof(date_stamp), "%Y-%m-%dT%H:%M:%S", &tm_stamp); 167 | #endif 168 | } else { 169 | strftime (date_stamp, sizeof(date_stamp), date_format, &tm_stamp); 170 | } 171 | switch (level) { 172 | case Y_LOG_LEVEL_ERROR: 173 | level_name = "ERROR"; 174 | break; 175 | case Y_LOG_LEVEL_WARNING: 176 | level_name = "WARNING"; 177 | break; 178 | case Y_LOG_LEVEL_INFO: 179 | level_name = "INFO"; 180 | break; 181 | case Y_LOG_LEVEL_DEBUG: 182 | level_name = "DEBUG"; 183 | break; 184 | default: 185 | level_name = "NONE"; 186 | break; 187 | } 188 | if (split == 1) { 189 | if (split_string(message, "\n", &message_split)) { 190 | for (i=0; message_split[i] != NULL; i++) { 191 | fprintf(log_file, "%s - %s %s: %s\n", date_stamp, app_name, level_name, message_split[i]); 192 | } 193 | free_string_array(message_split); 194 | } 195 | } else { 196 | fprintf(log_file, "%s - %s %s: %s\n", date_stamp, app_name, level_name, message); 197 | } 198 | fflush(log_file); 199 | } 200 | } 201 | 202 | /** 203 | * Main function for logging messages 204 | * Warning ! Contains static variables used for not having to pass general configuration values every time you call log_message 205 | */ 206 | static int y_write_log(const char * app_name, 207 | const unsigned long init_mode, 208 | const unsigned long init_level, 209 | const char * init_log_file, 210 | void (* y_callback_log_message) (void * cls, const char * app_name, const time_t date, const unsigned long level, const char * message), 211 | void * cls, 212 | const char * date_format, 213 | int split, 214 | const unsigned long level, 215 | const char * message) { 216 | static unsigned long cur_mode = Y_LOG_MODE_NONE, cur_level = Y_LOG_LEVEL_NONE; 217 | FILE * cur_log_file = NULL; 218 | static char * cur_app_name = NULL; 219 | static const char * cur_log_file_path = NULL; 220 | static void (* cur_callback_log_message) (void * cls, const char * app_name, const time_t date, const unsigned long level, const char * message) = NULL; 221 | static void * cur_cls = NULL; 222 | static char * cur_date_format = NULL; 223 | static int cur_split = 0; 224 | time_t now; 225 | char ** message_split = NULL; 226 | size_t i; 227 | 228 | // Closing logs: free cur_app_name 229 | if (app_name == NULL && 230 | init_mode == Y_LOG_MODE_NONE && 231 | init_level == Y_LOG_LEVEL_NONE && 232 | init_log_file == NULL && 233 | level == Y_LOG_LEVEL_NONE && 234 | message == NULL) { 235 | o_free(cur_app_name); 236 | o_free(cur_date_format); 237 | cur_app_name = NULL; 238 | return 1; 239 | } 240 | 241 | time(&now); 242 | 243 | if (init_mode != Y_LOG_MODE_CURRENT) { 244 | cur_mode = init_mode; 245 | } 246 | 247 | if (init_level != Y_LOG_LEVEL_CURRENT) { 248 | cur_level = init_level; 249 | } 250 | 251 | if (y_callback_log_message != NULL) { 252 | cur_callback_log_message = y_callback_log_message; 253 | cur_cls = cls; 254 | } 255 | 256 | if (date_format != NULL) { 257 | o_free(cur_date_format); 258 | cur_date_format = o_strdup(date_format); 259 | } 260 | 261 | if (split != Y_SPLIT_CURRENT) { 262 | cur_split = split; 263 | } 264 | 265 | if (cur_mode == Y_LOG_MODE_NONE && cur_level == Y_LOG_LEVEL_NONE) { 266 | // Logs have not been initialized, cancel 267 | return 0; 268 | } 269 | 270 | if (init_log_file != NULL) { 271 | if (cur_log_file_path == NULL) { 272 | cur_log_file_path = init_log_file; 273 | } else { 274 | // Logs have already been initialized, cancel 275 | perror("Error - yder logs already initialized"); 276 | return 0; 277 | } 278 | } 279 | 280 | if (app_name != NULL) { 281 | if (cur_app_name == NULL) { 282 | cur_app_name = o_strdup(app_name); 283 | } else { 284 | // Logs have already been initialized, cancel 285 | perror("Error - yder logs already initialized"); 286 | return 0; 287 | } 288 | } 289 | 290 | if (init_mode == Y_LOG_MODE_FILE && o_strnullempty(cur_log_file_path)) { 291 | // Logs have already been initialized, cancel 292 | perror("Error - log file path missing"); 293 | return 0; 294 | } 295 | 296 | if (cur_log_file_path != NULL) { 297 | if ((cur_log_file = fopen(cur_log_file_path, "a+")) == NULL) { 298 | fprintf(stderr, "%s - ", cur_log_file_path); 299 | perror("Error opening log file"); 300 | cur_log_file_path = NULL; 301 | o_free(cur_app_name); 302 | o_free(cur_date_format); 303 | cur_app_name = NULL; 304 | return 0; 305 | } 306 | } 307 | 308 | // write message to expected output if level expected 309 | if (cur_level >= level) { 310 | if (message != NULL) { 311 | if (cur_mode & Y_LOG_MODE_CONSOLE) { 312 | y_write_log_console(cur_app_name, cur_date_format, now, level, message, cur_split); 313 | } 314 | #ifndef _WIN32 315 | if (cur_mode & Y_LOG_MODE_SYSLOG) { 316 | y_write_log_syslog(cur_app_name, level, message); 317 | } 318 | #endif 319 | 320 | #if !defined(_WIN32) && !defined(Y_DISABLE_JOURNALD) 321 | if (cur_mode & Y_LOG_MODE_JOURNALD) { 322 | y_write_log_journald(cur_app_name, level, message); 323 | } 324 | #endif 325 | if (cur_mode & Y_LOG_MODE_FILE) { 326 | y_write_log_file(cur_app_name, cur_date_format, now, cur_log_file, level, message, cur_split); 327 | } 328 | if (cur_mode & Y_LOG_MODE_CALLBACK && cur_callback_log_message != NULL) { 329 | if (cur_split == 1) { 330 | if (split_string(message, "\n", &message_split)) { 331 | for (i=0; message_split[i] != NULL; i++) { 332 | cur_callback_log_message(cur_cls, cur_app_name, now, level, message_split[i]); 333 | } 334 | free_string_array(message_split); 335 | } 336 | } else { 337 | cur_callback_log_message(cur_cls, cur_app_name, now, level, message); 338 | } 339 | } 340 | } 341 | } 342 | 343 | if (cur_log_file != NULL && cur_log_file_path != NULL) { 344 | if (fclose(cur_log_file) != 0) { 345 | perror("Error closing log file"); 346 | return 0; 347 | } 348 | } 349 | 350 | return 1; 351 | } 352 | 353 | int y_init_logs(const char * app, const unsigned long init_mode, const unsigned long init_level, const char * init_log_file, const char * message) { 354 | #ifdef _WIN32 355 | if (init_mode & Y_LOG_MODE_SYSLOG) { 356 | perror("syslog mode not supported on your architecture"); 357 | return 0; 358 | } 359 | #endif 360 | 361 | #if defined(_WIN32) || defined(Y_DISABLE_JOURNALD) 362 | if (init_mode & Y_LOG_MODE_JOURNALD) { 363 | perror("journald mode not supported on your architecture"); 364 | return 0; 365 | } 366 | #endif 367 | 368 | return y_write_log(app, init_mode, init_level, init_log_file, NULL, NULL, NULL, Y_SPLIT_CURRENT, Y_LOG_LEVEL_INFO, message); 369 | } 370 | 371 | int y_set_logs_callback(void (* y_callback_log_message) (void * cls, const char * app_name, const time_t date, const unsigned long level, const char * message), 372 | void * cls, 373 | const char * message) { 374 | if (y_callback_log_message != NULL) { 375 | return y_write_log(NULL, Y_LOG_MODE_CURRENT, Y_LOG_LEVEL_CURRENT, NULL, y_callback_log_message, cls, NULL, Y_SPLIT_CURRENT, Y_LOG_LEVEL_INFO, message); 376 | } else { 377 | return 0; 378 | } 379 | } 380 | 381 | int y_set_date_format(const char * format, const char * message) { 382 | if (!o_strnullempty(format)) { 383 | return y_write_log(NULL, Y_LOG_MODE_CURRENT, Y_LOG_LEVEL_CURRENT, NULL, NULL, NULL, format, Y_SPLIT_CURRENT, Y_LOG_LEVEL_INFO, message); 384 | } else { 385 | return 0; 386 | } 387 | } 388 | 389 | int y_set_split_message_newline(int split, const char * message) { 390 | return y_write_log(NULL, Y_LOG_MODE_CURRENT, Y_LOG_LEVEL_CURRENT, NULL, NULL, NULL, NULL, split, Y_LOG_LEVEL_INFO, message); 391 | } 392 | 393 | int y_close_logs(void) { 394 | return y_write_log(NULL, 0, 0, NULL, NULL, NULL, NULL, Y_SPLIT_CURRENT, 0, NULL); 395 | } 396 | 397 | void y_log_message(const unsigned long level, const char * message, ...) { 398 | va_list args, args_cpy; 399 | size_t out_len = 0; 400 | char * out = NULL; 401 | int v_out = 0; 402 | va_start(args, message); 403 | // Use va_copy to make a new args pointer to avoid problems with vsnprintf which can change args parameter on some architectures 404 | va_copy(args_cpy, args); 405 | if ((v_out = vsnprintf(NULL, 0, message, args)) >= 0) { 406 | out_len = (size_t)v_out; 407 | out = o_malloc((out_len + 1)); 408 | if (out != NULL) { 409 | vsnprintf(out, (out_len + 1), message, args_cpy); 410 | y_write_log(NULL, Y_LOG_MODE_CURRENT, Y_LOG_LEVEL_CURRENT, NULL, NULL, NULL, NULL, Y_SPLIT_CURRENT, level, out); 411 | o_free(out); 412 | } 413 | } 414 | va_end(args); 415 | va_end(args_cpy); 416 | } 417 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | yder_test 2 | valgrind-*.txt 3 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Public domain, no copyright. Use at your own risk. 3 | # 4 | 5 | CC=gcc 6 | CFLAGS+=-Wall -Werror -Wextra -D_REENTRANT -DDEBUG -g -O0 -I$(INCLUDE_LOCATION) $(CPPFLAGS) 7 | YDER_LOCATION=../src 8 | INCLUDE_LOCATION=../include 9 | YDER_LIBRARY=$(YDER_LOCATION)/libyder.so 10 | LDFLAGS=-lc -lorcania -lyder $(shell pkg-config --libs check) -L$(YDER_LOCATION) 11 | TARGET=yder_test 12 | VALGRIND_COMMAND=valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all 13 | VERBOSE=0 14 | MEMCHECK=0 15 | 16 | all: test 17 | 18 | clean: 19 | rm -f *.o $(TARGET) *.log valgrind-*.txt 20 | 21 | $(YDER_LIBRARY): $(YDER_LOCATION)/yder.c $(INCLUDE_LOCATION)/yder.h 22 | cd $(YDER_LOCATION) && $(MAKE) debug $* 23 | 24 | %: $(YDER_LIBRARY) %.c 25 | $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) 26 | 27 | test: $(YDER_LIBRARY) $(TARGET) test_yder_test 28 | 29 | check: test 30 | 31 | test_%: % $(YDER_LIBRARY) 32 | @if [ "$(VERBOSE)" = "0" ] && [ "$(MEMCHECK)" = "0" ]; then \ 33 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./run_test.sh ./$^; \ 34 | elif [ "$(MEMCHECK)" = "0" ]; then \ 35 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} ./$^ ; \ 36 | else \ 37 | LD_LIBRARY_PATH=$(YDER_LOCATION):${LD_LIBRARY_PATH} $(VALGRIND_COMMAND) ./$^ 2>valgrind-$@.txt; \ 38 | fi 39 | -------------------------------------------------------------------------------- /test/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | printf_new() { 4 | str=$1 5 | num=$2 6 | v=$(printf "%-${num}s" "$str") 7 | printf "${v// / }" 8 | } 9 | 10 | RED='\033[0;31m' 11 | GREEN='\033[0;32m' 12 | NC='\033[0m' # No Color 13 | COMMAND=$1 14 | CHRLEN=${#COMMAND} 15 | NBSP=$((32-$CHRLEN)) 16 | 17 | printf "Run $1" 18 | printf_new " " $NBSP 19 | 20 | $1 $2 $3 $4 $5 $6 $7 $8 $9 1>$1.log 2>&1 21 | 22 | if [ $? -ne 0 ] 23 | then 24 | printf "${RED}FAIL${NC}\n" 25 | else 26 | printf "${GREEN}SUCCESS${NC}\n" 27 | fi 28 | -------------------------------------------------------------------------------- /test/yder_test.c: -------------------------------------------------------------------------------- 1 | /* Public domain, no copyright. Use at your own risk. */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include "yder.h" 12 | 13 | #define UNUSED(x) (void)(x) 14 | 15 | char message[1024]; 16 | char app_name[128]; 17 | int level; 18 | 19 | void unit_test_callback(void * cls, const char * log_app_name, const time_t date, const unsigned long log_level, const char * log_message) { 20 | UNUSED(date); 21 | strcpy(app_name, log_app_name); 22 | strcpy(cls, log_message); 23 | level = log_level; 24 | } 25 | 26 | void unit_test_newline(void * cls, const char * log_app_name, const time_t date, const unsigned long log_level, const char * log_message) { 27 | UNUSED(log_app_name); 28 | UNUSED(date); 29 | UNUSED(log_level); 30 | int * count = (int *)cls; 31 | ck_assert_int_gt(o_strlen(log_message), 0); 32 | (*count)++; 33 | } 34 | 35 | START_TEST(test_yder_init_console) 36 | { 37 | ck_assert_int_eq(y_init_logs("test_yder_console", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG, NULL, "first test"), 1); 38 | y_close_logs(); 39 | } 40 | END_TEST 41 | 42 | START_TEST(test_yder_init_file) 43 | { 44 | ck_assert_int_eq(y_init_logs("test_yder_file", Y_LOG_MODE_FILE, Y_LOG_LEVEL_DEBUG, "/tmp/test.log", "second test"), 1); 45 | y_close_logs(); 46 | } 47 | END_TEST 48 | 49 | START_TEST(test_yder_init_syslog) 50 | { 51 | #ifndef _WIN32 52 | ck_assert_int_eq(y_init_logs("test_yder_syslog", Y_LOG_MODE_SYSLOG, Y_LOG_LEVEL_DEBUG, NULL, "third test"), 1); 53 | y_close_logs(); 54 | #else 55 | ck_assert_int_eq(y_init_logs("test_yder_syslog", Y_LOG_MODE_SYSLOG, Y_LOG_LEVEL_DEBUG, NULL, "third test"), 0); 56 | #endif 57 | } 58 | END_TEST 59 | 60 | START_TEST(test_yder_init_journald) 61 | { 62 | #if !defined(_WIN32) && !defined(Y_DISABLE_JOURNALD) 63 | ck_assert_int_eq(y_init_logs("test_yder_journald", Y_LOG_MODE_JOURNALD, Y_LOG_LEVEL_DEBUG, NULL, "fourth test"), 1); 64 | y_close_logs(); 65 | #else 66 | ck_assert_int_eq(y_init_logs("test_yder_journald", Y_LOG_MODE_JOURNALD, Y_LOG_LEVEL_DEBUG, NULL, "fourth test"), 0); 67 | #endif 68 | } 69 | END_TEST 70 | 71 | START_TEST(test_yder_init_error_file) 72 | { 73 | ck_assert_int_eq(y_init_logs("test_yder_file_fail", Y_LOG_MODE_FILE, Y_LOG_LEVEL_DEBUG, "/nope/nope", "second test"), 0); 74 | ck_assert_int_eq(y_init_logs("test_yder_file_fail", Y_LOG_MODE_FILE, Y_LOG_LEVEL_DEBUG, "", "second test"), 0); 75 | ck_assert_int_eq(y_init_logs("test_yder_file_fail", Y_LOG_MODE_FILE, Y_LOG_LEVEL_DEBUG, NULL, "second test"), 0); 76 | } 77 | END_TEST 78 | 79 | START_TEST(test_yder_callback) 80 | { 81 | message[0] = '\0'; 82 | app_name[0] = '\0'; 83 | char * app_name_orig = "test_yder_callback"; 84 | ck_assert_int_eq(y_init_logs(app_name_orig, Y_LOG_MODE_CALLBACK, Y_LOG_LEVEL_DEBUG, NULL, "test_yder_callback"), 1); 85 | ck_assert_int_eq(y_set_logs_callback(NULL, NULL, NULL), 0); 86 | level = Y_LOG_LEVEL_NONE; 87 | ck_assert_int_eq(y_set_logs_callback(&unit_test_callback, message, "Start callback unit tests"), 1); 88 | ck_assert_str_eq(message, "Start callback unit tests"); 89 | ck_assert_str_eq(app_name, app_name_orig); 90 | ck_assert_int_eq(level, Y_LOG_LEVEL_INFO); 91 | 92 | message[0] = '\0'; 93 | app_name[0] = '\0'; 94 | level = Y_LOG_LEVEL_NONE; 95 | y_log_message(Y_LOG_LEVEL_DEBUG, "first test"); 96 | ck_assert_str_eq(message, "first test"); 97 | ck_assert_str_eq(app_name, app_name_orig); 98 | ck_assert_int_eq(level, Y_LOG_LEVEL_DEBUG); 99 | 100 | message[0] = '\0'; 101 | app_name[0] = '\0'; 102 | level = Y_LOG_LEVEL_NONE; 103 | y_log_message(Y_LOG_LEVEL_DEBUG, "second test with parameter: %d", 42); 104 | ck_assert_str_eq(message, "second test with parameter: 42"); 105 | ck_assert_str_eq(app_name, app_name_orig); 106 | ck_assert_int_eq(level, Y_LOG_LEVEL_DEBUG); 107 | 108 | message[0] = '\0'; 109 | app_name[0] = '\0'; 110 | level = Y_LOG_LEVEL_NONE; 111 | y_log_message(Y_LOG_LEVEL_DEBUG, ""); 112 | ck_assert_str_eq(message, ""); 113 | ck_assert_str_eq(app_name, app_name_orig); 114 | ck_assert_int_eq(level, Y_LOG_LEVEL_DEBUG); 115 | 116 | y_close_logs(); 117 | } 118 | END_TEST 119 | 120 | START_TEST(test_yder_init_multiple_error) 121 | { 122 | ck_assert_int_eq(y_init_logs("test_yder_console", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG, NULL, "first test"), 1); 123 | ck_assert_int_eq(y_init_logs("test_yder_console", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG, NULL, "first test"), 0); 124 | y_close_logs(); 125 | } 126 | END_TEST 127 | 128 | START_TEST(test_yder_init_multiple_ok) 129 | { 130 | ck_assert_int_eq(y_init_logs("test_yder_console", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG, NULL, "first test"), 1); 131 | ck_assert_int_eq(y_close_logs(), 1); 132 | ck_assert_int_eq(y_init_logs("test_yder_console", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG, NULL, "first test"), 1); 133 | ck_assert_int_eq(y_close_logs(), 1); 134 | } 135 | END_TEST 136 | 137 | START_TEST(test_yder_init_close_multiple) 138 | { 139 | ck_assert_int_eq(y_close_logs(), 1); 140 | ck_assert_int_eq(y_init_logs("test_yder_console", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG, NULL, "first test"), 1); 141 | ck_assert_int_eq(y_close_logs(), 1); 142 | ck_assert_int_eq(y_close_logs(), 1); 143 | } 144 | END_TEST 145 | 146 | START_TEST(test_yder_level_debug) 147 | { 148 | ck_assert_int_eq(y_init_logs("test_yder_level_debug", Y_LOG_MODE_CALLBACK, Y_LOG_LEVEL_DEBUG, NULL, "test_yder_level_debug"), 1); 149 | ck_assert_int_eq(y_set_logs_callback(&unit_test_callback, message, "Start callback unit tests"), 1); 150 | 151 | message[0] = '\0'; 152 | y_log_message(Y_LOG_LEVEL_DEBUG, "first test"); 153 | ck_assert_str_eq(message, "first test"); 154 | 155 | message[0] = '\0'; 156 | y_log_message(Y_LOG_LEVEL_INFO, "second test"); 157 | ck_assert_str_eq(message, "second test"); 158 | 159 | message[0] = '\0'; 160 | y_log_message(Y_LOG_LEVEL_WARNING, "third test"); 161 | ck_assert_str_eq(message, "third test"); 162 | 163 | message[0] = '\0'; 164 | y_log_message(Y_LOG_LEVEL_ERROR, "fourth test"); 165 | ck_assert_str_eq(message, "fourth test"); 166 | 167 | y_close_logs(); 168 | } 169 | END_TEST 170 | 171 | START_TEST(test_yder_level_info) 172 | { 173 | ck_assert_int_eq(y_init_logs("test_yder_level_info", Y_LOG_MODE_CALLBACK, Y_LOG_LEVEL_INFO, NULL, "test_yder_level_info"), 1); 174 | ck_assert_int_eq(y_set_logs_callback(&unit_test_callback, message, "Start callback unit tests"), 1); 175 | 176 | message[0] = '\0'; 177 | y_log_message(Y_LOG_LEVEL_DEBUG, "first test"); 178 | ck_assert_str_eq(message, ""); 179 | 180 | message[0] = '\0'; 181 | y_log_message(Y_LOG_LEVEL_INFO, "second test"); 182 | ck_assert_str_eq(message, "second test"); 183 | 184 | message[0] = '\0'; 185 | y_log_message(Y_LOG_LEVEL_WARNING, "third test"); 186 | ck_assert_str_eq(message, "third test"); 187 | 188 | message[0] = '\0'; 189 | y_log_message(Y_LOG_LEVEL_ERROR, "fourth test"); 190 | ck_assert_str_eq(message, "fourth test"); 191 | 192 | y_close_logs(); 193 | } 194 | END_TEST 195 | 196 | START_TEST(test_yder_level_warning) 197 | { 198 | ck_assert_int_eq(y_init_logs("test_yder_level_warning", Y_LOG_MODE_CALLBACK, Y_LOG_LEVEL_WARNING, NULL, "test_yder_level_warning"), 1); 199 | ck_assert_int_eq(y_set_logs_callback(&unit_test_callback, message, "Start callback unit tests"), 1); 200 | 201 | message[0] = '\0'; 202 | y_log_message(Y_LOG_LEVEL_DEBUG, "first test"); 203 | ck_assert_str_eq(message, ""); 204 | 205 | message[0] = '\0'; 206 | y_log_message(Y_LOG_LEVEL_INFO, "second test"); 207 | ck_assert_str_eq(message, ""); 208 | 209 | message[0] = '\0'; 210 | y_log_message(Y_LOG_LEVEL_WARNING, "third test"); 211 | ck_assert_str_eq(message, "third test"); 212 | 213 | message[0] = '\0'; 214 | y_log_message(Y_LOG_LEVEL_ERROR, "fourth test"); 215 | ck_assert_str_eq(message, "fourth test"); 216 | 217 | y_close_logs(); 218 | } 219 | END_TEST 220 | 221 | START_TEST(test_yder_level_error) 222 | { 223 | ck_assert_int_eq(y_init_logs("test_yder_level_error", Y_LOG_MODE_CALLBACK, Y_LOG_LEVEL_ERROR, NULL, "test_yder_level_error"), 1); 224 | ck_assert_int_eq(y_set_logs_callback(&unit_test_callback, message, "Start callback unit tests"), 1); 225 | 226 | message[0] = '\0'; 227 | y_log_message(Y_LOG_LEVEL_DEBUG, "first test"); 228 | ck_assert_str_eq(message, ""); 229 | 230 | message[0] = '\0'; 231 | y_log_message(Y_LOG_LEVEL_INFO, "second test"); 232 | ck_assert_str_eq(message, ""); 233 | 234 | message[0] = '\0'; 235 | y_log_message(Y_LOG_LEVEL_WARNING, "third test"); 236 | ck_assert_str_eq(message, ""); 237 | 238 | message[0] = '\0'; 239 | y_log_message(Y_LOG_LEVEL_ERROR, "fourth test"); 240 | ck_assert_str_eq(message, "fourth test"); 241 | 242 | y_close_logs(); 243 | } 244 | END_TEST 245 | 246 | START_TEST(test_yder_date_format) 247 | { 248 | ck_assert_int_eq(y_init_logs("test_yder_date_format", Y_LOG_MODE_CONSOLE, Y_LOG_LEVEL_DEBUG, NULL, "date format test"), 1); 249 | ck_assert_int_eq(y_set_date_format(NULL, "error"), 0); 250 | ck_assert_int_eq(y_set_date_format("TEST %Y - :%S", "success"), 1); 251 | y_log_message(Y_LOG_LEVEL_DEBUG, "first test"); 252 | y_close_logs(); 253 | } 254 | END_TEST 255 | 256 | START_TEST(test_yder_newline_split) 257 | { 258 | int count = 0; 259 | ck_assert_int_eq(y_init_logs("test_yder_newline_split", Y_LOG_MODE_CALLBACK, Y_LOG_LEVEL_DEBUG, NULL, "yder_newline_split"), 1); 260 | ck_assert_int_eq(y_set_logs_callback(&unit_test_newline, &count, "Start newline unit tests"), 1); 261 | ck_assert_int_eq(y_set_split_message_newline(1, "Set newline"), 1); 262 | count = 0; 263 | y_log_message(Y_LOG_LEVEL_DEBUG, "first test, one line"); 264 | ck_assert_int_eq(count, 1); 265 | count = 0; 266 | y_log_message(Y_LOG_LEVEL_DEBUG, "second test\ntwo lines"); 267 | ck_assert_int_eq(count, 2); 268 | count = 0; 269 | y_log_message(Y_LOG_LEVEL_DEBUG, "third test\nfour\nlines\nahead"); 270 | ck_assert_int_eq(count, 4); 271 | y_close_logs(); 272 | } 273 | END_TEST 274 | 275 | static Suite *yder_suite(void) 276 | { 277 | Suite *s; 278 | TCase *tc_core; 279 | 280 | s = suite_create("Yder tests functions"); 281 | tc_core = tcase_create("test_yder"); 282 | tcase_add_test(tc_core, test_yder_init_console); 283 | tcase_add_test(tc_core, test_yder_init_file); 284 | tcase_add_test(tc_core, test_yder_init_syslog); 285 | tcase_add_test(tc_core, test_yder_init_journald); 286 | tcase_add_test(tc_core, test_yder_init_error_file); 287 | tcase_add_test(tc_core, test_yder_init_multiple_error); 288 | tcase_add_test(tc_core, test_yder_init_multiple_ok); 289 | tcase_add_test(tc_core, test_yder_init_close_multiple); 290 | tcase_add_test(tc_core, test_yder_callback); 291 | tcase_add_test(tc_core, test_yder_level_debug); 292 | tcase_add_test(tc_core, test_yder_level_info); 293 | tcase_add_test(tc_core, test_yder_level_warning); 294 | tcase_add_test(tc_core, test_yder_level_error); 295 | tcase_add_test(tc_core, test_yder_date_format); 296 | tcase_add_test(tc_core, test_yder_newline_split); 297 | tcase_set_timeout(tc_core, 30); 298 | suite_add_tcase(s, tc_core); 299 | 300 | return s; 301 | } 302 | 303 | int main(void) 304 | { 305 | int number_failed; 306 | Suite *s; 307 | SRunner *sr; 308 | 309 | s = yder_suite(); 310 | sr = srunner_create(s); 311 | 312 | srunner_run_all(sr, CK_VERBOSE); 313 | number_failed = srunner_ntests_failed(sr); 314 | srunner_free(sr); 315 | 316 | return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 317 | } 318 | --------------------------------------------------------------------------------