Files
falco/userspace/engine/logger.cpp
Leonardo Grasso abdf5512c8 fix(userspace): add portable compat wrappers for gmtime_r, localtime_r, strerror_r
The previous commits used gmtime_r/localtime_r (unavailable on Windows)
and assumed the GNU strerror_r variant returning char* (only on glibc).
This broke macOS, musl, WASM, and Win32 builds.

Add userspace/engine/compat.h with portable inline wrappers:
- falco_gmtime_r / falco_localtime_r: use gmtime_s/localtime_s on Win32
- falco_strerror_r: returns const char* on all platforms, detecting
  glibc via __GLIBC__ (not _GNU_SOURCE alone, since musl defines
  _GNU_SOURCE but provides the XSI variant returning int)

Also fixes a pre-existing bug in create_signal_handlers.cpp where
the GNU strerror_r return value was incorrectly compared to 0 and
the actual error string was discarded.

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2026-04-09 16:57:04 +02:00

140 lines
4.4 KiB
C++

// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2023 The Falco Authors.
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.
*/
#include <ctime>
#include "compat.h"
#include "logger.h"
#include "falco_common.h"
falco_logger::level falco_logger::current_level = falco_logger::level::INFO;
bool falco_logger::time_format_iso_8601 = false;
static sinsp_logger::severity decode_sinsp_severity(const std::string& s) {
if(s == "trace") {
return sinsp_logger::SEV_TRACE;
} else if(s == "debug") {
return sinsp_logger::SEV_DEBUG;
} else if(s == "info") {
return sinsp_logger::SEV_INFO;
} else if(s == "notice") {
return sinsp_logger::SEV_NOTICE;
} else if(s == "warning") {
return sinsp_logger::SEV_WARNING;
} else if(s == "error") {
return sinsp_logger::SEV_ERROR;
} else if(s == "critical") {
return sinsp_logger::SEV_CRITICAL;
} else if(s == "fatal") {
return sinsp_logger::SEV_FATAL;
}
throw falco_exception("Unknown sinsp log severity " + s);
}
void falco_logger::set_time_format_iso_8601(bool val) {
falco_logger::time_format_iso_8601 = val;
}
void falco_logger::set_level(const std::string& level) {
if(level == "emergency") {
falco_logger::current_level = falco_logger::level::EMERG;
} else if(level == "alert") {
falco_logger::current_level = falco_logger::level::ALERT;
} else if(level == "critical") {
falco_logger::current_level = falco_logger::level::CRIT;
} else if(level == "error") {
falco_logger::current_level = falco_logger::level::ERR;
} else if(level == "warning") {
falco_logger::current_level = falco_logger::level::WARNING;
} else if(level == "notice") {
falco_logger::current_level = falco_logger::level::NOTICE;
} else if(level == "info") {
falco_logger::current_level = falco_logger::level::INFO;
} else if(level == "debug") {
falco_logger::current_level = falco_logger::level::DEBUG;
} else {
throw falco_exception("Unknown log level " + level);
}
}
static std::string s_sinsp_logger_prefix = "";
void falco_logger::set_sinsp_logging(bool enable,
const std::string& severity,
const std::string& prefix) {
if(enable) {
s_sinsp_logger_prefix = prefix;
libsinsp_logger()->set_severity(decode_sinsp_severity(severity));
libsinsp_logger()->disable_timestamps();
libsinsp_logger()->add_callback_log(
[](std::string&& str, const sinsp_logger::severity sev) {
// note: using falco_logger::level ensures that the sinsp
// logs are always printed by the Falco logger. These
// logs are pre-filtered at the sinsp level depending
// on the configured severity
falco_logger::log(falco_logger::current_level, s_sinsp_logger_prefix + str);
});
} else {
libsinsp_logger()->remove_callback_log();
}
}
bool falco_logger::log_stderr = true;
bool falco_logger::log_syslog = true;
void falco_logger::log(falco_logger::level priority, const std::string&& msg) {
if(priority > falco_logger::current_level) {
return;
}
std::string copy = msg;
#ifndef _WIN32
if(falco_logger::log_syslog) {
// Syslog output should not have any trailing newline
if(copy.back() == '\n') {
copy.pop_back();
}
::syslog(static_cast<int>(priority), "%s", copy.c_str());
}
#endif
if(falco_logger::log_stderr) {
// log output should always have a trailing newline
if(copy.back() != '\n') {
copy.push_back('\n');
}
std::time_t result = std::time(nullptr);
if(falco_logger::time_format_iso_8601) {
char buf[sizeof "YYYY-MM-DDTHH:MM:SS-0000"];
struct tm gtm;
if(falco_gmtime_r(&result, &gtm) != NULL &&
(strftime(buf, sizeof(buf), "%FT%T%z", &gtm) != 0)) {
fprintf(stderr, "%s: %s", buf, copy.c_str());
}
} else {
struct tm ltm;
falco_localtime_r(&result, &ltm);
char tstr[std::size("WWW MMM DD HH:mm:ss YYYY")];
std::strftime(std::data(tstr), std::size(tstr), "%a %b %d %H:%M:%S %Y", &ltm);
fprintf(stderr, "%s: %s", tstr, copy.c_str());
}
}
}