Skip to content

Conversation

@rgacogne
Copy link
Member

Short description

This PR implements structured logging support for DNSdist. A small amount of code is duplicated from the recursor, I tried to refactor it but the result was ugly because some parts are really tied to the recursor.

Checklist

I have:

  • read the CONTRIBUTING.md document
  • read and accepted the Developer Certificate of Origin document, including the AI Policy, and added a "Signed-off-by" to my commits
  • compiled this code
  • tested this code
  • included documentation (including possible behaviour changes)
  • documented the code
  • added or modified regression test(s)
  • added or modified unit test(s)

@coveralls
Copy link

coveralls commented Dec 30, 2025

Pull Request Test Coverage Report for Build 21136026407

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details

  • 523 of 1771 (29.53%) changed or added relevant lines in 54 files are covered.
  • 10845 unchanged lines in 109 files lost coverage.
  • Overall coverage decreased (-0.6%) to 72.722%

Changes Missing Coverage Covered Lines Changed/Added Lines %
pdns/dnsdistdist/dnsdist-tcp.hh 1 2 50.0%
pdns/dnsdistdist/dnsdist-console.cc 19 21 90.48%
pdns/dnsdistdist/dnsdist-lua-bindings-packetcache.cc 0 2 0.0%
pdns/dnsdistdist/dnsdist-lua-hooks.cc 0 2 0.0%
pdns/dnsdistdist/dnsdist-lua-network.cc 4 6 66.67%
pdns/dnsdistdist/dnsdist-lua-rules.cc 0 2 0.0%
pdns/dnsdistdist/dnsdist-protobuf.cc 0 2 0.0%
pdns/dnsdistdist/test-dnsdistnghttp2-in_cc.cc 0 2 0.0%
pdns/remote_logger.cc 0 2 0.0%
pdns/dnsdistdist/dnsdist-doh-common.hh 0 3 0.0%
Files with Coverage Reduction New Missed Lines %
pdns/dnsdistdist/dolog.cc 1 0.0%
pdns/protozero-trace.hh 1 68.37%
pdns/dnsdistdist/dnsdist-console.cc 1 53.09%
pdns/dnsdistdist/dnsdist-lua-hooks.cc 1 93.59%
pdns/dnsdistdist/dnsdist-protobuf.cc 1 76.17%
pdns/burtle.hh 2 98.19%
pdns/channel.hh 2 54.92%
pdns/dns.cc 2 88.29%
pdns/dnsdistdist/dnsdist-dnsquestion.cc 2 40.79%
pdns/dnsdistdist/dnsdist-lua-bindings-kvs.cc 2 48.0%
Totals Coverage Status
Change from base Build 21131045147: -0.6%
Covered Lines: 128561
Relevant Lines: 164838

💛 - Coveralls

{

static bool doOneCarbonExport(const Carbon::Endpoint& endpoint)
static bool doOneCarbonExport(const Carbon::Endpoint& endpoint, const Logr::Logger& logger)

Check warning

Code scanning / CodeQL

Poorly documented large function Warning

Poorly documented function: fewer than 2% comments for a function of 263 lines.
}

static std::shared_ptr<DownstreamState> createBackendFromConfiguration(const dnsdist::rust::settings::BackendConfiguration& config, bool configCheck)
static std::shared_ptr<DownstreamState> createBackendFromConfiguration(const Context& context, const dnsdist::rust::settings::BackendConfiguration& config, bool configCheck)

Check warning

Code scanning / CodeQL

Poorly documented large function Warning

Poorly documented function: fewer than 2% comments for a function of 161 lines.
}

bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeableBackend, ServiceDiscovery::DiscoveredResolverConfig& config)
bool ServiceDiscovery::getDiscoveredConfig(const Logr::Logger& topLogger, const UpgradeableBackend& upgradeableBackend, ServiceDiscovery::DiscoveredResolverConfig& config)

Check warning

