}
}
- dnsdist::configuration::updateImmutableConfiguration([settings](dnsdist::configuration::ImmutableConfiguration& config) {
+ std::optional<dnsdist::configuration::TimeFormat> timeFormat{};
+ const auto timeFormatStr = std::string(settings.structured.time_format);
+ if (!timeFormatStr.empty()) {
+ if (timeFormatStr == "numeric") {
+ timeFormat = dnsdist::configuration::TimeFormat::Numeric;
+ }
+ else if (timeFormatStr == "ISO8601") {
+ timeFormat = dnsdist::configuration::TimeFormat::ISO8601;
+ }
+ else {
+ SLOG(warnlog("Unknown value '%s' passed to logging.structured.time_format parameter", timeFormatStr),
+ context.logger->info(Logr::Warning, "Unknown value passed to logging.structured.time_format parameter", "value", Logging::Loggable(timeFormatStr)));
+ }
+ }
+
+ dnsdist::configuration::updateImmutableConfiguration([settings, timeFormat](dnsdist::configuration::ImmutableConfiguration& config) {
config.d_loggingBackend = std::string(settings.structured.backend);
config.d_structuredLogging = settings.structured.enabled;
+ if (timeFormat) {
+ config.d_structuredLoggingTimeFormat = *timeFormat;
+ }
});
}
static constexpr uint16_t s_udpIncomingBufferSize{1500}; // don't accept UDP queries larger than this value
static_assert(s_defaultPayloadSizeSelfGenAnswers < s_udpIncomingBufferSize, "The UDP responder's payload size should be smaller or equal to our incoming buffer size");
+enum class TimeFormat: uint8_t
+{
+ Numeric,
+ ISO8601
+};
+
/* this part of the configuration can only be updated at configuration
time, and is immutable once the configuration phase is over */
struct ImmutableConfiguration
uint32_t d_tcpBanDurationForExceedingMaxReadIOsPerQuery{60};
uint32_t d_tcpBanDurationForExceedingTCPTLSRate{10};
uint16_t d_maxUDPOutstanding{std::numeric_limits<uint16_t>::max()};
+ TimeFormat d_structuredLoggingTimeFormat{TimeFormat::Numeric};
uint8_t d_udpTimeout{2};
uint8_t d_tcpConnectionsOverloadThreshold{90};
uint8_t d_tcpConnectionsMaskV4{32};
namespace dnsdist::logging
{
+static const char* convertTime(const timeval& tval, std::array<char, 64>& buffer)
+{
+ auto format = dnsdist::configuration::getImmutableConfiguration().d_structuredLoggingTimeFormat;
+ if (format == dnsdist::configuration::TimeFormat::ISO8601) {
+ 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);
+
+ if (strftime(buffer.data(), buffer.size(), "%FT%H:%M:%S%z", &localNow) == 0) {
+ buffer[0] = '\0';
+ }
+ }
+
+ return buffer.data();
+ }
+ return Logging::toTimestampStringMilli(tval, buffer);
+}
+
#if defined(HAVE_SYSTEMD)
static void loggerSDBackend(const Logging::Entry& entry)
{
appendKeyAndVal("SUBSYSTEM", entry.name.value());
}
std::array<char, 64> timebuf{};
- appendKeyAndVal("TIMESTAMP", Logging::toTimestampStringMilli(entry.d_timestamp, timebuf));
+ appendKeyAndVal("TIMESTAMP", convertTime(entry.d_timestamp, timebuf));
for (const auto& value : entry.values) {
if (value.first.at(0) == '_' || special.count(value.first) != 0) {
string key{"PDNS"};
json11::Json::object json = {
{"msg", entry.message},
{"level", std::to_string(entry.level)},
- {"ts", Logging::toTimestampStringMilli(entry.d_timestamp, timebuf)},
+ {"ts", convertTime(entry.d_timestamp, timebuf)},
};
if (entry.error) {
}
std::array<char, 64> timebuf{};
- buf << " ts=" << std::quoted(Logging::toTimestampStringMilli(entry.d_timestamp, timebuf));
+ buf << " ts=" << std::quoted(convertTime(entry.d_timestamp, timebuf));
for (auto const& value : entry.values) {
buf << " ";
buf << value.first << "=" << std::quoted(value.second);
}
});
luaCtx.writeFunction("setStructuredLogging", [](bool enable, std::optional<LuaAssociativeTable<std::string>> options) {
+ std::optional<dnsdist::configuration::TimeFormat> format{};
+ std::string timeFormat;
std::string backend;
if (options) {
+ if (getOptionalValue<std::string>(options, "timeFormat", timeFormat) == 1) {
+ if (timeFormat == "numeric") {
+ format = dnsdist::configuration::TimeFormat::Numeric;
+ }
+ else if (timeFormat == "ISO8601") {
+ format = dnsdist::configuration::TimeFormat::ISO8601;
+ }
+ else {
+ SLOG(warnlog("Unknown value '%s' to setStructuredLogging's 'timeFormat' parameter", timeFormat),
+ getLogger("setStructuredLogging")->info(Logr::Warning, "Unknown value passed to setStructuredLogging's 'timeFormat' parameter", "value", Logging::Loggable(timeFormat)));
+ }
+ }
getOptionalValue<std::string>(options, "backend", backend);
checkAllParametersConsumed("setStructuredLogging", options);
}
- dnsdist::configuration::updateImmutableConfiguration([enable, &backend](dnsdist::configuration::ImmutableConfiguration& config) {
+ dnsdist::configuration::updateImmutableConfiguration([enable, &backend, format](dnsdist::configuration::ImmutableConfiguration& config) {
if (enable && !backend.empty()) {
config.d_loggingBackend = backend;
}
+ if (format) {
+ config.d_structuredLoggingTimeFormat = *format;
+ }
config.d_structuredLogging = enable;
});
});
parameters:
- name: "enabled"
type: "bool"
- default: "true"
+ default: "false"
description: |
Set whether log messages should be in structured-logging format."
changes:
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"
+ content: "This setting has no longer any effect because it was confusing. The log level is now always logged as ``level`` and the syslog priority, if any, as ``priority`` in all backends except the default one where it is named ``prio``"
- 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: ""
.. versionadded:: 1.9.0
+ .. versionchanged:: 2.1.0
+ The ``level_prefix`` option has no longer any effect because it was confusing. The log level is now always logged as ``level`` and the syslog priority, if any, as ``priority`` in all backends except the default one where it is named ``prio``
+
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 ``levelPrefix="prio"`` and ``timeFormat="ISO8601"``)::
+ The resulting format looks like this (when timestamps are enabled via ``--log-timestamps`` and ``timeFormat="ISO8601"``)::
- ts="2023-11-06T12:04:58+0100" prio="Info" msg="Added downstream server 127.0.0.1:53"
+ ts="2023-11-06T12:04:58+0100" level="Info" msg="Added downstream server 127.0.0.1:53"
- And with ``levelPrefix="level"`` and ``timeFormat="numeric"``)::
+ And with ``timeFormat="numeric"`` instead)::
ts="1699268815.133" level="Info" msg="Added downstream server 127.0.0.1:53"
Options:
- * ``levelPrefix=prefix``: string - Set the prefix for the log level. Default is ``prio``.
+ * ``levelPrefix=prefix``: string - Set the prefix for the log level. Default is ``prio``. Not supported since 2.1.0.
* ``timeFormat=format``: string - Set the time format. Supported values are ``ISO8601`` and ``numeric``. Default is ``numeric``.
.. function:: setOpenTelemetryTracing(value)