mirror of
https://github.com/savoirfairelinux/opendht.git
synced 2026-11-08 04:21:51 +00:00
185 lines
4.5 KiB
C++
185 lines
4.5 KiB
C++
// Copyright (c) 2014-2026 Savoir-faire Linux Inc.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#include "log.h"
|
|
#include "dhtrunner.h"
|
|
|
|
#include <fmt/format.h>
|
|
#include <fmt/ostream.h>
|
|
#include <fmt/printf.h>
|
|
|
|
#ifndef _WIN32
|
|
#include <syslog.h>
|
|
#endif
|
|
|
|
#include <fstream>
|
|
#include <chrono>
|
|
|
|
namespace dht {
|
|
namespace log {
|
|
|
|
/**
|
|
* Terminal colors for logging
|
|
*/
|
|
namespace Color {
|
|
enum Code {
|
|
FG_RED = 31,
|
|
FG_GREEN = 32,
|
|
FG_YELLOW = 33,
|
|
FG_BLUE = 34,
|
|
FG_DEFAULT = 39,
|
|
BG_RED = 41,
|
|
BG_GREEN = 42,
|
|
BG_BLUE = 44,
|
|
BG_DEFAULT = 49
|
|
};
|
|
class Modifier
|
|
{
|
|
const Code code;
|
|
|
|
public:
|
|
constexpr Modifier(Code pCode)
|
|
: code(pCode)
|
|
{}
|
|
friend std::ostream& operator<<(std::ostream& os, const Modifier& mod) { return os << "\033[" << mod.code << 'm'; }
|
|
};
|
|
} // namespace Color
|
|
|
|
constexpr const Color::Modifier def(Color::FG_DEFAULT);
|
|
constexpr const Color::Modifier red(Color::FG_RED);
|
|
constexpr const Color::Modifier yellow(Color::FG_YELLOW);
|
|
|
|
using namespace std::chrono;
|
|
using log_precision = microseconds;
|
|
constexpr auto den = log_precision::period::den;
|
|
|
|
/**
|
|
* Print va_list to std::ostream (used for logging).
|
|
*/
|
|
void
|
|
printfLog(std::ostream& s, source_loc loc, std::string_view prefix, const std::string& message)
|
|
{
|
|
auto num = duration_cast<log_precision>(steady_clock::now().time_since_epoch()).count();
|
|
if (!loc.file.empty())
|
|
fmt::print(s,
|
|
"[{:06d}.{:06d} {:>20}:{:<5} {:<24}] {}",
|
|
num / den,
|
|
num % den,
|
|
loc.file,
|
|
loc.line,
|
|
loc.function,
|
|
prefix);
|
|
else
|
|
fmt::print(s, "[{:06d}.{:06d}] {}", num / den, num % den, prefix);
|
|
s << message << std::endl;
|
|
}
|
|
|
|
void
|
|
printLog(std::ostream& s, source_loc loc, std::string_view prefix, fmt::string_view format, fmt::format_args args)
|
|
{
|
|
auto num = duration_cast<log_precision>(steady_clock::now().time_since_epoch()).count();
|
|
fmt::print(s, "[{:06d}.{:06d}] [{:>16}:{:<5}] {}", num / den, num % den, loc.file, loc.line, prefix);
|
|
fmt::vprint(s, format, args);
|
|
s << std::endl;
|
|
}
|
|
|
|
std::shared_ptr<Logger>
|
|
getStdLogger()
|
|
{
|
|
return std::make_shared<Logger>([](source_loc loc, LogLevel level, std::string_view prefix, std::string&& message) {
|
|
if (level == LogLevel::error)
|
|
std::cerr << red;
|
|
else if (level == LogLevel::warning)
|
|
std::cerr << yellow;
|
|
printfLog(std::cerr, loc, prefix, message);
|
|
std::cerr << def;
|
|
});
|
|
}
|
|
|
|
std::shared_ptr<Logger>
|
|
getFileLogger(const std::string& path)
|
|
{
|
|
auto logfile = std::make_shared<std::ofstream>();
|
|
logfile->open(path, std::ios::out);
|
|
return std::make_shared<Logger>(
|
|
[logfile](source_loc loc, LogLevel /*level*/, std::string_view prefix, std::string&& message) {
|
|
printfLog(*logfile, loc, prefix, message);
|
|
});
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
constexpr int
|
|
syslogLevel(LogLevel level)
|
|
{
|
|
switch (level) {
|
|
case LogLevel::error:
|
|
return LOG_ERR;
|
|
case LogLevel::warning:
|
|
return LOG_WARNING;
|
|
case LogLevel::debug:
|
|
return LOG_INFO;
|
|
}
|
|
return LOG_ERR;
|
|
}
|
|
#endif
|
|
|
|
std::shared_ptr<Logger>
|
|
getSyslogLogger(const char* name)
|
|
{
|
|
#ifndef _WIN32
|
|
struct Syslog
|
|
{
|
|
explicit Syslog(const char* n) { openlog(n, LOG_NDELAY, LOG_USER); }
|
|
~Syslog() { closelog(); }
|
|
};
|
|
// syslog is global. Existing instance must be reused.
|
|
static std::weak_ptr<Syslog> opened_logfile;
|
|
auto logfile = opened_logfile.lock();
|
|
if (not logfile) {
|
|
logfile = std::make_shared<Syslog>(name);
|
|
opened_logfile = logfile;
|
|
}
|
|
return std::make_shared<Logger>(
|
|
[logfile](source_loc loc, LogLevel level, std::string_view prefix, std::string&& message) {
|
|
syslog(syslogLevel(level),
|
|
"%.*s:%u %.*s%.*s",
|
|
(int) loc.file.size(),
|
|
loc.file.data(),
|
|
loc.line,
|
|
(int) prefix.size(),
|
|
prefix.data(),
|
|
(int) message.size(),
|
|
message.data());
|
|
});
|
|
#else
|
|
return getStdLogger();
|
|
#endif
|
|
}
|
|
|
|
void
|
|
enableLogging(dht::DhtRunner& dht)
|
|
{
|
|
dht.setLogger(getStdLogger());
|
|
}
|
|
|
|
void
|
|
enableFileLogging(dht::DhtRunner& dht, const std::string& path)
|
|
{
|
|
dht.setLogger(getFileLogger(path));
|
|
}
|
|
|
|
OPENDHT_PUBLIC void
|
|
enableSyslog(dht::DhtRunner& dht, const char* name)
|
|
{
|
|
dht.setLogger(getSyslogLogger(name));
|
|
}
|
|
|
|
void
|
|
disableLogging(dht::DhtRunner& dht)
|
|
{
|
|
dht.setLogger();
|
|
}
|
|
|
|
} // namespace log
|
|
} // namespace dht
|