Code scanning / CodeQL

Poorly documented large function Warning

Poorly documented function: fewer than 2% comments for a function of 124 lines.

#ifndef DISABLE_BUILTIN_HTML
static void handleJSONStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
static void handleJSONStats(const YaHTTP::Request& req, YaHTTP::Response& resp, const Logr::Logger& logger)

Check warning

Code scanning / CodeQL

Poorly documented large function Warning

Poorly documented function: fewer than 2% comments for a function of 114 lines.
}

static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp)
static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp, const Logr::Logger& logger)

Check warning

Code scanning / CodeQL

Poorly documented large function Warning

Poorly documented function: fewer than 2% comments for a function of 203 lines.
@rgacogne rgacogne force-pushed the ddist-structured-logging branch from 5fee7f5 to 6b7c5bc Compare January 5, 2026 13:23
@rgacogne
Copy link
Member Author

rgacogne commented Jan 5, 2026

Rebased on current master to fix a conflict with #16576.

@rgacogne
Copy link
Member Author

rgacogne commented Jan 5, 2026

I'll have a look at #16693 to see how we can prevent or minimize conflicts, I'm not too worried.

@rgacogne rgacogne force-pushed the ddist-structured-logging branch from 44f062d to 5271287 Compare January 9, 2026 15:19
@rgacogne
Copy link
Member Author

rgacogne commented Jan 9, 2026

I looked at the possible conflicts with #16693 and edited the first commit of my branch to move logging.cc in pdns/ as is done in the other branch to limit the possible issues. There will be some work to do to merge the changes to logging.hh once one branch is merged, but that doesn't seem very hard to do, regardless of which branch is merged to master first.

@miodvallat
Copy link
Contributor

Note that in the auth PR, the plumbing work consists only of moving recursor-specific bits to the common place; but there is still some code duplication until things settle.

@rgacogne rgacogne force-pushed the ddist-structured-logging branch from 5271287 to 53ec974 Compare January 12, 2026 10:43
@rgacogne
Copy link
Member Author

Rebased on current master to fix conflicts.

@omoerbeek
Copy link
Member

omoerbeek commented Jan 15, 2026

Observation: the subsystem key is not always filled in.

msg="Adding TCP worker thread to handle TCP connections from clients" level="0" prio="Info" ts="1768484074.208"
msg="Adding outgoing DoH worker thread" level="0" prio="Info" ts="1768484074.208"

With rec I always try to make sure that the subsystem key is present.

@rgacogne
Copy link
Member Author

Right, this is unexpected since I documented that key to be always present in dnsdist as well. I'm thinking of adding a mandatory const std::string_view& subsystem parameter to getTopLogger() so that we cannot forget, do you think it would make sense?

@omoerbeek
Copy link
Member

Right, this is unexpected since I documented that key to be always present in dnsdist as well. I'm thinking of adding a mandatory const std::string_view& subsystem parameter to getTopLogger() so that we cannot forget, do you think it would make sense?

Yes, I think that would work. In rec I make sure that I never use g_slog directly and create a logger with withName(). But something that can be enforced by the compiler is better.

@miodvallat
Copy link
Contributor

Well, if you use g_slog directly without a withName() alteration, you can only use error() but not info(), which limits your capabilities enough to make you remember to not use a straight g_slog unless there is no other way.

@omoerbeek
Copy link
Member

Well, if you use g_slog directly without a withName() alteration, you can only use error() but not info(), which limits your capabilities enough to make you remember to not use a straight g_slog unless there is no other way.

Hmm this diff compiles and runes here:

diff --git a/pdns/recursordist/rec-main.cc b/pdns/recursordist/rec-main.cc
index 3b4851c2d..13d71a912 100644
--- a/pdns/recursordist/rec-main.cc
+++ b/pdns/recursordist/rec-main.cc
@@ -3159,6 +3159,9 @@ int main(int argc, char** argv)
 
     ::arg().setSLog(startupLog);
 
