Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter

- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
This commit is contained in:
Eric F
2026-06-08 00:38:27 -04:00
parent 468cfeaa50
commit d398a6ced2
7326 changed files with 1177561 additions and 7 deletions

View File

@@ -0,0 +1,2 @@
*build
workspace.yaml

View File

@@ -0,0 +1,3 @@
if (BUILD_BACKTRACE_SUPPORT)
add_subdirectory(libbacktrace)
endif()

View File

@@ -0,0 +1,64 @@
include(ExternalProject)
# set flags correct configure flags if cross compiling
if (CMAKE_CROSSCOMPILING)
if (ENV{CONFIGURE_FLAGS})
separate_arguments(CONFIGURE_FLAGS UNIX_COMMAND $ENV{CONFIGURE_FLAGS})
else ()
string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}-${CMAKE_HOST_SYSTEM_NAME}" CONFIGURE_BUILD_SYSTEM)
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}-${CMAKE_SYSTEM_NAME}" CONFIGURE_HOST_SYSTEM)
list(APPEND CONFIGURE_FLAGS "--host=${CONFIGURE_HOST_SYSTEM}" "--build=${CONFIGURE_BUILD_SYSTEM}")
endif()
if (NOT ENV{CC})
set (CONFIGURE_ENV "CC=${CMAKE_C_COMPILER}")
endif ()
endif ()
ExternalProject_Add(
libbacktrace
# download
GIT_REPOSITORY https://github.com/ianlancetaylor/libbacktrace
GIT_TAG 4d2dd0b172f2c9192f83ba93425f868f2a13c553
GIT_SHALLOW false
# update
UPDATE_COMMAND ""
# configure
CONFIGURE_COMMAND
${CMAKE_COMMAND} -E env ${CONFIGURE_ENV}
<SOURCE_DIR>/configure
${CONFIGURE_FLAGS}
--prefix=<INSTALL_DIR>
--includedir=<INSTALL_DIR>/include/backtrace
--libdir=<INSTALL_DIR>/lib
--enable-static=yes
--disable-shared
# build options
BUILD_ALWAYS false
# specify byproducts
BUILD_BYPRODUCTS <INSTALL_DIR>/lib/libbacktrace.a
# log options
LOG_DOWNLOAD true
LOG_CONFIGURE true
LOG_BUILD true
LOG_INSTALL true
LOG_OUTPUT_ON_FAILURE true
)
add_library(
backtrace
STATIC IMPORTED GLOBAL
)
add_dependencies(backtrace libbacktrace)
ExternalProject_Get_Property(libbacktrace INSTALL_DIR)
# hack to get INTERFACE_INCLUDE_DIRECTORIES working
# see https://gitlab.kitware.com/cmake/cmake/-/issues/15052
file(MAKE_DIRECTORY ${INSTALL_DIR}/include)
set_target_properties(
backtrace
PROPERTIES
IMPORTED_LOCATION ${INSTALL_DIR}/lib/libbacktrace.a
INTERFACE_INCLUDE_DIRECTORIES ${INSTALL_DIR}/include
)

View File

@@ -0,0 +1,17 @@
load("@rules_cc//cc:defs.bzl", "cc_library")
cc_library(
name = "liblog",
srcs = glob(["lib/*.cpp"]),
hdrs = glob(["include/**/*.hpp"]),
deps = [
"@boost.utility",
"@boost.exception",
"@boost.log",
],
visibility = [
"//visibility:public",
],
strip_include_prefix = "include",
cxxopts = ["-std=c++17"],
)

View File

@@ -0,0 +1,136 @@
cmake_minimum_required(VERSION 3.16)
project(everest-log
VERSION 0.3.0
DESCRIPTION "EVerest logging library"
LANGUAGES CXX C
)
find_package(everest-cmake 0.5 REQUIRED
PATHS ../everest-cmake
)
# options
option(BUILD_BACKTRACE_SUPPORT "Build with backtrace support from libbacktrace" OFF)
option(${PROJECT_NAME}_BUILD_TESTING "Build unit tests, used if included as dependency" OFF)
option(BUILD_TESTING "Run unit tests" OFF)
option(BUILD_EXAMPLES "Build liblog example binaries." OFF)
option(LOG_INSTALL "Install the library (shared data might be installed anyway)" ${EVC_MAIN_PROJECT})
option(CMAKE_RUN_CLANG_TIDY "Run clang-tidy" OFF)
option(LIBLOG_USE_BOOST_FILESYSTEM "Usage of boost/filesystem.hpp instead of std::filesystem" OFF)
if((${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME} OR ${PROJECT_NAME}_BUILD_TESTING) AND BUILD_TESTING)
set(EVEREST_LIBLOG_BUILD_TESTING ON)
# this policy allows us to link gcov to targets defined in other directories
if(POLICY CMP0079)
set(CMAKE_POLICY_DEFAULT_CMP0079 NEW)
endif()
endif()
if (NOT DISABLE_EDM)
evc_setup_edm()
# In EDM mode, we can't install exports (because the dependencies usually do not install their exports)
set(LOG_INSTALL OFF)
else()
if (EVEREST_LIBLOG_BUILD_TESTING)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/release-1.12.1.zip
)
FetchContent_MakeAvailable(googletest)
endif()
endif()
# library dependencies
if (LIBLOG_USE_BOOST_FILESYSTEM)
message(STATUS "Using boost/filesystem instead of std::filesystem")
find_package(Boost COMPONENTS log_setup log filesystem REQUIRED)
else()
find_package(Boost COMPONENTS log_setup log REQUIRED)
endif()
# third party dependencies
add_subdirectory(3rd_party)
# logging library
add_subdirectory(lib)
# packaging
install(
FILES examples/logging.ini
DESTINATION ${CMAKE_INSTALL_DATADIR}/everest/log
RENAME example-config.ini
)
if (LOG_INSTALL)
set_target_properties(everest_log PROPERTIES EXPORT_NAME log)
install(
TARGETS everest_log
EXPORT log-targets
)
install(
DIRECTORY include/
TYPE INCLUDE
)
if (BUILD_BACKTRACE_SUPPORT)
# FIXME (aw): if statically build, we would need to install libbacktrace too
endif()
evc_setup_package(
NAME everest-log
NAMESPACE everest
EXPORT log-targets
ADDITIONAL_CONTENT
"find_dependency(Boost COMPONENTS log_setup log)"
)
endif()
# testing
if(EVEREST_LIBLOG_BUILD_TESTING)
include(CTest)
add_subdirectory(tests)
set(CMAKE_BUILD_TYPE Debug)
endif()
if(BUILD_EXAMPLES)
message("Building liblog example binaries.")
add_subdirectory(examples)
else()
message("Not building liblog example binaries.")
endif()
# configure clang-tidy if requested
if(CMAKE_RUN_CLANG_TIDY)
message("Running clang-tidy")
string(CONCAT CLANG_TIDY_CHECKS "*,"
"-llvmlibc*,"
"-fuchsia-default-arguments-calls,"
"-fuchsia-overloaded-operator,"
"-fuchsia-statically-constructed-objects,"
"-readability-function-cognitive-complexity,"
"-modernize-use-trailing-return-type,"
"-abseil-string-find-startswith,"
"-abseil-string-find-str-contains,"
";")
set(CMAKE_CXX_CLANG_TIDY
clang-tidy;
-header-filter='.*'
-checks=${CLANG_TIDY_CHECKS})
endif()
# build doxygen documentation if doxygen is available
find_package(Doxygen)
if(DOXYGEN_FOUND)
set( DOXYGEN_OUTPUT_DIRECTORY dist/docs )
doxygen_add_docs(doxygen-${PROJECT_NAME} include lib src)
else()
message("Doxygen is needed to generate documentation")
endif()

