Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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.
kheaactua committed May 28, 2024
1 parent 6c0e9db commit 6553f94
Showing 5 changed files with 168 additions and 90 deletions.
5 changes: 4 additions & 1 deletion implementation/configuration/include/configuration_impl.hpp
Original file line number Diff line number Diff line change
@@ -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;

@@ -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_;
@@ -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,
@@ -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];
19 changes: 19 additions & 0 deletions implementation/configuration/src/configuration_impl.cpp
Original file line number Diff line number Diff line change
@@ -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),
@@ -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_;
@@ -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."
@@ -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_;
}
13 changes: 13 additions & 0 deletions implementation/logger/include/logger_impl.hpp
Original file line number Diff line number Diff line change
@@ -9,6 +9,9 @@
#include <memory>
#include <mutex>

#ifdef __QNX__
#include <sys/slog2.h>
#endif
#ifdef USE_DLT
#ifndef ANDROID
#include <dlt/dlt.h>
@@ -34,6 +37,11 @@ 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];
#endif

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

@@ -47,6 +55,11 @@ class logger_impl {
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_)
29 changes: 29 additions & 0 deletions implementation/logger/src/logger_impl.cpp
Original file line number Diff line number Diff line change
@@ -21,6 +21,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(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
{
slog2_is_initialized_ = true;
}
#endif

#ifdef USE_DLT
# define VSOMEIP_LOG_DEFAULT_CONTEXT_ID "VSIP"
# define VSOMEIP_LOG_DEFAULT_CONTEXT_NAME "vSomeIP context"
192 changes: 103 additions & 89 deletions implementation/logger/src/message.cpp
Original file line number Diff line number Diff line change
@@ -12,51 +12,14 @@
#ifdef ANDROID
#include <utils/Log.h>

#ifdef ALOGE
#undef ALOGE
#endif

#define ALOGE(LOG_TAG, ...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
#ifndef LOGE
#define LOGE ALOGE
#endif

#ifdef ALOGW
#undef ALOGW
#endif

#define ALOGW(LOG_TAG, ...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
#ifndef LOGE
#define LOGW ALOGW
#endif

#ifdef ALOGI
#undef ALOGI
#endif

#define ALOGI(LOG_TAG, ...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
#ifndef LOGE
#define LOGI ALOGI
#endif

#ifdef ALOGD
#undef ALOGD
#endif

#define ALOGD(LOG_TAG, ...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#ifndef LOGE
#define LOGD ALOGD
#endif

#ifdef ALOGV
#undef ALOGV
#endif

#define ALOGV(LOG_TAG, ...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#ifndef LOGE
#define LOGV ALOGV
#endif

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

#include <vsomeip/internal/logger.hpp>
@@ -70,6 +33,91 @@ namespace logger {

std::mutex message::mutex__;

#ifdef __QNX__
slog2_buffer_set_config_t logger_impl::buffer_config = {0};
slog2_buffer_t logger_impl::buffer_handle[1] = {0};
#endif

inline auto constexpr levelAsString(level_e const _level) -> const char *
{
// Prepare log level
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__
inline auto constexpr logger_impl::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
inline constexpr auto level_to_aosp_level(level_e _level) {
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

message::message(level_e _level)
: std::ostream(&buffer_),
level_(_level) {
@@ -85,36 +133,24 @@ message::~message() try {
if (!its_configuration)
return;

#ifdef __QNX__
// Write to slog withuot filtering on the level. This way we can modify
// the threshold in the pps settings, e.g.
// echo buffer_name:n:7 >> /var/pps/slog2/verbose
if (its_configuration->has_slog2_log() && slog2_is_initialized_) {
// Truncates after 508 characters (and adds ellipsis)
slog2c(its_logger->buffer_handle[0], 0x0000, levelAsSlog2(_level), buffer_.data_.str());
}
#endif

if (level_ > its_configuration->get_loglevel())
return;

if (its_configuration->has_console_log()
|| its_configuration->has_file_log()) {

// Prepare log level
const char *its_level;
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";
};
const auto its_level = levelAsString(level_);

// Prepare time stamp
auto its_time_t = std::chrono::system_clock::to_time_t(when_);
@@ -143,29 +179,7 @@ message::~message() try {
<< std::endl;
#else
std::string app = runtime::get_property("LogApplication");

switch (level_) {
case level_e::LL_FATAL:
ALOGE(app.c_str(), ("VSIP: " + buffer_.data_.str()).c_str());
break;
case level_e::LL_ERROR:
ALOGE(app.c_str(), ("VSIP: " + buffer_.data_.str()).c_str());
break;
case level_e::LL_WARNING:
ALOGW(app.c_str(), ("VSIP: " + buffer_.data_.str()).c_str());
break;
case level_e::LL_INFO:
ALOGI(app.c_str(), ("VSIP: " + buffer_.data_.str()).c_str());
break;
case level_e::LL_DEBUG:
ALOGD(app.c_str(), ("VSIP: " + buffer_.data_.str()).c_str());
break;
case level_e::LL_VERBOSE:
ALOGV(app.c_str(), ("VSIP: " + buffer_.data_.str()).c_str());
break;
default:
ALOGI(app.c_str(), ("VSIP: " + buffer_.data_.str()).c_str());
};
static_cast<void>(__android_log_print(level_to_aosp_level(_level), app.c_str(), "VSIP: %s", buffer_.data_.str().c_str()));
#endif // !ANDROID
}

@@ -204,7 +218,7 @@ message::~message() try {
std::streambuf::int_type
message::buffer::overflow(std::streambuf::int_type c) {
if (c != EOF) {
data_ << (char)c;
data_ << static_cast<char>(c);
}

return c;

0 comments on commit 6553f94

Please sign in to comment.