+    g_slog->error(99, "bla");
+    g_slog->info(Logr::Warning, "bla");
+
     string yamlconfigname;
     pdns::rust::settings::rec::Recursorsettings settings;
     pdns::settings::rec::YamlSettingsStatus yamlstatus{};

@miodvallat
Copy link
Contributor

Oh then it's info with the use of multiple Logging::Loggable values perhaps.

@omoerbeek
Copy link
Member

omoerbeek commented Jan 15, 2026

Oh then it's info with the use of multiple Logging::Loggable values perhaps.

Both these lines error, so no difference bewteen info and error

    g_slog->error(99, "bla", "k", Logging::Loggable("v"));
    g_slog->info(Logr::Warning, "bla", "k", Logging::Loggable("v"));

@rgacogne
Copy link
Member Author

Right, this is unexpected since I documented that key to be always present in dnsdist as well. I'm thinking of adding a mandatory const std::string_view& subsystem parameter to getTopLogger() so that we cannot forget, do you think it would make sense?

Yes, I think that would work. In rec I make sure that I never use g_slog directly and create a logger with withName(). But something that can be enforced by the compiler is better.

Done.

@rgacogne rgacogne force-pushed the ddist-structured-logging branch from 01573b7 to 498215c Compare January 16, 2026 12:31
@pieterlexis
Copy link
Contributor

pieterlexis commented Jan 16, 2026

I like it. But startup is a bit inconsistent. With this config, I get one line of un-structured log and one line of wrongly structured log (wrong backend) before structured logging actually does the right thing:

setStructuredLogging(true, { backend = "json" })
newServer({ address = "8.8.8.8" })
dnsdist 0.0.33893.0.ddiststructuredlogging.g498215c5ae.dirty comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it according to the terms of the GPL version 2
msg="Added downstream server" subsystem="configuration" level="0" prio="Info" ts="1768574581.850" backend.address="8.8.8.8:53" lua.function="newServer"
{"frontend.address": "127.0.0.1:5300", "level": "0", "msg": "Raised send buffer size", "network.send_buffer_size": "4194304", "priority": "6", "subsystem": "setup", "ts": "1768574581.850"}

Perhaps we should delay/buffer all logging until config has been parsed. When that was successful, log everything in the right format. If parsing was not successful, just use the default logging settings for the buffered messages.

@rgacogne
Copy link
Member Author

I like it. But startup is a bit inconsistent. With this config, I get one line of un-structured log and one line of wrongly structured log (wrong backend) before structured logging actually does the right thing:

You can use --structured-logging and --structured-logging-backend to prevent that.

Perhaps we should delay/buffer all logging until config has been parsed. When that was successful, log everything in the right format. If parsing was not successful, just use the default logging settings for the buffered messages.

What bothers me about that idea is that if we crash without reaching the "successful" part we get nothing.

@pieterlexis
Copy link
Contributor

That could be a problem indeed. Let's keep it like this and perhaps document that folks should use the command line switches if they need proper logging from the moment of startup.

Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
rgacogne and others added 23 commits January 19, 2026 11:00
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
I had not realized before that the `Logging::Loggable` ctor takes
a `const` reference to the object we pass to it, meaning that we
cannot pass temporaries to it without creating dangling references.

Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
@rgacogne rgacogne force-pushed the ddist-structured-logging branch from e83bc74 to ba030fb Compare January 19, 2026 11:24
pieterlexis
pieterlexis previously approved these changes Jan 19, 2026
Copy link
Contributor

@pieterlexis pieterlexis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One nit, but I can live with that. Merge it!

Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
Copy link
Contributor

@pieterlexis pieterlexis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ship it

@rgacogne rgacogne merged commit 1ff1dca into PowerDNS:master Jan 19, 2026
165 of 167 checks passed
@rgacogne rgacogne deleted the ddist-structured-logging branch January 19, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants