Skip to content

Commit

Permalink
Implement slog2 logging capability
Browse files Browse the repository at this point in the history
slog2 is enabled by default, but guarded with #ifdef __QNX__. It can be
controlled with /etc/vsomeip/logging.json, i.e.:

```json
"logging": {
  "slog2": true
}
```

This code allocates 4 pages (16kB) by default, but the caller can provide
an environment variable VSOMEIP_SLOG2_NUM_PAGES to control the allocation

The logger must be initialized prior to calling config through the
implementation.  Because non-CommonAPI apps (e.g. routingmanagerd) can
use the VSOMEIP logging macros which would trigger a logging seg fault,
the message object will now output the message in the erroneous case
rather than raising a seg fault.

Minimal CMake changes were made to link against the slog2 library on QNX
  • Loading branch information
kheaactua committed May 29, 2024
1 parent 6c0e9db commit ae1255e
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 107 deletions.
62 changes: 49 additions & 13 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,27 +64,65 @@ endif()
set(CMAKE_CXX_STANDARD 17)

# OS
add_library(OS_INTERFACE INTERFACE IMPORTED)
target_link_libraries(OS_INTERFACE INTERFACE Threads::Threads)

if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(DL_LIBRARY "dl")

if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# This is only relevant for GCC and causes warnings on Clang
set(EXPORTSYMBOLS "-Wl,-export-dynamic -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/exportmap.gcc")
set(OS_CXX_FLAGS "${OS_CXX_FLAGS} -pie -Wno-tsan -Wl,-z,relro,-z,now")
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# This is only relevant for GCC and causes warnings on Clang
set(EXPORTSYMBOLS "-Wl,-export-dynamic -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/exportmap.gcc")
set(OS_CXX_FLAGS "${OS_CXX_FLAGS} -Wno-tsan -Wl,-z,now")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()

set(NO_DEPRECATED "")
set(OPTIMIZE "")
if(NOT DEFINED _FORTIFY_SOURCE)
set(_FORTIFY_SOURCE 2)
endif()
set(OS_CXX_FLAGS "${OS_CXX_FLAGS} -D_GLIBCXX_USE_NANOSLEEP -pthread -O -Wall -Wextra -Wformat -Wformat-security -Wconversion -fexceptions -fstrict-aliasing -fstack-protector-strong -fasynchronous-unwind-tables -fno-omit-frame-pointer -D_FORTIFY_SOURCE=${_FORTIFY_SOURCE} -Wformat -Wformat-security -Wpedantic -Werror -fPIE")
if(NOT DEFINED _FORTIFY_SOURCE)
set(_FORTIFY_SOURCE 2)
endif()

add_compile_options(
-Wall
-Wextra
-Wformat
-Wformat-security
-Wconversion
-fexceptions
-fstrict-aliasing
-fstack-protector-strong
-fasynchronous-unwind-tables
-fno-omit-frame-pointer
-Wformat
-Wformat-security
-Wpedantic
-Werror
)

# force all use of std::mutex and std::recursive_mutex to use runtime init
# instead of static initialization so mutexes can be hooked to enable PI as needed
add_definitions(-D_GTHREAD_USE_MUTEX_INIT_FUNC -D_GTHREAD_USE_RECURSIVE_MUTEX_INIT_FUNC)
add_definitions(-D_GTHREAD_USE_MUTEX_INIT_FUNC -D_GTHREAD_USE_RECURSIVE_MUTEX_INIT_FUNC -D_FORTIFY_SOURCE=${_FORTIFY_SOURCE})

add_link_options(-Wl,--wrap=socket,--wrap=accept,--wrap=open)
endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")

if(${CMAKE_SYSTEM_NAME} MATCHES "QNX")
set(OS "QNX")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

add_compile_options(
-fexceptions
-fstrict-aliasing
-fstack-protector
-fasynchronous-unwind-tables
-fno-omit-frame-pointer
)
add_link_options(-Wl,-export-dynamic)
add_link_options(-Wl,--wrap=socket,--wrap=accept,--wrap=open)
target_link_libraries(OS_INTERFACE INTERFACE slog2 socket)
endif (${CMAKE_SYSTEM_NAME} MATCHES "QNX")