View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,40 @@
# C++ logging and exceptions library for the EVerest framework
Provides a common infrastructure for all EVerest modules on logging, wrapped around Boost.Log.
All documentation and the issue tracking can be found in our main repository here: https://github.com/EVerest/everest
## Build instructions
==================
Clone the repository:
```bash
git clone https://github.com/EVerest/liblog
```
Create a folder named build and cd into it.
Execute cmake and then make install:
```bash
mkdir build && cd build
cmake ..
make install
```
To check your code with clang-tidy you can use the following cmake
command:
```
cmake .. -DCMAKE_RUN_CLANG_TIDY=ON make
```
To run unit tests and generate a code coverage report you can run the
following commands:
```
make && make install && make gcovr_coverage
```
The coverage report will be available in the index.html file in the
```build/gcovr_coverage``` directory.

View File

@@ -0,0 +1,5 @@
# Third-party dependencies used by this project
- [CodeCoverage.cmake](https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake) licensed under [The 3-Clause BSD License](https://opensource.org/licenses/BSD-3-Clause)
- [Macros for metaprogramming](https://github.com/jspahrsummers/libextobjc/blob/master/extobjc/metamacros.h) licensed under [The MIT License](https://opensource.org/licenses/MIT)
- [libbacktrace](https://github.com/ianlancetaylor/libbacktrace) licensed under [The 3-Clause BSD License](https://opensource.org/licenses/BSD-3-Clause)

View File

@@ -0,0 +1,5 @@
---
gtest:
git: https://github.com/google/googletest.git
git_tag: release-1.12.1
cmake_condition: "EVEREST_LIBLOG_BUILD_TESTING"

View File

@@ -0,0 +1,13 @@
find_package(Boost COMPONENTS program_options REQUIRED)
add_executable(main main.cpp)
target_link_libraries(main
PRIVATE
everest::log
Boost::program_options
)
add_executable(test_trace test_trace.cpp)
target_link_libraries(test_trace PRIVATE
everest::log
)

View File

@@ -0,0 +1,18 @@
# for documentation on this file format see:
# https://www.boost.org/doc/libs/1_54_0/libs/log/doc/html/log/detailed/utilities.html#log.detailed.utilities.setup.filter_formatter
[Core]
DisableLogging=false
Filter="%Severity% >= VERB"
[Sinks.Console]
Destination=Console
# Filter="%Target% contains \"MySink1\""
Format="%TimeStamp% \033[1;32m%Process%\033[0m [\033[1;32m%ProcessID%\033[0m] [%Severity%] {\033[1;34m%ThreadID%\033[0m} \033[1;36m%function%\033[0m \033[1;30m%file%:\033[0m\033[1;32m%line%\033[0m: %Message%"
Asynchronous=false
AutoFlush=true
SeverityStringColorDebug="\033[1;30m"
SeverityStringColorInfo="\033[1;37m"
SeverityStringColorWarning="\033[1;33m"
SeverityStringColorError="\033[1;31m"
SeverityStringColorCritical="\033[1;35m"

View File

@@ -0,0 +1,18 @@
# for documentation on this file format see:
# https://www.boost.org/doc/libs/1_54_0/libs/log/doc/html/log/detailed/utilities.html#log.detailed.utilities.setup.filter_formatter
[Core]
DisableLogging=false
Filter="%Severity% >= DEBG"
[Sinks.Console]
Destination=Console
# Filter="%Target% contains \"MySink1\""
Format="%TimeStamp% \033[1;32m%Process%\033[0m [\033[1;32m%ProcessID%\033[0m] [%Severity%] {\033[1;34m%ThreadID%\033[0m} \033[1;36m%function%\033[0m \033[1;30m%file%:\033[0m\033[1;32m%line%\033[0m: %Message%"
Asynchronous=false
AutoFlush=true
SeverityStringColorDebug="\033[1;30m"
SeverityStringColorInfo="\033[1;37m"
SeverityStringColorWarning="\033[1;33m"
SeverityStringColorError="\033[1;31m"
SeverityStringColorCritical="\033[1;35m"

View File

@@ -0,0 +1,66 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include <everest/logging.hpp>
#include <iostream>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/program_options.hpp>
namespace po = boost::program_options;
int main(int argc, char* argv[]) {
po::options_description desc("EVerest::log example");
desc.add_options()("help,h", "produce help message");
desc.add_options()("logconf", po::value<std::string>(), "The path to a custom logging.ini");
desc.add_options()("logconfreinit", po::value<std::string>(), "The path to a custom logging.ini");
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
if (vm.count("help") != 0) {
std::cout << desc << "\n";
return 1;
}
// initialize logging as early as possible
Everest::Logging::init();
// since we initialized without any config the following messages should not logged at all:
EVLOG_verbose << "This is a VERBOSE message.";
EVLOG_debug << "This is a DEBUG message.";
EVLOG_info << "This is a INFO message.";
EVLOG_warning << "This is a WARNING message.";
EVLOG_error << "This is a ERROR message.";
EVLOG_critical << "This is a CRITICAL message.";
std::string logging_config = "logging.ini";
if (vm.count("logconf") != 0) {
logging_config = vm["logconf"].as<std::string>();
}
Everest::Logging::init(logging_config, "hello there");
EVLOG_debug << "logging_config was set to " << logging_config;
EVLOG_verbose << "This is a VERBOSE message.";
EVLOG_debug << "This is a DEBUG message.";
EVLOG_info << "This is a INFO message.";
EVLOG_warning << "This is a WARNING message.";
EVLOG_error << "This is a ERROR message.";
EVLOG_critical << "This is a CRITICAL message.";
std::string logging_config_reinit = "logging_reinit.ini";
if (vm.count("logconfreinit") != 0) {
logging_config_reinit = vm["logconfreinit"].as<std::string>();
}
Everest::Logging::init(logging_config_reinit, "hello reinit");
EVLOG_verbose << "This is a VERBOSE message after reinit.";
EVLOG_debug << "This is a DEBUG message after reinit.";
EVLOG_info << "This is a INFO message after reinit.";
EVLOG_warning << "This is a WARNING message after reinit.";
EVLOG_error << "This is a ERROR message after reinit.";
EVLOG_critical << "This is a CRITICAL message after reinit.";
return 0;
}

View File

@@ -0,0 +1,47 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2022 Pionix GmbH and Contributors to EVerest
#include <everest/logging.hpp>
#include <iostream>
class TraceTest {
public:
static void do_trace(bool) {
std::cout << Everest::Logging::trace();
}
};
void bax() {
std::cout << Everest::Logging::trace();
}
bool baz(const char* str) {
auto lambda = [&str](int& i) {
i++;
bax();
};
int test = 41;
lambda(test);
return true;
}
extern "C" {
void bar(int) {
baz("Please trace ...");
}
}
void foo() {
bar(85);
}
int main(int argc, char* argv[]) {
TraceTest::do_trace(true);
foo();
return 0;
}

View File

@@ -0,0 +1,76 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2021 Pionix GmbH and Contributors to EVerest
#ifndef EXCEPTIONS_HPP
#define EXCEPTIONS_HPP
#include <boost/exception/exception.hpp>
#include <everest/metamacros.hpp>
#include <sstream>
#include <stdexcept>
#include <string>
namespace Everest {
///
/// \brief base class for all everest logic exceptions
class EverestBaseError : public boost::exception {
public:
///
/// \brief base constructor for all everest exceptions, inherited from boost::exception
EverestBaseError() {
}
};
///
/// \brief base class for all everest logic exceptions
class EverestBaseLogicError : public EverestBaseError, public std::logic_error {
public:
///
/// \brief base constructor for all everest exceptions, inherited from std::logic_error
explicit EverestBaseLogicError(const std::string& what) : std::logic_error(what) {
}
};
///
/// \brief base class for all everest runtime exceptions
class EverestBaseRuntimeError : public EverestBaseError, public std::runtime_error {
public:
///
/// \brief base constructor for all everest exceptions, inherited from std::runtime_error
explicit EverestBaseRuntimeError(const std::string& what) : std::runtime_error(what) {
}
};
///
/// \brief represents an internal error, like a missing configuration file
class EverestInternalError : public EverestBaseRuntimeError {
public:
using EverestBaseRuntimeError::EverestBaseRuntimeError;
};
///
/// \brief represents a configuration error, like a malformed configuration entry
class EverestConfigError : public EverestBaseLogicError {
using EverestBaseLogicError::EverestBaseLogicError;
};
///
/// \brief represents a API error, like tring to call a non-existing command
class EverestApiError : public EverestBaseLogicError {
public:
using EverestBaseLogicError::EverestBaseLogicError;
};
///
/// \brief represents a timeout error, like tring to call a not answering command
class EverestTimeoutError : public EverestBaseRuntimeError {
public:
using EverestBaseRuntimeError::EverestBaseRuntimeError;
};
} // namespace Everest
#define EVEXCEPTION(ex, ...) \
ex((static_cast<const std::ostringstream&>(metamacro_foreach(_EVEXCEPTION_INTERNALS, <<, __VA_ARGS__))).str())
#define _EVEXCEPTION_INTERNALS(index, arg) metamacro_if_eq(0, index)(std::ostringstream() << arg)(arg)
#endif // EXCEPTIONS_HPP

View File

@@ -0,0 +1,110 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2022 Pionix GmbH and Contributors to EVerest
#ifndef LOGGING_HPP
#define LOGGING_HPP
#include <boost/current_function.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/log/attributes/attribute_set.hpp>
#include <boost/log/attributes/mutable_constant.hpp>
#include <boost/log/attributes/named_scope.hpp>
#include <boost/log/sources/global_logger_storage.hpp>
#include <boost/log/sources/severity_logger.hpp>
#include <boost/log/support/exception.hpp>
#include <boost/log/utility/manipulators/add_value.hpp>
#include <boost/throw_exception.hpp>
#include <exception>
#include <string>
namespace Everest {
namespace Logging {
enum severity_level {
verbose,
debug,
info,
warning,
error,
critical,
};
/// \brief Initialize a completely silenced logger
/// \return -1 for off.
int init();
/// \brief Initialize logger using the config pointed to by \p logconf
/// \return minimum accepted severity level (-1=off, 0=verbose .. 5=critical)
int init(const std::string& logconf);
/// \brief Initialize logger using the config pointed to by \p logconf additionally setting the \p process_name
/// \return minimum accepted severity level (-1=off, 0=verbose .. 5=critical)
int init(const std::string& logconf, std::string process_name);
/// \brief Logging function for foreign language interfaces.
void ffi_log(int level, int line, const std::string& file, const std::string& message);
void update_process_name(std::string process_name);
std::string trace();
} // namespace Logging
#ifdef EVEREST_DISABLE_VERBOSE_LOGGING
#define EVLOG_verbose \
if (true) { \
} else \
BOOST_LOG_SEV(::global_logger::get(), ::Everest::Logging::verbose)
#else
// clang-format off
#define EVLOG_verbose \
BOOST_LOG_SEV(::global_logger::get(), ::Everest::Logging::verbose) \
<< boost::log::BOOST_LOG_VERSION_NAMESPACE::add_value("file", __FILE__) \
<< boost::log::BOOST_LOG_VERSION_NAMESPACE::add_value("line", __LINE__) \
<< boost::log::BOOST_LOG_VERSION_NAMESPACE::add_value("function", BOOST_CURRENT_FUNCTION)
#endif
#ifdef EVEREST_DISABLE_DEBUG_LOGGING
#define EVLOG_debug if (true) {} else BOOST_LOG_SEV(::global_logger::get(), ::Everest::Logging::debug)
#else
#define EVLOG_debug \
BOOST_LOG_SEV(::global_logger::get(), ::Everest::Logging::debug) \
<< boost::log::BOOST_LOG_VERSION_NAMESPACE::add_value("function", BOOST_CURRENT_FUNCTION)
#endif
#define EVLOG_info \
BOOST_LOG_SEV(::global_logger::get(), ::Everest::Logging::info)
#define EVLOG_warning \
BOOST_LOG_SEV(::global_logger::get(), ::Everest::Logging::warning) \
<< boost::log::BOOST_LOG_VERSION_NAMESPACE::add_value("function", BOOST_CURRENT_FUNCTION)
#define EVLOG_error \
BOOST_LOG_SEV(::global_logger::get(), ::Everest::Logging::error) \
<< boost::log::BOOST_LOG_VERSION_NAMESPACE::add_value("function", BOOST_CURRENT_FUNCTION)
#define EVLOG_critical \
BOOST_LOG_SEV(::global_logger::get(), ::Everest::Logging::critical) \
<< boost::log::BOOST_LOG_VERSION_NAMESPACE::add_value("function", BOOST_CURRENT_FUNCTION)
// clang-format on
#define EVLOG_AND_THROW(ex) \
do { \
try { \
BOOST_THROW_EXCEPTION(boost::enable_error_info(ex) \
<< boost::log::BOOST_LOG_VERSION_NAMESPACE::current_scope()); \
} catch (std::exception & e) { \
EVLOG_error << e.what(); \
throw; \
} \
} while (0)
#define EVTHROW(ex) \
do { \
BOOST_THROW_EXCEPTION(boost::enable_error_info(ex) \
<< boost::log::BOOST_LOG_VERSION_NAMESPACE::current_scope()); \
} while (0)
} // namespace Everest
BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(
global_logger,
boost::log::BOOST_LOG_VERSION_NAMESPACE::sources::severity_logger_mt<Everest::Logging::severity_level>)
#endif // LOGGING_HPP

View File

@@ -0,0 +1,551 @@
/**
* Macros for metaprogramming
* ExtendedC
*
* Copyright (C) 2012 Justin Spahr-Summers
* Released under the MIT license
*/
#ifndef EXTC_METAMACROS_H
#define EXTC_METAMACROS_H
/**
* Executes one or more expressions (which may have a void type, such as a call
* to a function that returns no value) and always returns true.
*/
#define metamacro_exprify(...) ((__VA_ARGS__), true)
/**
* Returns a string representation of VALUE after full macro expansion.
*/
#define metamacro_stringify(VALUE) metamacro_stringify_(VALUE)
/**
* Returns A and B concatenated after full macro expansion.
*/
#define metamacro_concat(A, B) metamacro_concat_(A, B)
/**
* Returns the Nth variadic argument (starting from zero). At least
* N + 1 variadic arguments must be given. N must be between zero and twenty,
* inclusive.
*/
#define metamacro_at(N, ...) metamacro_concat(metamacro_at, N)(__VA_ARGS__)
/**
* Returns the number of arguments (up to twenty) provided to the macro. At
* least one argument must be provided.
*
* Inspired by P99: http://p99.gforge.inria.fr
*/
#define metamacro_argcount(...) \
metamacro_at(20, ##__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
/**
* Identical to #metamacro_foreach_cxt, except that no CONTEXT argument is
* given. Only the index and current argument will thus be passed to MACRO.
*/
#define metamacro_foreach(MACRO, SEP, ...) metamacro_foreach_cxt(metamacro_foreach_iter, SEP, MACRO, __VA_ARGS__)
/**
* For each consecutive variadic argument (up to twenty), MACRO is passed the
* zero-based index of the current argument, CONTEXT, and then the argument
* itself. The results of adjoining invocations of MACRO are then separated by
* SEP.
*
* Inspired by P99: http://p99.gforge.inria.fr
*/
#define metamacro_foreach_cxt(MACRO, SEP, CONTEXT, ...) \
metamacro_concat(metamacro_foreach_cxt, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
/**
* Identical to #metamacro_foreach_cxt. This can be used when the former would
* fail due to recursive macro expansion.
*/
#define metamacro_foreach_cxt_recursive(MACRO, SEP, CONTEXT, ...) \
metamacro_concat(metamacro_foreach_cxt_recursive, metamacro_argcount(__VA_ARGS__))(MACRO, SEP, CONTEXT, __VA_ARGS__)
/**
* In consecutive order, appends each variadic argument (up to twenty) onto
* BASE. The resulting concatenations are then separated by SEP.
*
* This is primarily useful to manipulate a list of macro invocations into instead
* invoking a different, possibly related macro.
*/
#define metamacro_foreach_concat(BASE, SEP, ...) \
metamacro_foreach_cxt(metamacro_foreach_concat_iter, SEP, BASE, __VA_ARGS__)
/**
* Iterates COUNT times, each time invoking MACRO with the current index
* (starting at zero) and CONTEXT. The results of adjoining invocations of MACRO
* are then separated by SEP.
*
* COUNT must be an integer between zero and twenty, inclusive.
*/
#define metamacro_for_cxt(COUNT, MACRO, SEP, CONTEXT) metamacro_concat(metamacro_for_cxt, COUNT)(MACRO, SEP, CONTEXT)
/**
* Returns the first argument given. At least one argument must be provided.
*
* This is useful when implementing a variadic macro, where you may have only
* one variadic argument, but no way to retrieve it (for example, because \c ...
* always needs to match at least one argument).
*
* @code
#define varmacro(...) \
metamacro_head(__VA_ARGS__)
* @endcode
*/
#define metamacro_head(...) metamacro_head_(__VA_ARGS__, 0)
/**
* Returns every argument except the first. At least two arguments must be
* provided.
*/
#define metamacro_tail(...) metamacro_tail_(__VA_ARGS__)
/**
* Returns the first N (up to twenty) variadic arguments as a new argument list.
* At least N variadic arguments must be provided.
*/
#define metamacro_take(N, ...) metamacro_concat(metamacro_take, N)(__VA_ARGS__)
/**
* Removes the first N (up to twenty) variadic arguments from the given argument
* list. At least N variadic arguments must be provided.
*/
#define metamacro_drop(N, ...) metamacro_concat(metamacro_drop, N)(__VA_ARGS__)
/**
* Decrements VAL, which must be a number between zero and twenty, inclusive.
*
* This is primarily useful when dealing with indexes and counts in
* metaprogramming.
*/
#define metamacro_dec(VAL) metamacro_at(VAL, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)
/**
* Increments VAL, which must be a number between zero and twenty, inclusive.
*
* This is primarily useful when dealing with indexes and counts in
* metaprogramming.
*/
#define metamacro_inc(VAL) metamacro_at(VAL, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21)
/**
* If A is equal to B, the next argument list is expanded; otherwise, the
* argument list after that is expanded. A and B must be numbers between zero
* and twenty, inclusive. Additionally, B must be greater than or equal to A.
*
* @code
// expands to true
metamacro_if_eq(0, 0)(true)(false)
// expands to false
metamacro_if_eq(0, 1)(true)(false)
* @endcode
*
* This is primarily useful when dealing with indexes and counts in
* metaprogramming.
*/
#define metamacro_if_eq(A, B) metamacro_concat(metamacro_if_eq, A)(B)
/**
* Identical to #metamacro_if_eq. This can be used when the former would fail
* due to recursive macro expansion.
*/
#define metamacro_if_eq_recursive(A, B) metamacro_concat(metamacro_if_eq_recursive, A)(B)
/**
* Returns 1 if N is an even number, or 0 otherwise. N must be between zero and
* twenty, inclusive.
*
* For the purposes of this test, zero is considered even.
*/
#define metamacro_is_even(N) metamacro_at(N, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1)
/**
* Returns the logical NOT of B, which must be the number zero or one.
*/
#define metamacro_not(B) metamacro_at(B, 1, 0)
// IMPLEMENTATION DETAILS FOLLOW!
// Do not write code that depends on anything below this line.
#define metamacro_stringify_(VALUE) #VALUE
#define metamacro_concat_(A, B) A##B
#define metamacro_foreach_iter(INDEX, MACRO, ARG) MACRO(INDEX, ARG)
#define metamacro_head_(FIRST, ...) FIRST
#define metamacro_tail_(FIRST, ...) __VA_ARGS__
#define metamacro_consume_(...)
#define metamacro_expand_(...) __VA_ARGS__
// implemented from scratch so that metamacro_concat() doesn't end up nesting
#define metamacro_foreach_concat_iter(INDEX, BASE, ARG) metamacro_foreach_concat_iter_(BASE, ARG)
#define metamacro_foreach_concat_iter_(BASE, ARG) BASE##ARG
// metamacro_at expansions
#define metamacro_at0(...) metamacro_head(__VA_ARGS__)
#define metamacro_at1(_0, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at2(_0, _1, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at3(_0, _1, _2, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at4(_0, _1, _2, _3, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at5(_0, _1, _2, _3, _4, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at6(_0, _1, _2, _3, _4, _5, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at7(_0, _1, _2, _3, _4, _5, _6, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at8(_0, _1, _2, _3, _4, _5, _6, _7, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at9(_0, _1, _2, _3, _4, _5, _6, _7, _8, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) metamacro_head(__VA_ARGS__)
#define metamacro_at16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) \
metamacro_head(__VA_ARGS__)
#define metamacro_at17(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) \
metamacro_head(__VA_ARGS__)
#define metamacro_at18(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, ...) \
metamacro_head(__VA_ARGS__)
#define metamacro_at19(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, ...) \
metamacro_head(__VA_ARGS__)
#define metamacro_at20(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, ...) \
metamacro_head(__VA_ARGS__)
// metamacro_foreach_cxt expansions
#define metamacro_foreach_cxt0(MACRO, SEP, CONTEXT)
#define metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)
#define metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) \
metamacro_foreach_cxt1(MACRO, SEP, CONTEXT, _0) SEP MACRO(1, CONTEXT, _1)
#define metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) \
metamacro_foreach_cxt2(MACRO, SEP, CONTEXT, _0, _1) SEP MACRO(2, CONTEXT, _2)
#define metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \
metamacro_foreach_cxt3(MACRO, SEP, CONTEXT, _0, _1, _2) SEP MACRO(3, CONTEXT, _3)
#define metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \
metamacro_foreach_cxt4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) SEP MACRO(4, CONTEXT, _4)
#define metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \
metamacro_foreach_cxt5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) SEP MACRO(5, CONTEXT, _5)
#define metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \
metamacro_foreach_cxt6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) SEP MACRO(6, CONTEXT, _6)
#define metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \
metamacro_foreach_cxt7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) SEP MACRO(7, CONTEXT, _7)
#define metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \
metamacro_foreach_cxt8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) SEP MACRO(8, CONTEXT, _8)
#define metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
metamacro_foreach_cxt9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) SEP MACRO(9, CONTEXT, _9)
#define metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
metamacro_foreach_cxt10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) SEP MACRO(10, CONTEXT, _10)
#define metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
metamacro_foreach_cxt11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
SEP MACRO(11, CONTEXT, _11)
#define metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
metamacro_foreach_cxt12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
SEP MACRO(12, CONTEXT, _12)
#define metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
metamacro_foreach_cxt13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
SEP MACRO(13, CONTEXT, _13)
#define metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
metamacro_foreach_cxt14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
SEP MACRO(14, CONTEXT, _14)
#define metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, \
_15) \
metamacro_foreach_cxt15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) \
SEP MACRO(15, CONTEXT, _15)
#define metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, \
_15, _16) \
metamacro_foreach_cxt16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) \
SEP MACRO(16, CONTEXT, _16)
#define metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, \
_15, _16, _17) \
metamacro_foreach_cxt17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \
_16) SEP MACRO(17, CONTEXT, _17)
#define metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, \
_15, _16, _17, _18) \
metamacro_foreach_cxt18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \
_16, _17) SEP MACRO(18, CONTEXT, _18)
#define metamacro_foreach_cxt20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, \
_15, _16, _17, _18, _19) \
metamacro_foreach_cxt19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, \
_16, _17, _18) SEP MACRO(19, CONTEXT, _19)
// metamacro_foreach_cxt_recursive expansions
#define metamacro_foreach_cxt_recursive0(MACRO, SEP, CONTEXT)
#define metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) MACRO(0, CONTEXT, _0)
#define metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) \
metamacro_foreach_cxt_recursive1(MACRO, SEP, CONTEXT, _0) SEP MACRO(1, CONTEXT, _1)
#define metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) \
metamacro_foreach_cxt_recursive2(MACRO, SEP, CONTEXT, _0, _1) SEP MACRO(2, CONTEXT, _2)
#define metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) \
metamacro_foreach_cxt_recursive3(MACRO, SEP, CONTEXT, _0, _1, _2) SEP MACRO(3, CONTEXT, _3)
#define metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) \
metamacro_foreach_cxt_recursive4(MACRO, SEP, CONTEXT, _0, _1, _2, _3) SEP MACRO(4, CONTEXT, _4)
#define metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) \
metamacro_foreach_cxt_recursive5(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4) SEP MACRO(5, CONTEXT, _5)
#define metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) \
metamacro_foreach_cxt_recursive6(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5) SEP MACRO(6, CONTEXT, _6)
#define metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) \
metamacro_foreach_cxt_recursive7(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6) SEP MACRO(7, CONTEXT, _7)
#define metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) \
metamacro_foreach_cxt_recursive8(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7) SEP MACRO(8, CONTEXT, _8)
#define metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
metamacro_foreach_cxt_recursive9(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8) SEP MACRO(9, CONTEXT, _9)
#define metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
metamacro_foreach_cxt_recursive10(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9) \
SEP MACRO(10, CONTEXT, _10)
#define metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
metamacro_foreach_cxt_recursive11(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) \
SEP MACRO(11, CONTEXT, _11)
#define metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
metamacro_foreach_cxt_recursive12(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) \
SEP MACRO(12, CONTEXT, _12)
#define metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
_13) \
metamacro_foreach_cxt_recursive13(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) \
SEP MACRO(13, CONTEXT, _13)
#define metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
_13, _14) \
metamacro_foreach_cxt_recursive14(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) \
SEP MACRO(14, CONTEXT, _14)
#define metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
_13, _14, _15) \
metamacro_foreach_cxt_recursive15(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \
_14) SEP MACRO(15, CONTEXT, _15)
#define metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
_13, _14, _15, _16) \
metamacro_foreach_cxt_recursive16(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \
_14, _15) SEP MACRO(16, CONTEXT, _16)
#define metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
_13, _14, _15, _16, _17) \
metamacro_foreach_cxt_recursive17(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \
_14, _15, _16) SEP MACRO(17, CONTEXT, _17)
#define metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
_13, _14, _15, _16, _17, _18) \
metamacro_foreach_cxt_recursive18(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \
_14, _15, _16, _17) SEP MACRO(18, CONTEXT, _18)
#define metamacro_foreach_cxt_recursive20(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
_13, _14, _15, _16, _17, _18, _19) \
metamacro_foreach_cxt_recursive19(MACRO, SEP, CONTEXT, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, \
_14, _15, _16, _17, _18) SEP MACRO(19, CONTEXT, _19)
// metamacro_for_cxt expansions
#define metamacro_for_cxt0(MACRO, SEP, CONTEXT)
#define metamacro_for_cxt1(MACRO, SEP, CONTEXT) MACRO(0, CONTEXT)
#define metamacro_for_cxt2(MACRO, SEP, CONTEXT) metamacro_for_cxt1(MACRO, SEP, CONTEXT) SEP MACRO(1, CONTEXT)
#define metamacro_for_cxt3(MACRO, SEP, CONTEXT) metamacro_for_cxt2(MACRO, SEP, CONTEXT) SEP MACRO(2, CONTEXT)
#define metamacro_for_cxt4(MACRO, SEP, CONTEXT) metamacro_for_cxt3(MACRO, SEP, CONTEXT) SEP MACRO(3, CONTEXT)
#define metamacro_for_cxt5(MACRO, SEP, CONTEXT) metamacro_for_cxt4(MACRO, SEP, CONTEXT) SEP MACRO(4, CONTEXT)
#define metamacro_for_cxt6(MACRO, SEP, CONTEXT) metamacro_for_cxt5(MACRO, SEP, CONTEXT) SEP MACRO(5, CONTEXT)
#define metamacro_for_cxt7(MACRO, SEP, CONTEXT) metamacro_for_cxt6(MACRO, SEP, CONTEXT) SEP MACRO(6, CONTEXT)
#define metamacro_for_cxt8(MACRO, SEP, CONTEXT) metamacro_for_cxt7(MACRO, SEP, CONTEXT) SEP MACRO(7, CONTEXT)
#define metamacro_for_cxt9(MACRO, SEP, CONTEXT) metamacro_for_cxt8(MACRO, SEP, CONTEXT) SEP MACRO(8, CONTEXT)
#define metamacro_for_cxt10(MACRO, SEP, CONTEXT) metamacro_for_cxt9(MACRO, SEP, CONTEXT) SEP MACRO(9, CONTEXT)
#define metamacro_for_cxt11(MACRO, SEP, CONTEXT) metamacro_for_cxt10(MACRO, SEP, CONTEXT) SEP MACRO(10, CONTEXT)
#define metamacro_for_cxt12(MACRO, SEP, CONTEXT) metamacro_for_cxt11(MACRO, SEP, CONTEXT) SEP MACRO(11, CONTEXT)
#define metamacro_for_cxt13(MACRO, SEP, CONTEXT) metamacro_for_cxt12(MACRO, SEP, CONTEXT) SEP MACRO(12, CONTEXT)
#define metamacro_for_cxt14(MACRO, SEP, CONTEXT) metamacro_for_cxt13(MACRO, SEP, CONTEXT) SEP MACRO(13, CONTEXT)
#define metamacro_for_cxt15(MACRO, SEP, CONTEXT) metamacro_for_cxt14(MACRO, SEP, CONTEXT) SEP MACRO(14, CONTEXT)
#define metamacro_for_cxt16(MACRO, SEP, CONTEXT) metamacro_for_cxt15(MACRO, SEP, CONTEXT) SEP MACRO(15, CONTEXT)
#define metamacro_for_cxt17(MACRO, SEP, CONTEXT) metamacro_for_cxt16(MACRO, SEP, CONTEXT) SEP MACRO(16, CONTEXT)
#define metamacro_for_cxt18(MACRO, SEP, CONTEXT) metamacro_for_cxt17(MACRO, SEP, CONTEXT) SEP MACRO(17, CONTEXT)
#define metamacro_for_cxt19(MACRO, SEP, CONTEXT) metamacro_for_cxt18(MACRO, SEP, CONTEXT) SEP MACRO(18, CONTEXT)
#define metamacro_for_cxt20(MACRO, SEP, CONTEXT) metamacro_for_cxt19(MACRO, SEP, CONTEXT) SEP MACRO(19, CONTEXT)
// metamacro_if_eq expansions
#define metamacro_if_eq0(VALUE) metamacro_concat(metamacro_if_eq0_, VALUE)
#define metamacro_if_eq0_0(...) __VA_ARGS__ metamacro_consume_
#define metamacro_if_eq0_1(...) metamacro_expand_
#define metamacro_if_eq0_2(...) metamacro_expand_
#define metamacro_if_eq0_3(...) metamacro_expand_
#define metamacro_if_eq0_4(...) metamacro_expand_
#define metamacro_if_eq0_5(...) metamacro_expand_
#define metamacro_if_eq0_6(...) metamacro_expand_
#define metamacro_if_eq0_7(...) metamacro_expand_
#define metamacro_if_eq0_8(...) metamacro_expand_
#define metamacro_if_eq0_9(...) metamacro_expand_
#define metamacro_if_eq0_10(...) metamacro_expand_
#define metamacro_if_eq0_11(...) metamacro_expand_
#define metamacro_if_eq0_12(...) metamacro_expand_
#define metamacro_if_eq0_13(...) metamacro_expand_
#define metamacro_if_eq0_14(...) metamacro_expand_
#define metamacro_if_eq0_15(...) metamacro_expand_
#define metamacro_if_eq0_16(...) metamacro_expand_
#define metamacro_if_eq0_17(...) metamacro_expand_
#define metamacro_if_eq0_18(...) metamacro_expand_
#define metamacro_if_eq0_19(...) metamacro_expand_
#define metamacro_if_eq0_20(...) metamacro_expand_
#define metamacro_if_eq1(VALUE) metamacro_if_eq0(metamacro_dec(VALUE))
#define metamacro_if_eq2(VALUE) metamacro_if_eq1(metamacro_dec(VALUE))
#define metamacro_if_eq3(VALUE) metamacro_if_eq2(metamacro_dec(VALUE))
#define metamacro_if_eq4(VALUE) metamacro_if_eq3(metamacro_dec(VALUE))
#define metamacro_if_eq5(VALUE) metamacro_if_eq4(metamacro_dec(VALUE))
#define metamacro_if_eq6(VALUE) metamacro_if_eq5(metamacro_dec(VALUE))
#define metamacro_if_eq7(VALUE) metamacro_if_eq6(metamacro_dec(VALUE))
#define metamacro_if_eq8(VALUE) metamacro_if_eq7(metamacro_dec(VALUE))
#define metamacro_if_eq9(VALUE) metamacro_if_eq8(metamacro_dec(VALUE))
#define metamacro_if_eq10(VALUE) metamacro_if_eq9(metamacro_dec(VALUE))
#define metamacro_if_eq11(VALUE) metamacro_if_eq10(metamacro_dec(VALUE))
#define metamacro_if_eq12(VALUE) metamacro_if_eq11(metamacro_dec(VALUE))
#define metamacro_if_eq13(VALUE) metamacro_if_eq12(metamacro_dec(VALUE))
#define metamacro_if_eq14(VALUE) metamacro_if_eq13(metamacro_dec(VALUE))
#define metamacro_if_eq15(VALUE) metamacro_if_eq14(metamacro_dec(VALUE))
#define metamacro_if_eq16(VALUE) metamacro_if_eq15(metamacro_dec(VALUE))
#define metamacro_if_eq17(VALUE) metamacro_if_eq16(metamacro_dec(VALUE))
#define metamacro_if_eq18(VALUE) metamacro_if_eq17(metamacro_dec(VALUE))
#define metamacro_if_eq19(VALUE) metamacro_if_eq18(metamacro_dec(VALUE))
#define metamacro_if_eq20(VALUE) metamacro_if_eq19(metamacro_dec(VALUE))
// metamacro_if_eq_recursive expansions
#define metamacro_if_eq_recursive0(VALUE) metamacro_concat(metamacro_if_eq_recursive0_, VALUE)
#define metamacro_if_eq_recursive0_0(...) __VA_ARGS__ metamacro_consume_
#define metamacro_if_eq_recursive0_1(...) metamacro_expand_
#define metamacro_if_eq_recursive0_2(...) metamacro_expand_
#define metamacro_if_eq_recursive0_3(...) metamacro_expand_
#define metamacro_if_eq_recursive0_4(...) metamacro_expand_
#define metamacro_if_eq_recursive0_5(...) metamacro_expand_
#define metamacro_if_eq_recursive0_6(...) metamacro_expand_
#define metamacro_if_eq_recursive0_7(...) metamacro_expand_
#define metamacro_if_eq_recursive0_8(...) metamacro_expand_
#define metamacro_if_eq_recursive0_9(...) metamacro_expand_
#define metamacro_if_eq_recursive0_10(...) metamacro_expand_
#define metamacro_if_eq_recursive0_11(...) metamacro_expand_
#define metamacro_if_eq_recursive0_12(...) metamacro_expand_
#define metamacro_if_eq_recursive0_13(...) metamacro_expand_
#define metamacro_if_eq_recursive0_14(...) metamacro_expand_
#define metamacro_if_eq_recursive0_15(...) metamacro_expand_
#define metamacro_if_eq_recursive0_16(...) metamacro_expand_
#define metamacro_if_eq_recursive0_17(...) metamacro_expand_
#define metamacro_if_eq_recursive0_18(...) metamacro_expand_
#define metamacro_if_eq_recursive0_19(...) metamacro_expand_
#define metamacro_if_eq_recursive0_20(...) metamacro_expand_
#define metamacro_if_eq_recursive1(VALUE) metamacro_if_eq_recursive0(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive2(VALUE) metamacro_if_eq_recursive1(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive3(VALUE) metamacro_if_eq_recursive2(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive4(VALUE) metamacro_if_eq_recursive3(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive5(VALUE) metamacro_if_eq_recursive4(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive6(VALUE) metamacro_if_eq_recursive5(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive7(VALUE) metamacro_if_eq_recursive6(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive8(VALUE) metamacro_if_eq_recursive7(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive9(VALUE) metamacro_if_eq_recursive8(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive10(VALUE) metamacro_if_eq_recursive9(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive11(VALUE) metamacro_if_eq_recursive10(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive12(VALUE) metamacro_if_eq_recursive11(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive13(VALUE) metamacro_if_eq_recursive12(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive14(VALUE) metamacro_if_eq_recursive13(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive15(VALUE) metamacro_if_eq_recursive14(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive16(VALUE) metamacro_if_eq_recursive15(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive17(VALUE) metamacro_if_eq_recursive16(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive18(VALUE) metamacro_if_eq_recursive17(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive19(VALUE) metamacro_if_eq_recursive18(metamacro_dec(VALUE))
#define metamacro_if_eq_recursive20(VALUE) metamacro_if_eq_recursive19(metamacro_dec(VALUE))
// metamacro_take expansions
#define metamacro_take0(...)
#define metamacro_take1(...) metamacro_head(__VA_ARGS__)
#define metamacro_take2(...) metamacro_head(__VA_ARGS__), metamacro_take1(metamacro_tail(__VA_ARGS__))
#define metamacro_take3(...) metamacro_head(__VA_ARGS__), metamacro_take2(metamacro_tail(__VA_ARGS__))
#define metamacro_take4(...) metamacro_head(__VA_ARGS__), metamacro_take3(metamacro_tail(__VA_ARGS__))
#define metamacro_take5(...) metamacro_head(__VA_ARGS__), metamacro_take4(metamacro_tail(__VA_ARGS__))
#define metamacro_take6(...) metamacro_head(__VA_ARGS__), metamacro_take5(metamacro_tail(__VA_ARGS__))
#define metamacro_take7(...) metamacro_head(__VA_ARGS__), metamacro_take6(metamacro_tail(__VA_ARGS__))
#define metamacro_take8(...) metamacro_head(__VA_ARGS__), metamacro_take7(metamacro_tail(__VA_ARGS__))
#define metamacro_take9(...) metamacro_head(__VA_ARGS__), metamacro_take8(metamacro_tail(__VA_ARGS__))
#define metamacro_take10(...) metamacro_head(__VA_ARGS__), metamacro_take9(metamacro_tail(__VA_ARGS__))
#define metamacro_take11(...) metamacro_head(__VA_ARGS__), metamacro_take10(metamacro_tail(__VA_ARGS__))
#define metamacro_take12(...) metamacro_head(__VA_ARGS__), metamacro_take11(metamacro_tail(__VA_ARGS__))
#define metamacro_take13(...) metamacro_head(__VA_ARGS__), metamacro_take12(metamacro_tail(__VA_ARGS__))
#define metamacro_take14(...) metamacro_head(__VA_ARGS__), metamacro_take13(metamacro_tail(__VA_ARGS__))
#define metamacro_take15(...) metamacro_head(__VA_ARGS__), metamacro_take14(metamacro_tail(__VA_ARGS__))
#define metamacro_take16(...) metamacro_head(__VA_ARGS__), metamacro_take15(metamacro_tail(__VA_ARGS__))
#define metamacro_take17(...) metamacro_head(__VA_ARGS__), metamacro_take16(metamacro_tail(__VA_ARGS__))
#define metamacro_take18(...) metamacro_head(__VA_ARGS__), metamacro_take17(metamacro_tail(__VA_ARGS__))
#define metamacro_take19(...) metamacro_head(__VA_ARGS__), metamacro_take18(metamacro_tail(__VA_ARGS__))
#define metamacro_take20(...) metamacro_head(__VA_ARGS__), metamacro_take19(metamacro_tail(__VA_ARGS__))
// metamacro_drop expansions
#define metamacro_drop0(...) __VA_ARGS__
#define metamacro_drop1(...) metamacro_tail(__VA_ARGS__)
#define metamacro_drop2(...) metamacro_drop1(metamacro_tail(__VA_ARGS__))
#define metamacro_drop3(...) metamacro_drop2(metamacro_tail(__VA_ARGS__))
#define metamacro_drop4(...) metamacro_drop3(metamacro_tail(__VA_ARGS__))
#define metamacro_drop5(...) metamacro_drop4(metamacro_tail(__VA_ARGS__))
#define metamacro_drop6(...) metamacro_drop5(metamacro_tail(__VA_ARGS__))
#define metamacro_drop7(...) metamacro_drop6(metamacro_tail(__VA_ARGS__))
#define metamacro_drop8(...) metamacro_drop7(metamacro_tail(__VA_ARGS__))
#define metamacro_drop9(...) metamacro_drop8(metamacro_tail(__VA_ARGS__))
#define metamacro_drop10(...) metamacro_drop9(metamacro_tail(__VA_ARGS__))
#define metamacro_drop11(...) metamacro_drop10(metamacro_tail(__VA_ARGS__))
#define metamacro_drop12(...) metamacro_drop11(metamacro_tail(__VA_ARGS__))
#define metamacro_drop13(...) metamacro_drop12(metamacro_tail(__VA_ARGS__))
#define metamacro_drop14(...) metamacro_drop13(metamacro_tail(__VA_ARGS__))
#define metamacro_drop15(...) metamacro_drop14(metamacro_tail(__VA_ARGS__))
#define metamacro_drop16(...) metamacro_drop15(metamacro_tail(__VA_ARGS__))
#define metamacro_drop17(...) metamacro_drop16(metamacro_tail(__VA_ARGS__))
#define metamacro_drop18(...) metamacro_drop17(metamacro_tail(__VA_ARGS__))
#define metamacro_drop19(...) metamacro_drop18(metamacro_tail(__VA_ARGS__))
#define metamacro_drop20(...) metamacro_drop19(metamacro_tail(__VA_ARGS__))
#endif

