}
}
- if (settings.structured.enabled) {
- auto levelPrefix = std::string(settings.structured.level_prefix);
- auto timeFormat = std::string(settings.structured.time_format);
- if (!timeFormat.empty()) {
- if (timeFormat == "numeric") {
- dnsdist::logging::LoggingConfiguration::setStructuredTimeFormat(dnsdist::logging::LoggingConfiguration::TimeFormat::Numeric);
- }
- else if (timeFormat == "ISO8601") {
- dnsdist::logging::LoggingConfiguration::setStructuredTimeFormat(dnsdist::logging::LoggingConfiguration::TimeFormat::ISO8601);
- }
- else {
- warnlog("Unknown value '%s' to logging.structured.time_format parameter", timeFormat);
- }
- }
-
- dnsdist::logging::LoggingConfiguration::setStructuredLogging(true, std::move(levelPrefix));
- }
-
dnsdist::configuration::updateImmutableConfiguration([settings](dnsdist::configuration::ImmutableConfiguration& config) {
config.d_loggingBackend = std::string(settings.structured.backend);
+ config.d_structuredLogging = settings.structured.enabled;
});
}
bool d_ringsRecordResponses{true};
bool d_snmpEnabled{false};
bool d_snmpTrapsEnabled{false};
+ bool d_structuredLogging{true};
};
/* this part of the configuration can be updated at runtime via
return dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose;
}
+bool doStructuredLogging()
+{
+ return dnsdist::configuration::getImmutableConfiguration().d_structuredLogging;
+}
+
}
void setup(const std::string& backend);
std::shared_ptr<const Logr::Logger> getTopLogger();
bool doVerboseLogging();
+bool doStructuredLogging();
}
}
});
luaCtx.writeFunction("setStructuredLogging", [](bool enable, std::optional<LuaAssociativeTable<std::string>> options) {
- std::string levelPrefix;
- std::string timeFormat;
+ std::string backend;
if (options) {
- getOptionalValue<std::string>(options, "levelPrefix", levelPrefix);
- if (getOptionalValue<std::string>(options, "timeFormat", timeFormat) == 1) {
- if (timeFormat == "numeric") {
- dnsdist::logging::LoggingConfiguration::setStructuredTimeFormat(dnsdist::logging::LoggingConfiguration::TimeFormat::Numeric);
- }
- else if (timeFormat == "ISO8601") {
- dnsdist::logging::LoggingConfiguration::setStructuredTimeFormat(dnsdist::logging::LoggingConfiguration::TimeFormat::ISO8601);
- }
- else {
- warnlog("Unknown value '%s' to setStructuredLogging's 'timeFormat' parameter", timeFormat);
- }
- }
+ getOptionalValue<std::string>(options, "backend", backend);
checkAllParametersConsumed("setStructuredLogging", options);
}
- dnsdist::logging::LoggingConfiguration::setStructuredLogging(enable, std::move(levelPrefix));
+ dnsdist::configuration::updateImmutableConfiguration([enable, &backend](dnsdist::configuration::ImmutableConfiguration& config) {
+ if (enable && !backend.empty()) {
+ config.d_loggingBackend = backend;
+ }
+ config.d_structuredLogging = enable;
+ });
});
luaCtx.writeFunction("showBinds", []() {
if (configCheck) {
throw std::runtime_error("Unable to read configuration file from " + config);
}
- dnsdist::logging::getTopLogger()->withName("lua-configuration")->info(Logr::Error, "Unable to read configuration from file", "configuration-file", Logging::Loggable(config));
+ SLOG(
+ warnlog("Unable to read configuration from '%s'", config),
+ dnsdist::logging::getTopLogger()->withName("lua-configuration")->info(Logr::Error, "Unable to read configuration from file", "configuration-file", Logging::Loggable(config))
+ );
}
else {
- vinfolog("Read configuration from '%s'", config);
if (dnsdist::logging::doVerboseLogging()) {
- dnsdist::logging::getTopLogger()->withName("lua-configuration")->info(Logr::Info, "Read configuration from file", "configuration-file", Logging::Loggable(config));
+ SLOG(
+ infolog("Read configuration from '%s'", config),
+ dnsdist::logging::getTopLogger()->withName("lua-configuration")->info(Logr::Info, "Read configuration from file", "configuration-file", Logging::Loggable(config))
+ );
}
}
parameters:
- name: "enabled"
type: "bool"
- default: "false"
+ default: "true"
description: |
- Set whether log messages should be in a structured-logging-like format. This is turned off by default.
- The resulting format looks like this (when timestamps are enabled via ``--log-timestamps`` and with ``level_prefix: prio`` and ``time_format: ISO8601``)::
-
- ts=\"2023-11-06T12:04:58+0100\" prio=\"Info\" msg=\"Added downstream server 127.0.0.1:53\"
-
- And with ``level_prefix: level`` and ``time_format: numeric``)::
-
- ts=\"1699268815.133\" level=\"Info\" msg=\"Added downstream server 127.0.0.1:53\"
-
+ Set whether log messages should be in structured-logging format."
+ changes:
+ - version: "2.1.0"
+ content: "This setting is now enabled by default"
- name: "level_prefix"
type: "String"
default: "prio"
description: "Set the key name for the log level. There is unfortunately no standard name for this key, so in some setups it might be useful to set this value to a different name to have consistency across products"
+ changes:
+ - version: "2.1.0"
+ content: "This setting has been removed"
- name: "time_format"
type: "String"
default: "numeric"
supported-values:
- "ISO8601"
- "numeric"
+ changes:
+ - version: "2.1.0"
+ content: "This setting has been removed"
- name: "backend"
type: "String"
default: ""
namespace dnsdist::logging
{
std::optional<std::ofstream> LoggingConfiguration::s_verboseStream{std::nullopt};
-std::string LoggingConfiguration::s_structuredLevelPrefix{"prio"};
-LoggingConfiguration::TimeFormat LoggingConfiguration::s_structuredTimeFormat{LoggingConfiguration::TimeFormat::Numeric};
-bool LoggingConfiguration::s_structuredLogging{false};
bool LoggingConfiguration::s_logTimestamps{false};
bool LoggingConfiguration::s_syslog{true};
-namespace
-{
- const char* getTimeFormat()
- {
- if (!dnsdist::logging::LoggingConfiguration::getStructuredLogging()) {
- return "%b %d %H:%M:%S ";
- }
-
- auto format = dnsdist::logging::LoggingConfiguration::getStructuredLoggingTimeFormat();
- if (format == dnsdist::logging::LoggingConfiguration::TimeFormat::ISO8601) {
- return "%FT%H:%M:%S%z";
- }
- return nullptr;
- }
-}
-
void logTime(std::ostream& stream)
{
std::array<char, 50> buffer{""};
- if (LoggingConfiguration::getStructuredLogging() && LoggingConfiguration::getStructuredLoggingTimeFormat() == LoggingConfiguration::TimeFormat::Numeric) {
- struct timeval now{};
- gettimeofday(&now, nullptr);
- snprintf(buffer.data(), buffer.size(), "%lld.%03ld", static_cast<long long>(now.tv_sec), static_cast<long>(now.tv_usec / 1000));
- }
- else {
- const auto* timeFormat = getTimeFormat();
- if (timeFormat == nullptr) {
- return;
- }
-
- time_t now{0};
- time(&now);
- struct tm localNow{};
- localtime_r(&now, &localNow);
+ time_t now{};
+ time(&now);
+ struct tm localNow{};
+ localtime_r(&now, &localNow);
- {
- // strftime is not thread safe, it can access locale information
- static std::mutex mutex;
- auto lock = std::scoped_lock(mutex);
+ {
+ // strftime is not thread safe, it can access locale information
+ static std::mutex mutex;
+ auto lock = std::scoped_lock(mutex);
- if (strftime(buffer.data(), buffer.size(), timeFormat, &localNow) == 0) {
- buffer[0] = '\0';
- }
+ if (strftime(buffer.data(), buffer.size(), "%b %d %H:%M:%S ", &localNow) == 0) {
+ buffer[0] = '\0';
}
}
- if (dnsdist::logging::LoggingConfiguration::getStructuredLogging()) {
- stream << "ts=" << std::quoted(buffer.data()) << " ";
- }
- else {
- stream << buffer.data();
- }
+ stream << buffer.data();
}
}
class LoggingConfiguration
{
public:
- enum class TimeFormat
- {
- Numeric,
- ISO8601
- };
-
static void setSyslog(bool value = true)
{
s_syslog = value;
}
- static void setStructuredLogging(bool value = true, std::string levelPrefix = "")
- {
- s_structuredLogging = value;
- if (value) {
- s_structuredLevelPrefix = levelPrefix.empty() ? "prio" : std::move(levelPrefix);
- }
- }
static void setLogTimestamps(bool value = true)
{
s_logTimestamps = value;
}
- static void setStructuredTimeFormat(TimeFormat format)
- {
- s_structuredTimeFormat = format;
- }
static void setVerboseStream(std::ofstream&& stream)
{
s_verboseStream = std::move(stream);
{
return s_verboseStream;
}
- static bool getStructuredLogging()
- {
- return s_structuredLogging;
- }
- static const std::string& getStructuredLoggingLevelPrefix()
- {
- return s_structuredLevelPrefix;
- }
-
- static TimeFormat getStructuredLoggingTimeFormat()
- {
- return s_structuredTimeFormat;
- }
private:
static std::optional<std::ofstream> s_verboseStream;
- static std::string s_structuredLevelPrefix;
- static TimeFormat s_structuredTimeFormat;
- static bool s_structuredLogging;
static bool s_logTimestamps;
static bool s_syslog;
};
dnsdist::logging::logTime(stream);
}
- if (dnsdist::logging::LoggingConfiguration::getStructuredLogging()) {
- stream << dnsdist::logging::LoggingConfiguration::getStructuredLoggingLevelPrefix() << "=\"" << syslogLevelToStr(level) << "\" ";
- stream << "msg=" << std::quoted(output) << std::endl;
- }
- else {
- stream << output << std::endl;
- }
-#else
- stream << output << std::endl;
#endif
+ stream << output << std::endl;
}
template <typename... Args>
do { \
slogCall; \
} while (0)
-#else // No structured logging (e.g. auth)
+
+#else // DNSdist
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
-#define SLOG(oldStyle, slogCall) \
- do { \
- oldStyle; \
- } while (0)
+#define SLOG(nonStructured, structured) \
+ do { \
+ if (dnsdist::logging::doStructuredLogging()) { \
+ structured; \
+ } \
+ else { \
+ nonStructured; \
+ } \
+ } \
+ while (0)
+
#endif /* ! DNSDIST */
#endif // RECURSOR || DNSDIST
#endif
#ifdef RECURSOR
#include "logger.hh"
-#else
+#else /* !RECURSOR */
#include "dolog.hh"
-#endif
+#if defined(DNSDIST)
+#include "dnsdist-logging.hh"
+#endif /* DNSDIST */
+#endif /* !RECURSOR */
#include "logging.hh"
bool CircularWriteBuffer::hasRoomFor(const std::string& str) const
SLOG(g_log<<Logger::Warning<<"Error connecting to remote logger "<<d_remote.toStringWithPort()<<": "<<e.what()<<std::endl,
g_slog->withName("protobuf")->error(Logr::Error, e.what(), "Exception while connecting to remote logger", "address", Logging::Loggable(d_remote)));
#else
- warnlog("Error connecting to remote logger %s: %s", d_remote.toStringWithPort(), e.what());
+ SLOG(warnlog("Error connecting to remote logger %s: %s", d_remote.toStringWithPort(), e.what()),
+ dnsdist::logging::getTopLogger()->withName("protobuf")->error(e.what(), "Exception while connecting to remote logger", "address", Logging::Loggable(d_remote))
+ );
#endif
return false;
}
catch (const std::exception& e)
{
+#ifdef RECURSOR
SLOG(cerr << "Remote Logger's maintenance thread died on: " << e.what() << endl,
g_slog->withName("protobuf")->error(Logr::Error, e.what(), "Remote Logger's maintenance thread died"));
+#else
+ SLOG(errlog("Remote Logger's maintenance thread died on: %s", e.what()),
+ dnsdist::logging::getTopLogger()->withName("protobuf")->error(e.what(), "Remote Logger's maintenance thread died")
+ );
+#endif
}
catch (...) {
+#ifdef RECURSOR
SLOG(cerr << "Remote Logger's maintenance thread died on unknown exception" << endl,
g_slog->withName("protobuf")->info(Logr::Error, "Remote Logger's maintenance thread died"));
+#else
+ SLOG(errlog("Remote Logger's maintenance thread died on: %s"),
+ dnsdist::logging::getTopLogger()->withName("protobuf")->info(Logr::Error, "Remote Logger's maintenance thread died")
+ );
+#endif
}
}
d_thread.join();
}
-