if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
set(DL_LIBRARY "")
set(EXPORTSYMBOLS "")
Expand Down Expand Up @@ -308,8 +346,6 @@ set_target_properties (${VSOMEIP_NAME} PROPERTIES VERSION ${VSOMEIP_VERSION} SOV
target_compile_features(${VSOMEIP_NAME} PRIVATE cxx_std_17)
if (MSVC)
set_target_properties(${VSOMEIP_NAME} PROPERTIES COMPILE_DEFINITIONS "VSOMEIP_DLL_COMPILATION")
else ()
set_target_properties(${VSOMEIP_NAME} PROPERTIES LINK_FLAGS "-Wl,-wrap,socket -Wl,-wrap,accept -Wl,-wrap,open")
endif ()
target_include_directories(${VSOMEIP_NAME} INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/interface>
Expand All @@ -320,7 +356,7 @@ target_include_directories(${VSOMEIP_NAME} INTERFACE
# them (which shouldn't be required). ${Boost_LIBRARIES} includes absolute
# build host paths as of writing, which also makes this important as it breaks
# the build.
target_link_libraries(${VSOMEIP_NAME} PRIVATE ${Boost_LIBRARIES} ${USE_RT} ${DL_LIBRARY} ${DLT_LIBRARIES} ${SystemD_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(${VSOMEIP_NAME} PRIVATE ${Boost_LIBRARIES} ${USE_RT} ${DL_LIBRARY} ${DLT_LIBRARIES} ${SystemD_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} OS_INTERFACE)

if(NOT WIN32)
target_link_options(${VSOMEIP_NAME} PRIVATE "LINKER:-as-needed")
Expand Down
1 change: 1 addition & 0 deletions implementation/configuration/include/configuration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class configuration {
virtual bool has_console_log() const = 0;
virtual bool has_file_log() const = 0;
virtual bool has_dlt_log() const = 0;
virtual bool has_slog2_log() const = 0;
virtual const std::string &get_logfile() const = 0;
virtual logger::level_e get_loglevel() const = 0;

Expand Down
5 changes: 4 additions & 1 deletion implementation/configuration/include/configuration_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class configuration_impl:
VSOMEIP_EXPORT bool has_console_log() const;
VSOMEIP_EXPORT bool has_file_log() const;
VSOMEIP_EXPORT bool has_dlt_log() const;
VSOMEIP_EXPORT bool has_slog2_log() const;
VSOMEIP_EXPORT const std::string & get_logfile() const;
VSOMEIP_EXPORT vsomeip_v3::logger::level_e get_loglevel() const;

Expand Down Expand Up @@ -491,6 +492,7 @@ class configuration_impl:
bool has_console_log_;
bool has_file_log_;
bool has_dlt_log_;
bool has_slog2_log_;
std::string logfile_;
mutable std::mutex mutex_loglevel_;
vsomeip_v3::logger::level_e loglevel_;
Expand Down Expand Up @@ -561,6 +563,7 @@ class configuration_impl:
ET_LOGGING_CONSOLE,
ET_LOGGING_FILE,
ET_LOGGING_DLT,
ET_LOGGING_SLOG2,
ET_LOGGING_LEVEL,
ET_ROUTING,
ET_SERVICE_DISCOVERY_ENABLE,
Expand Down Expand Up @@ -598,7 +601,7 @@ class configuration_impl:
ET_PARTITIONS,
ET_SECURITY_AUDIT_MODE,
ET_SECURITY_REMOTE_ACCESS,
ET_MAX = 45
ET_MAX = 46
};

bool is_configured_[ET_MAX];
Expand Down
19 changes: 19 additions & 0 deletions implementation/configuration/src/configuration_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ configuration_impl::configuration_impl(const std::string &_path)
has_console_log_(true),
has_file_log_(false),
has_dlt_log_(false),
#ifdef __QNX__
has_slog2_log_(true),
#else
has_slog2_log_(false),
#endif
logfile_("/tmp/vsomeip.log"),
loglevel_(vsomeip_v3::logger::level_e::LL_INFO),
is_sd_enabled_(VSOMEIP_SD_DEFAULT_ENABLED),
Expand Down Expand Up @@ -162,6 +167,7 @@ configuration_impl::configuration_impl(const configuration_impl &_other)
has_console_log_ = _other.has_console_log_;
has_file_log_ = _other.has_file_log_;
has_dlt_log_ = _other.has_dlt_log_;
has_slog2_log_ = _other.has_slog2_log_;
logfile_ = _other.logfile_;

loglevel_ = _other.loglevel_;
Expand Down Expand Up @@ -655,6 +661,15 @@ bool configuration_impl::load_logging(
has_dlt_log_ = (its_value == "true");
is_configured_[ET_LOGGING_DLT] = true;
}
} else if (its_key == "slog2") {
if (is_configured_[ET_LOGGING_SLOG2]) {
_warnings.insert("Multiple definitions for logging.slog2."
" Ignoring definition from " + _element.name_);
} else {
std::string its_value(i->second.data());
has_slog2_log_ = (its_value == "true");
is_configured_[ET_LOGGING_SLOG2] = true;
}
} else if (its_key == "level") {
if (is_configured_[ET_LOGGING_LEVEL]) {
_warnings.insert("Multiple definitions for logging.level."
Expand Down Expand Up @@ -2894,6 +2909,10 @@ bool configuration_impl::has_dlt_log() const {
return has_dlt_log_;
}

bool configuration_impl::has_slog2_log() const {
return has_slog2_log_;
}

const std::string & configuration_impl::get_logfile() const {
return logfile_;
}
Expand Down
104 changes: 104 additions & 0 deletions implementation/logger/include/logger_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
#include <memory>
#include <mutex>

#ifdef __QNX__
#include <sys/slog2.h>
#endif

#ifdef ANDROID
#include <android/log.h>
#endif
#ifdef USE_DLT
#ifndef ANDROID
#include <dlt/dlt.h>
Expand All @@ -34,19 +41,116 @@ class logger_impl {
std::shared_ptr<configuration> get_configuration() const;
void set_configuration(const std::shared_ptr<configuration> &_configuration);

#ifdef __QNX__
static slog2_buffer_set_config_t buffer_config;
static slog2_buffer_t buffer_handle[1];

auto slog2_is_initialized() const -> bool {
return slog2_is_initialized_;
}

auto set_slog2_initialized(bool initialized) -> void {
slog2_is_initialized_ = initialized;
}
#endif

#ifdef USE_DLT
void log(level_e _level, const char *_data);

private:
void enable_dlt(const std::string &_application, const std::string &_context);
#endif

static auto constexpr levelAsString(level_e const _level) -> const char *
{
const char* its_level = nullptr;
switch (_level) {
case level_e::LL_FATAL:
its_level = "fatal";
break;
case level_e::LL_ERROR:
its_level = "error";
break;
case level_e::LL_WARNING:
its_level = "warning";
break;
case level_e::LL_INFO:
its_level = "info";
break;
case level_e::LL_DEBUG:
its_level = "debug";
break;
case level_e::LL_VERBOSE:
its_level = "verbose";
break;
default:
its_level = "none";
}

return its_level;
}

#ifdef __QNX__
static auto constexpr levelAsSlog2(level_e const _level) -> std::uint8_t
{
uint8_t severity = 0;
switch (_level) {
case level_e::LL_FATAL:
severity = SLOG2_CRITICAL;
break;
case level_e::LL_ERROR:
severity = SLOG2_ERROR;
break;
case level_e::LL_WARNING:
severity = SLOG2_WARNING;
break;
case level_e::LL_INFO:
severity = SLOG2_INFO;
break;
case level_e::LL_DEBUG:
severity = SLOG2_DEBUG1;
break;
case level_e::LL_VERBOSE:
default:
severity = SLOG2_DEBUG2;
break;
}
return severity;
}
#endif

#ifdef ANDROID
static constexpr auto levelAsAospLevel(level_e _level) -> android_LogPriority {
switch (_level) {
case level_e::LL_FATAL:
return ANDROID_LOG_ERROR;
case level_e::LL_ERROR:
return ANDROID_LOG_ERROR;
case level_e::LL_WARNING:
return ANDROID_LOG_WARN;
case level_e::LL_INFO:
return ANDROID_LOG_INFO;
case level_e::LL_DEBUG:
return ANDROID_LOG_DEBUG;
case level_e::LL_VERBOSE:
return ANDROID_LOG_VERBOSE;
default:
return ANDROID_LOG_INFO;
}
}
#endif // !ANDROID

private:
static std::mutex mutex__;

std::shared_ptr<configuration> configuration_;
mutable std::mutex configuration_mutex_;

#ifdef __QNX__
// Flag whether slog2 was successfully initialized.
bool slog2_is_initialized_ = false;
#endif

#ifdef USE_DLT
#ifndef ANDROID
DLT_DECLARE_CONTEXT(dlt_)
Expand Down
37 changes: 37 additions & 0 deletions implementation/logger/src/logger_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@
#include "../include/logger_impl.hpp"
#include "../../configuration/include/configuration.hpp"

#ifdef __QNX__
#include <sys/slog2.h>
extern char * __progname;
#elif __linux__
extern char * __progname;
#endif


namespace vsomeip_v3 {
namespace logger {

Expand All @@ -21,6 +29,35 @@ logger_impl::init(const std::shared_ptr<configuration> &_configuration) {
auto its_logger = logger_impl::get();
its_logger->set_configuration(_configuration);

#ifdef __QNX__
logger_impl::buffer_config.buffer_set_name = __progname;
logger_impl::buffer_config.num_buffers = 1;
logger_impl::buffer_config.verbosity_level = levelAsSlog2(its_logger->configuration_->get_loglevel());

// Use a 16kB log buffer by default
// Override with a size specified by environment variable
long unsigned int num_pages = 4;
auto s = getenv("VSOMEIP_SLOG2_NUM_PAGES");
if (s != nullptr)
{
char * endptr = nullptr;
num_pages = strtoul(s, &endptr, 0);
}
logger_impl::buffer_config.buffer_config[0].buffer_name = "vsomeip";
logger_impl::buffer_config.buffer_config[0].num_pages = static_cast<int>(num_pages);

// Register the buffer set.
if (-1 == slog2_register(&logger_impl::buffer_config, logger_impl::buffer_handle, 0))
{
std::fprintf(stderr, "Error registering slogger2 buffer!\n");
return;
}
else
{
its_logger->set_slog2_initialized(true);
}
#endif

#ifdef USE_DLT
# define VSOMEIP_LOG_DEFAULT_CONTEXT_ID "VSIP"
# define VSOMEIP_LOG_DEFAULT_CONTEXT_NAME "vSomeIP context"
Expand Down
Loading

0 comments on commit ae1255e

Please sign in to comment.