Files
ternfs-XTXMarkets/cpp/core/Env.hpp
Francesco Mazzoli 38f3d54ecd Wait forever, rather than having timeouts
The goal here is to not have constant wakeups due to timeout. Do
not attempt to clean things up nicely before termination -- just
terminate instead. We can setup a proper termination system in
the future, I first want to see if this makes a difference.

Also, change xmon to use pipes for communication, so that it can
wait without timers as well.

Also, `write` directly for logging, so that we know the logs will
make it to the file after the logging call returns (since we now
do not have the chance to flush them afterwards).
2023-12-07 10:11:19 +00:00

183 lines
5.0 KiB
C++

#pragma once
#include <cstdint>
#include <mutex>
#include <sstream>
#include <string>
#include <signal.h>
#include <memory>
#include "Common.hpp"
#include "Exception.hpp"
#include "Time.hpp"
#include "XmonAgent.hpp"
enum class LogLevel : uint32_t {
LOG_TRACE = 0,
LOG_DEBUG = 1,
LOG_INFO = 2,
LOG_ERROR = 3,
};
std::ostream& operator<<(std::ostream& out, LogLevel ll);
void installLoggerSignalHandler(void* logger);
void tearDownLoggerSignalHandler(void* logger);
struct Logger {
private:
LogLevel _logLevel;
LogLevel _savedLogLevel;
int _fd;
std::mutex _mutex;
bool _syslog;
bool _usr2ToDebug;
public:
Logger(LogLevel logLevel, int fd, bool syslog, bool usr2ToDebug):
_logLevel(logLevel), _savedLogLevel(logLevel), _fd(fd), _syslog(syslog), _usr2ToDebug(usr2ToDebug)
{
if (usr2ToDebug) {
installLoggerSignalHandler(this);
}
}
~Logger() {
if (_usr2ToDebug) {
tearDownLoggerSignalHandler(this);
}
}
template<typename ...Args>
void _log(LogLevel level, const std::string& prefix, const char* fmt, Args&&... args) {
std::stringstream formatSs;
std::stringstream outSs;
format_pack(formatSs, fmt, args...);
std::string line;
if (likely(_syslog)) {
int syslogLevel;
switch (level) {
case LogLevel::LOG_TRACE:
case LogLevel::LOG_DEBUG:
syslogLevel = 7; break;
case LogLevel::LOG_INFO:
syslogLevel = 6; break;
case LogLevel::LOG_ERROR:
syslogLevel = 3; break;
default:
syslogLevel = 3; break; // should be throw?
}
while (std::getline(formatSs, line)) {
outSs << "<" << syslogLevel << ">" << prefix << ": " << line << std::endl;
}
} else {
auto t = eggsNow();
while (std::getline(formatSs, line)) {
outSs << t << " " << prefix << " [" << level << "] " << line << std::endl;
}
}
{
std::scoped_lock lock(_mutex);
std::string_view v = outSs.view();
int remaining = v.size();
while (remaining) {
int res = write(_fd, v.data(), v.size());
if (res < 0) {
throw SYSCALL_EXCEPTION("write");
}
remaining -= res;
}
}
}
bool _shouldLog(LogLevel level) {
return level >= _logLevel;
}
void toggleDebug();
};
struct Env {
private:
Logger& _logger;
std::shared_ptr<XmonAgent> _xmon;
std::string _prefix;
public:
Env(Logger& logger, std::shared_ptr<XmonAgent>& xmon, const std::string& prefix): _logger(logger), _xmon(xmon), _prefix(prefix) {}
template<typename ...Args>
void _log(LogLevel level, const char* fmt, Args&&... args) {
_logger._log(level, _prefix, fmt, std::forward<Args>(args)...);
}
template<typename ...Args>
void raiseAlert(const char* fmt, Args&&... args) {
std::stringstream ss;
format_pack(ss, fmt, args...);
std::string line;
std::string s = ss.str();
_log(LogLevel::LOG_ERROR, s.c_str());
if (likely(_xmon)) {
_xmon->raiseAlert(s);
}
}
template<typename ...Args>
void updateAlert(XmonNCAlert& alert, const char* fmt, Args&&... args) {
std::stringstream ss;
format_pack(ss, fmt, args...);
std::string line;
std::string s = ss.str();
_log(LogLevel::LOG_ERROR, s.c_str());
if (likely(_xmon)) {
_xmon->updateAlert(alert, s);
}
}
void clearAlert(XmonNCAlert& alert) {
if (likely(_xmon)) {
_xmon->clearAlert(alert);
}
}
bool _shouldLog(LogLevel level) {
return _logger._shouldLog(level);
}
};
#ifdef EGGS_DEBUG
#define LOG_TRACE(env, ...) \
do { \
if (unlikely((env)._shouldLog(LogLevel::LOG_TRACE))) { \
(env)._log(LogLevel::LOG_TRACE, VALIDATE_FORMAT(__VA_ARGS__)); \
} \
} while (false)
#else
#define LOG_TRACE(env, ...) do {} while (false)
#endif
#define LOG_DEBUG(env, ...) \
do { \
if (unlikely((env)._shouldLog(LogLevel::LOG_DEBUG))) { \
(env)._log(LogLevel::LOG_DEBUG, VALIDATE_FORMAT(__VA_ARGS__)); \
} \
} while (false)
#define LOG_INFO(env, ...) \
do { \
if (likely((env)._shouldLog(LogLevel::LOG_INFO))) { \
(env)._log(LogLevel::LOG_INFO, VALIDATE_FORMAT(__VA_ARGS__)); \
} \
} while (false)
#define LOG_ERROR(env, ...) \
do { \
if (likely((env)._shouldLog(LogLevel::LOG_ERROR))) { \
(env)._log(LogLevel::LOG_ERROR, VALIDATE_FORMAT(__VA_ARGS__)); \
} \
} while (false)
#define RAISE_ALERT(env, ...) \
do { \
(env).raiseAlert(VALIDATE_FORMAT(__VA_ARGS__)); \
} while (false)