View File

@@ -0,0 +1,68 @@
add_library(everest_log)
add_library(everest::log ALIAS everest_log)
target_sources(everest_log
PRIVATE
logging.cpp
trace.cpp
)
target_include_directories(everest_log
PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
set_target_properties(everest_log
PROPERTIES
POSITION_INDEPENDENT_CODE ON
)
target_link_libraries(everest_log
PUBLIC
Boost::log
PRIVATE
Boost::log_setup
)
if (LIBLOG_USE_BOOST_FILESYSTEM)
target_link_libraries(everest_log
PRIVATE
Boost::filesystem
)
target_compile_definitions(everest_log
PRIVATE
LIBLOG_USE_BOOST_FILESYSTEM
)
endif()
# FIXME (aw): in case FindBoost.cmake was used we need to add things
# this should be removed no support for Boost < 1.74 is needed
if (NOT Boost_DIR)
target_compile_definitions(everest_log
PUBLIC
BOOST_LOG_DYN_LINK
)
target_link_libraries(everest_log
PUBLIC
rt dl
)
endif()
if (BUILD_BACKTRACE_SUPPORT)
target_link_libraries(everest_log
PRIVATE
backtrace
)
target_compile_definitions(everest_log PRIVATE WITH_LIBBACKTRACE)
endif()
if (EVEREST_DISABLE_VERBOSE_LOGGING)
target_compile_definitions(everest_log PUBLIC EVEREST_DISABLE_VERBOSE_LOGGING)
endif ()
if (EVEREST_DISABLE_DEBUG_LOGGING)
target_compile_definitions(everest_log PUBLIC EVEREST_DISABLE_DEBUG_LOGGING)
endif ()
target_compile_features(everest_log PUBLIC cxx_std_17)

View File

@@ -0,0 +1,241 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifdef LIBLOG_USE_BOOST_FILESYSTEM
#include <boost/filesystem.hpp>
#else
#include <filesystem>
#endif
#include <boost/log/attributes/current_process_id.hpp>
#include <boost/log/attributes/current_process_name.hpp>
#include <boost/log/attributes/current_thread_id.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/expressions/attr.hpp>
#include <boost/log/expressions/formatter.hpp>
#include <boost/log/expressions/formatters/c_decorator.hpp>
#include <boost/log/expressions/formatters/format.hpp>
#include <boost/log/expressions/formatters/stream.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/setup/filter_parser.hpp>
#include <boost/log/utility/setup/formatter_parser.hpp>
#include <boost/log/utility/setup/from_settings.hpp>
#include <boost/log/utility/setup/from_stream.hpp>
#include <boost/log/utility/setup/settings.hpp>
#include <boost/log/utility/setup/settings_parser.hpp>
#include <fstream>
#include <everest/exceptions.hpp>
#include <everest/logging.hpp>
// this will only be used while bootstrapping our logging (e.g. the logging settings aren't yet applied)
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define EVEREST_INTERNAL_LOG_AND_THROW(exception) \
do { \
BOOST_LOG_TRIVIAL(fatal) << (exception).what(); \
throw(exception); \
} while (0);
#ifdef LIBLOG_USE_BOOST_FILESYSTEM
namespace fs = boost::filesystem;
#else
namespace fs = std::filesystem;
#endif
namespace logging = boost::log::BOOST_LOG_VERSION_NAMESPACE;
namespace attrs = logging::attributes;
namespace expr = logging::expressions;
namespace Everest {
namespace Logging {
namespace {
bool is_initialized = false;
}
std::array<std::string, 6> severity_strings = {
"VERB", //
"DEBG", //
"INFO", //
"WARN", //
"ERRO", //
"CRIT", //
};
std::array<std::string, 6> severity_strings_colors = {
"", //
"", //
"", //
"", //
"", //
"", //
};
std::string process_name_padding(const std::string& process_name) {
const unsigned int process_name_padding_length = 15;
std::string padded_process_name = process_name;
if (process_name_padding_length > padded_process_name.size())
padded_process_name.insert(padded_process_name.size(), process_name_padding_length, ' ');
if (padded_process_name.size() > process_name_padding_length)
padded_process_name = padded_process_name.substr(0, process_name_padding_length);
return padded_process_name;
}
attrs::mutable_constant<std::string> current_process_name(process_name_padding(logging::aux::get_process_name()));
// The operator puts a human-friendly representation of the severity level to the stream
std::ostream& operator<<(std::ostream& strm, severity_level level) {
if (static_cast<std::size_t>(level) < severity_strings.size()) {
strm << severity_strings_colors.at(level) << severity_strings.at(level) << "\033[0m";
} else {
strm << static_cast<int>(level);
}
return strm;
}
// The operator parses the severity level from the stream
std::istream& operator>>(std::istream& strm, severity_level& level) {
if (strm.good()) {
std::string str;
strm >> str;
for (unsigned int i = 0; i < severity_strings.size(); ++i) {
if (str == severity_strings.at(i)) {
level = static_cast<severity_level>(i);
return strm;
}
}
strm.setstate(std::ios_base::failbit);
}
return strm;
}
/// Custom formatter for escaped messages.
///
/// Not really clear but just a wrapper around the c_decor formatter.
struct escaped_message_formatter {
explicit escaped_message_formatter(logging::attribute_name const& name) :
f_{expr::stream << expr::c_decor[expr::stream << expr::smessage]} {
}
void operator()(logging::record_view const& rec, logging::formatting_ostream& strm) const {
f_(rec, strm);
}
private:
/// @brief The formatter itself.
boost::log::formatter f_;
};
/// The factory for the EscMessage formatter.
struct escaped_message_formatter_factory : public logging::formatter_factory<char> {
formatter_type create_formatter(logging::attribute_name const& attr_name, args_map const& args) {
return formatter_type(escaped_message_formatter(attr_name));
}
};
int init() {
logging::core::get()->remove_all_sinks();
logging::core::get()->set_logging_enabled(false);
return -1;
}
int init(const std::string& logconf) {
return init(logconf, "");
}
int init(const std::string& logconf, std::string process_name) {
BOOST_LOG_FUNCTION();
if (is_initialized) {
// this prevents us from registering the sinks multiple times which would lead to duplicate output
logging::core::get()->remove_all_sinks();
}
// First thing - register the custom formatter for EscMessage
logging::register_formatter_factory("EscapedMessage", boost::make_shared<escaped_message_formatter_factory>());
// add useful attributes
logging::add_common_attributes();
std::string padded_process_name;
if (!process_name.empty()) {
padded_process_name = process_name_padding(process_name);
}
logging::core::get()->add_global_attribute("Process", current_process_name);
if (!padded_process_name.empty()) {
current_process_name.set(padded_process_name);
}
logging::core::get()->add_global_attribute("Scope", attrs::named_scope());
// Before initializing the library from settings, we need to register any custom filter and formatter factories
logging::register_simple_filter_factory<severity_level>("Severity");
logging::register_simple_formatter_factory<severity_level, char>("Severity");
// open logging.ini config file located at our base_dir and use it to configure boost::log logging (filters and
// format)
fs::path logging_path = fs::path(logconf);
std::ifstream logging_config(logging_path.c_str());
if (!logging_config.is_open()) {
EVEREST_INTERNAL_LOG_AND_THROW(EverestConfigError(std::string("Could not open logging config file at ") +
std::string(fs::absolute(logging_path).c_str())));
}
auto settings = logging::parse_settings(logging_config);
auto sink = settings["Sinks.Console"].get_section();
severity_strings_colors[severity_level::verbose] =
sink["SeverityStringColorTrace"].get<std::string>().get_value_or("");
severity_strings_colors[severity_level::debug] =
sink["SeverityStringColorDebug"].get<std::string>().get_value_or("");
severity_strings_colors[severity_level::info] = sink["SeverityStringColorInfo"].get<std::string>().get_value_or("");
severity_strings_colors[severity_level::warning] =
sink["SeverityStringColorWarning"].get<std::string>().get_value_or("");
severity_strings_colors[severity_level::error] =
sink["SeverityStringColorError"].get<std::string>().get_value_or("");
severity_strings_colors[severity_level::critical] =
sink["SeverityStringColorCritical"].get<std::string>().get_value_or("");
logging::init_from_settings(settings);
logging::core::get()->set_logging_enabled(true);
EVLOG_debug << "Logger " << (is_initialized ? "re" : "") << "initialized (using " << logconf << ")...";
is_initialized = true;
// Probe the installed filter to find the minimum accepted severity level.
for (int level = static_cast<int>(verbose); level <= static_cast<int>(critical); ++level) {
auto rec =
global_logger::get().open_record(boost::log::keywords::severity = static_cast<severity_level>(level));
if (rec) {
return level;
}
}
return -1;
}
void update_process_name(std::string process_name) {
if (!process_name.empty()) {
std::string padded_process_name;
padded_process_name = process_name_padding(process_name);
current_process_name.set(padded_process_name);
}
}
void ffi_log(int level, int line, const std::string& file, const std::string& message) {
// Logging is off.
if (level < 0) {
return;
}
const auto logging_level = static_cast<severity_level>(level);
BOOST_LOG_SEV(::global_logger::get(), logging_level)
<< boost::log::BOOST_LOG_VERSION_NAMESPACE::add_value("file", file)
<< boost::log::BOOST_LOG_VERSION_NAMESPACE::add_value("line", line) << message;
}
} // namespace Logging
} // namespace Everest

View File

@@ -0,0 +1,90 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2022 Pionix GmbH and Contributors to EVerest
#include <everest/logging.hpp>
#ifdef WITH_LIBBACKTRACE
#include <backtrace/backtrace-supported.h>
#include <backtrace/backtrace.h>
#include <cxxabi.h>
#include <mutex>
static backtrace_state* bt_state;
static bool tried_to_initialize;
static std::mutex init_mtx;
struct StackTrace {
int frame_count{0};
std::string info;
};
inline int frame_handler(void* data, uintptr_t pc, const char* filename, int lineno, const char* function) {
// FIXME(aw): we might have unknown frames everywhere in the call
// stack, it probably only make sense to skip the
// contigeous set of the top/root frames, that are all
// unknown
// if ((filename == nullptr) && (lineno == 0) && (function == nullptr)) {
// return 1; // stop backtracing
// }
auto& trace = *static_cast<StackTrace*>(data);
std::string function_name = "<function unknown>";
if (function != nullptr) {
// try to demangle
int status;
size_t length;
auto demangled_function = __cxxabiv1::__cxa_demangle(function, nullptr, &length, &status);
if (status == 0) {
// successfully demangled
function_name = std::string(demangled_function);
} else {
function_name = std::string(function);
}
}
trace.info += ("#" + std::to_string(trace.frame_count) + ": ");
trace.info += (function_name + " at ");
trace.info += (filename != nullptr) ? filename : "<filename unknown>";
trace.info += (":" + std::to_string(lineno));
trace.info += "\n";
trace.frame_count++;
return 0; // continue backtracing
}
#endif
namespace Everest {
namespace Logging {
std::string trace() {
#ifdef WITH_LIBBACKTRACE
{
std::lock_guard<std::mutex> lck(init_mtx);
if (!tried_to_initialize) {
// 1 means support threaded
bt_state = backtrace_create_state(nullptr, 1, nullptr, nullptr);
tried_to_initialize = true;
}
}
if (bt_state == nullptr) {
return "Backtrace functionality not available\n";
}
StackTrace trace;
// FIXME (aw): 1 means we're skipping this functions frame, can this
// be optimized away by the compiler, so we are going to
// miss the first frame?
backtrace_full(bt_state, 1, frame_handler, nullptr, &trace);
return trace.info;
#else
return "Backtrace functionality not built in\n";
#endif
}
} // namespace Logging
} // namespace Everest

View File

@@ -0,0 +1,37 @@
set(TEST_TARGET_NAME ${PROJECT_NAME}_tests)
set(GTEST_LIBRARIES GTest::gmock_main GTest::gtest_main)
add_executable(${TEST_TARGET_NAME} liblog_test.cpp)
target_include_directories(${TEST_TARGET_NAME} PUBLIC ${GTEST_INCLUDE_DIRS})
target_include_directories(everest_log
PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/lib>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_link_libraries(${TEST_TARGET_NAME}
PRIVATE
everest::log
${GTEST_LIBRARIES}
)
add_test(${TEST_TARGET_NAME} ${TEST_TARGET_NAME})
if (EVEREST_LIBLOG_BUILD_TESTING)
evc_include(CodeCoverage)
append_coverage_compiler_flags_to_target(everest_log)
setup_target_for_coverage_gcovr_html(
NAME ${PROJECT_NAME}_gcovr_coverage
EXECUTABLE ctest
DEPENDENCIES ${TEST_TARGET_NAME}
EXCLUDE "tests/*"
)
setup_target_for_coverage_gcovr_xml(
NAME ${PROJECT_NAME}_gcovr_coverage_xml
EXECUTABLE ctest
DEPENDENCIES ${TEST_TARGET_NAME}
EXCLUDE "tests/*"
)
endif()

View File

@@ -0,0 +1,22 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#include <gtest/gtest.h>
namespace Everest {
namespace Logging {
class LibLogUnitTest : public ::testing::Test {
protected:
void SetUp() override {
}
void TearDown() override {
}
};
TEST(LibLogUnitTest, test_truth) {
ASSERT_TRUE(1 == 1);
}
} // namespace Logging
} // namespace Everest