]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: More structured logging
authorRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 15 Dec 2025 17:01:15 +0000 (18:01 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 19 Jan 2026 09:58:27 +0000 (10:58 +0100)
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
pdns/dnsdistdist/dnsdist-discovery.cc
pdns/dnsdistdist/dnsdist-discovery.hh
pdns/dnsdistdist/dnsdist-dnscrypt.cc
pdns/dnsdistdist/dnsdist-dynblocks.cc
pdns/dnsdistdist/dnsdist-healthchecks.cc

index b3b9fff82ef726ca6d52bcc266b5d1fc9935ba5c..d07ac100396afb87063cddaef6a5be88c94e363e 100644 (file)
@@ -139,11 +139,12 @@ static bool parseSVCParams(const PacketBuffer& answer, std::map<uint16_t, Design
   return !resolvers.empty();
 }
 
-static bool handleSVCResult(const PacketBuffer& answer, const ComboAddress& existingAddr, uint16_t dohSVCKey, ServiceDiscovery::DiscoveredResolverConfig& config)
+static bool handleSVCResult(const Logr::Logger& logger, const PacketBuffer& answer, const ComboAddress& existingAddr, uint16_t dohSVCKey, ServiceDiscovery::DiscoveredResolverConfig& config)
 {
   std::map<uint16_t, DesignatedResolvers> resolvers;
   if (!parseSVCParams(answer, resolvers)) {
-    vinfolog("No configuration found in response for backend %s", existingAddr.toStringWithPort());
+    VERBOSESLOG(infolog("No configuration found in response for backend %s", existingAddr.toStringWithPort()),
+                logger.info(Logr::Info, "No configuration found in response"));
     return false;
   }
 
@@ -198,7 +199,8 @@ static bool handleSVCResult(const PacketBuffer& answer, const ComboAddress& exis
       continue;
 #endif
       if (tempConfig.d_dohPath.empty()) {
-        vinfolog("Got a DoH upgrade offered for %s but no path, skipping", existingAddr.toStringWithPort());
+        VERBOSESLOG(infolog("Got a DoH upgrade offered for %s but no path, skipping", existingAddr.toStringWithPort()),
+                    logger.info(Logr::Info, "Got a DoH upgrade offer but no path, skipping"));
         continue;
       }
     }
@@ -234,7 +236,7 @@ static bool handleSVCResult(const PacketBuffer& answer, const ComboAddress& exis
   return false;
 }
 
-bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeableBackend, ServiceDiscovery::DiscoveredResolverConfig& config)
+bool ServiceDiscovery::getDiscoveredConfig(const Logr::Logger& topLogger, const UpgradeableBackend& upgradeableBackend, ServiceDiscovery::DiscoveredResolverConfig& config)
 {
   const auto verbose = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose;
   const auto& backend = upgradeableBackend.d_ds;
@@ -248,6 +250,8 @@ bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeable
     pw.addOpt(4096, 0, 0);
     pw.commit();
 
+    auto logger = topLogger.withValues("dns.query.id", Logging::Loggable(id), "dns.query.name", Logging::Loggable(s_discoveryDomain), "dns.query.type", Logging::Loggable(QType(s_discoveryType)));
+
     uint16_t querySize = static_cast<uint16_t>(packet.size());
     const uint8_t sizeBytes[] = {static_cast<uint8_t>(querySize / 256), static_cast<uint8_t>(querySize % 256)};
     packet.insert(packet.begin(), sizeBytes, sizeBytes + 2);
@@ -279,7 +283,8 @@ bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeable
     auto got = readn2WithTimeout(sock.getHandle(), &responseSize, sizeof(responseSize), remainingTime);
     if (got != sizeof(responseSize)) {
       if (verbose) {
-        warnlog("Error while waiting for the ADD upgrade response size from backend %s: %d", addr.toStringWithPort(), got);
+        SLOG(warnlog("Error while waiting for the ADD upgrade response size from backend %s: %d", addr.toStringWithPort(), got),
+             logger->info(Logr::Warning, "Error while waiting for the ADD upgrade response size from backend", "value", Logging::Loggable(got), "expected", Logging::Loggable(sizeof(responseSize))));
       }
       return false;
     }
@@ -289,14 +294,16 @@ bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeable
     got = readn2WithTimeout(sock.getHandle(), packet.data(), packet.size(), remainingTime);
     if (got != packet.size()) {
       if (verbose) {
-        warnlog("Error while waiting for the ADD upgrade response from backend %s: %d", addr.toStringWithPort(), got);
+        SLOG(warnlog("Error while waiting for the ADD upgrade response from backend %s: %d", addr.toStringWithPort(), got),
+             logger->info(Logr::Warning, "Error while waiting for the ADD upgrade response from backend", "value", Logging::Loggable(got), "expected", Logging::Loggable(packet.size())));
       }
       return false;
     }
 
     if (packet.size() <= sizeof(struct dnsheader)) {
       if (verbose) {
-        warnlog("Too short answer of size %d received from the backend %s", packet.size(), addr.toStringWithPort());
+        SLOG(warnlog("Too short answer of size %d received from the backend %s", packet.size(), addr.toStringWithPort()),
+             logger->info(Logr::Warning, "Too short answer received from the backend", "dns.response.size", Logging::Loggable(packet.size())));
       }
       return false;
     }
@@ -305,14 +312,16 @@ bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeable
     memcpy(&d, packet.data(), sizeof(d));
     if (d.id != id) {
       if (verbose) {
-        warnlog("Invalid ID (%d / %d) received from the backend %s", d.id, id, addr.toStringWithPort());
+        SLOG(warnlog("Invalid ID (%d / %d) received from the backend %s", d.id, id, addr.toStringWithPort()),
+             logger->info(Logr::Warning, "Invalid ID received from the backend", "dns.response.id", Logging::Loggable(d.id)));
       }
       return false;
     }
 
     if (d.rcode != RCode::NoError) {
       if (verbose) {
-        warnlog("Response code '%s' received from the backend %s for '%s'", RCode::to_s(d.rcode), addr.toStringWithPort(), s_discoveryDomain);
+        SLOG(warnlog("Response code '%s' received from the backend %s for '%s'", RCode::to_s(d.rcode), addr.toStringWithPort(), s_discoveryDomain),
+             logger->info(Logr::Warning, "Unexpected response code received from backend", "dns.response.code", Logging::Loggable(RCode::to_s(d.rcode))));
       }
 
       return false;
@@ -320,7 +329,8 @@ bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeable
 
     if (ntohs(d.qdcount) != 1) {
       if (verbose) {
-        warnlog("Invalid answer (qdcount %d) received from the backend %s", ntohs(d.qdcount), addr.toStringWithPort());
+        SLOG(warnlog("Invalid answer (qdcount %d) received from the backend %s", ntohs(d.qdcount), addr.toStringWithPort()),
+             logger->info(Logr::Warning, "Invalid qdcount in answer received from the backend", "dns.response.qdcount", Logging::Loggable(ntohs(d.qdcount))));
       }
       return false;
     }
@@ -331,24 +341,27 @@ bool ServiceDiscovery::getDiscoveredConfig(const UpgradeableBackend& upgradeable
 
     if (receivedName != s_discoveryDomain || receivedType != s_discoveryType || receivedClass != QClass::IN) {
       if (verbose) {
-        warnlog("Invalid answer, either the qname (%s / %s), qtype (%s / %s) or qclass (%s / %s) does not match, received from the backend %s", receivedName, s_discoveryDomain, QType(receivedType).toString(), s_discoveryType.toString(), QClass(receivedClass).toString(), QClass::IN.toString(), addr.toStringWithPort());
+        SLOG(warnlog("Invalid answer, either the qname (%s / %s), qtype (%s / %s) or qclass (%s / %s) does not match, received from the backend %s", receivedName, s_discoveryDomain, QType(receivedType).toString(), s_discoveryType.toString(), QClass(receivedClass).toString(), QClass::IN.toString(), addr.toStringWithPort()),
+             logger->info(Logr::Warning, "Response received from the backend doesn't match query", "dns.response.name", Logging::Loggable(receivedName), "dns.response.type", Logging::Loggable(QType(receivedType)), "dns.response.class", Logging::Loggable(receivedClass)));
       }
       return false;
     }
 
-    return handleSVCResult(packet, addr, upgradeableBackend.d_dohKey, config);
+    return handleSVCResult(*logger, packet, addr, upgradeableBackend.d_dohKey, config);
   }
   catch (const std::exception& e) {
-    warnlog("Error while trying to discover backend upgrade for %s: %s", addr.toStringWithPort(), e.what());
+    SLOG(warnlog("Error while trying to discover backend upgrade for %s: %s", addr.toStringWithPort(), e.what()),
+         topLogger.error(Logr::Warning, e.what(), "Error while trying to discover backend upgrade"));
   }
   catch (...) {
-    warnlog("Error while trying to discover backend upgrade for %s", addr.toStringWithPort());
+    SLOG(warnlog("Error while trying to discover backend upgrade for %s", addr.toStringWithPort()),
+         topLogger.info(Logr::Error, "Error while trying to discover backend upgrade"));
   }
 
   return false;
 }
 
-static bool checkBackendUsability(std::shared_ptr<DownstreamState>& ds)
+static bool checkBackendUsability(const Logr::Logger& logger, std::shared_ptr<DownstreamState>& ds)
 {
   try {
     Socket sock(ds->d_config.remote.sin4.sin_family, SOCK_STREAM);
@@ -375,21 +388,25 @@ static bool checkBackendUsability(std::shared_ptr<DownstreamState>& ds)
     return true;
   }
   catch (const std::exception& e) {
-    vinfolog("Exception when trying to use a newly upgraded backend %s (subject %s): %s", ds->getNameWithAddr(), ds->d_config.d_tlsSubjectName, e.what());
+    VERBOSESLOG(infolog("Exception when trying to use a newly upgraded backend %s (subject %s): %s", ds->getNameWithAddr(), ds->d_config.d_tlsSubjectName, e.what()),
+                logger.error(Logr::Info, e.what(), "Exception when trying to use a newly upgraded backend", "tls-subject-name", Logging::Loggable(ds->d_config.d_tlsSubjectName)));
   }
   catch (...) {
-    vinfolog("Exception when trying to use a newly upgraded backend %s (subject %s)", ds->getNameWithAddr(), ds->d_config.d_tlsSubjectName);
+    VERBOSESLOG(infolog("Exception when trying to use a newly upgraded backend %s (subject %s)", ds->getNameWithAddr(), ds->d_config.d_tlsSubjectName),
+                logger.info(Logr::Info, "Exception when trying to use a newly upgraded backend", "tls-subject-name", Logging::Loggable(ds->d_config.d_tlsSubjectName)));
   }
 
   return false;
 }
 
-bool ServiceDiscovery::tryToUpgradeBackend(const UpgradeableBackend& backend)
+bool ServiceDiscovery::tryToUpgradeBackend(const Logr::Logger& logger, const UpgradeableBackend& backend)
 {
   ServiceDiscovery::DiscoveredResolverConfig discoveredConfig;
 
-  vinfolog("Trying to discover configuration for backend %s", backend.d_ds->getNameWithAddr());
-  if (!ServiceDiscovery::getDiscoveredConfig(backend, discoveredConfig)) {
+  VERBOSESLOG(infolog("Trying to discover configuration for backend %s", backend.d_ds->getNameWithAddr()),
+              logger.info(Logr::Info, "Trying to discover upgrade configuration for backend"));
+
+  if (!ServiceDiscovery::getDiscoveredConfig(logger, backend, discoveredConfig)) {
     return false;
   }
 
@@ -444,12 +461,14 @@ bool ServiceDiscovery::tryToUpgradeBackend(const UpgradeableBackend& backend)
     auto newServer = std::make_shared<DownstreamState>(std::move(config), std::move(tlsCtx), true);
 
     /* check that we can connect to the backend (including certificate validation */
-    if (!checkBackendUsability(newServer)) {
-      vinfolog("Failed to use the automatically upgraded server %s, skipping for now", newServer->getNameWithAddr());
+    if (!checkBackendUsability(logger, newServer)) {
+      VERBOSESLOG(infolog("Failed to use the automatically upgraded server %s, skipping for now", newServer->getNameWithAddr()),
+                  logger.info(Logr::Info, "Failed to use the automatically upgraded server, skipping for now"));
       return false;
     }
 
-    infolog("Added automatically upgraded server %s", newServer->getNameWithAddr());
+    SLOG(infolog("Added automatically upgraded server %s", newServer->getNameWithAddr()),
+         logger.info(Logr::Info, "Added automatically upgraded server"));
 
     if (!newServer->d_config.pools.empty()) {
       for (const auto& poolName : newServer->d_config.pools) {
@@ -490,7 +509,8 @@ bool ServiceDiscovery::tryToUpgradeBackend(const UpgradeableBackend& backend)
     return true;
   }
   catch (const std::exception& e) {
-    warnlog("Error when trying to upgrade a discovered backend: %s", e.what());
+    SLOG(warnlog("Error when trying to upgrade a discovered backend: %s", e.what()),
+         logger.error(Logr::Warning, e.what(), "Error when trying to upgrade a discovered backend"));
   }
 
   return false;
@@ -499,6 +519,8 @@ bool ServiceDiscovery::tryToUpgradeBackend(const UpgradeableBackend& backend)
 void ServiceDiscovery::worker()
 {
   setThreadName("dnsdist/discove");
+  auto logger = dnsdist::logging::getTopLogger()->withName("service-discovery");
+
   while (true) {
     dnsdist::configuration::refreshLocalRuntimeConfiguration();
     time_t now = time(nullptr);
@@ -508,13 +530,15 @@ void ServiceDiscovery::worker()
 
     for (auto backendIt = upgradeables.begin(); backendIt != upgradeables.end();) {
       auto& backend = *backendIt;
+      auto backendLogger = logger->withValues("backend.name", Logging::Loggable(backend->d_ds->getName()), "backend.address", Logging::Loggable(backend->d_ds->d_config.remote));
+
       try {
         if (backend->d_nextCheck > now) {
           ++backendIt;
           continue;
         }
 
-        auto upgraded = tryToUpgradeBackend(*backend);
+        auto upgraded = tryToUpgradeBackend(*backendLogger, *backend);
         if (upgraded) {
           upgradedBackends.insert(backend->d_ds);
           backendIt = upgradeables.erase(backendIt);
@@ -522,10 +546,12 @@ void ServiceDiscovery::worker()
         }
       }
       catch (const std::exception& e) {
-        vinfolog("Exception in the Service Discovery thread: %s", e.what());
+        VERBOSESLOG(infolog("Exception in the Service Discovery thread: %s", e.what()),
+                    backendLogger->error(Logr::Info, e.what(), "Exception in the Service Discovery thread"));
       }
       catch (...) {
-        vinfolog("Exception in the Service Discovery thread");
+        VERBOSESLOG(infolog("Exception in the Service Discovery thread"),
+                    backendLogger->info(Logr::Info, "Exception in the Service Discovery thread"));
       }
 
       backend->d_nextCheck = now + backend->d_interval;
index ceb2d2cafe09c8ba0ae39006da4d6de3635a25c3..185c0456548e6c6ef61467ad9f79eb7e85c024b4 100644 (file)
 #include "lock.hh"
 
 struct DownstreamState;
+namespace Logr
+{
+class Logger;
+}
 
 namespace dnsdist
 {
@@ -66,8 +70,8 @@ private:
     bool keepAfterUpgrade;
   };
 
-  static bool getDiscoveredConfig(const UpgradeableBackend& backend, DiscoveredResolverConfig& config);
-  static bool tryToUpgradeBackend(const UpgradeableBackend& backend);
+  static bool getDiscoveredConfig(const Logr::Logger& logger, const UpgradeableBackend& backend, DiscoveredResolverConfig& config);
+  static bool tryToUpgradeBackend(const Logr::Logger& logger, const UpgradeableBackend& backend);
 
   static void worker();
 
index a7a776cba7fea0209d143c7a5fa5779bc3de01d7..ac1196fde4de5d9e0d9340a9c44285727d355de5 100644 (file)
@@ -30,7 +30,8 @@ bool handleDNSCryptQuery(PacketBuffer& packet, DNSCryptQuery& query, bool tcp, t
   query.parsePacket(packet, tcp, now);
 
   if (!query.isValid()) {
-    vinfolog("Dropping DNSCrypt invalid query");
+    VERBOSESLOG(infolog("Dropping DNSCrypt invalid query"),
+                dnsdist::logging::getTopLogger()->info(Logr::Info, "Dropping DNSCrypt invalid query"));
     return false;
   }
 
index 82b31f0959b43dbe361d560dbf8e8f7c215926bc..11d9079554a6d1df48ad3a5f23ee5389becd1091 100644 (file)
@@ -262,12 +262,14 @@ bool addOrRefreshBlock(ClientAddressDynamicRules& blocks, const timespec& now, c
         }
       }
       catch (const std::exception& e) {
-        vinfolog("Unable to insert eBPF dynamic block for %s, falling back to regular dynamic block: %s", requestor.toString(), e.what());
+        VERBOSESLOG(infolog("Unable to insert eBPF dynamic block for %s, falling back to regular dynamic block: %s", requestor.toString(), e.what()),
+                    dnsdist::logging::getTopLogger()->withName("dynamic-rules")->error(Logr::Info, e.what(), "Unable to insert eBPF dynamic block, falling back to regular dynamic block", "client.address", Logging::Loggable(requestor)));
       }
     }
 
     if (!beQuiet) {
-      warnlog("Inserting %s%sdynamic block for %s for %d seconds: %s", dblock.warning ? "(warning) " : "", bpf ? "eBPF " : "", requestor.toString(), dblock.until.tv_sec - now.tv_sec, dblock.reason);
+      SLOG(warnlog("Inserting %s%sdynamic block for %s for %d seconds: %s", dblock.warning ? "(warning) " : "", bpf ? "eBPF " : "", requestor.toString(), dblock.until.tv_sec - now.tv_sec, dblock.reason),
+           dnsdist::logging::getTopLogger()->withName("dynamic-rules")->info(Logr::Warning, "Inserting dynamic rule", "dynamic_rule.warning_rule", Logging::Loggable(dblock.warning), "client.address", Logging::Loggable(requestor), "dynamic_rule.use_bpf", Logging::Loggable(bpf), "dyanmic_rule.reason", Logging::Loggable(dblock.reason), "dynamic_rule.duration", Logging::Loggable(dblock.until.tv_sec - now.tv_sec)));
     }
   }
 
@@ -308,8 +310,10 @@ bool addOrRefreshBlockSMT(SuffixDynamicRules& blocks, const timespec& now, DynBl
   dblock.blocks = count;
 
   if (!beQuiet && (got == nullptr || expired)) {
-    warnlog("Inserting dynamic block for %s for %d seconds: %s", dblock.domain, dblock.until.tv_sec - now.tv_sec, dblock.reason);
+    SLOG(warnlog("Inserting dynamic block for %s for %d seconds: %s", dblock.domain, dblock.until.tv_sec - now.tv_sec, dblock.reason),
+         dnsdist::logging::getTopLogger()->withName("dynamic-rules")->info(Logr::Warning, "Inserting dynamic rule", "dynamic_rule.warning_rule", Logging::Loggable(false), "dns.query.name", Logging::Loggable(dblock.domain), "dynamic_rule.use_bpf", Logging::Loggable(false), "dyanmic_rule.reason", Logging::Loggable(dblock.reason), "dynamic_rule.duration", Logging::Loggable(dblock.until.tv_sec - now.tv_sec)));
   }
+
   auto domain = dblock.domain;
   blocks.add(domain, std::move(dblock));
   return true;
@@ -341,7 +345,8 @@ void DynBlockRulesGroup::addOrRefreshBlock(std::optional<ClientAddressDynamicRul
       d_newBlockHook(dnsdist_ffi_dynamic_block_type_nmt, requestor.toString().c_str(), rule.d_blockReason.c_str(), static_cast<uint8_t>(rule.d_action), rule.d_blockDuration, warning);
     }
     catch (const std::exception& exp) {
-      warnlog("Error calling the Lua hook after a dynamic block insertion: %s", exp.what());
+      SLOG(warnlog("Error calling the Lua hook after a dynamic block insertion: %s", exp.what()),
+           dnsdist::logging::getTopLogger()->withName("dynamic-rules")->error(Logr::Warning, exp.what(), "Error calling the Lua hook after a dynamic rule insertion"));
     }
   }
 }
@@ -365,7 +370,8 @@ void DynBlockRulesGroup::addOrRefreshBlockSMT(SuffixDynamicRules& blocks, const
       d_newBlockHook(dnsdist_ffi_dynamic_block_type_smt, name.toString().c_str(), rule.d_blockReason.c_str(), static_cast<uint8_t>(rule.d_action), rule.d_blockDuration, false);
     }
     catch (const std::exception& exp) {
-      warnlog("Error calling the Lua hook after a dynamic block insertion: %s", exp.what());
+      SLOG(warnlog("Error calling the Lua hook after a dynamic block insertion: %s", exp.what()),
+           dnsdist::logging::getTopLogger()->withName("dynamic-rules")->error(Logr::Warning, exp.what(), "Error calling the Lua hook after a suffix-based dynamic rule insertion"));
     }
   }
 }
@@ -504,13 +510,16 @@ void DynBlockMaintenance::purgeExpired(const struct timespec& now)
             bpfBlocked += g_defaultBPFFilter->getHits(network);
           }
           catch (const std::exception& e) {
-            vinfolog("Error while getting block count before removing eBPF dynamic block for %s: %s", entry.first.toString(), e.what());
+            VERBOSESLOG(infolog("Error while getting block count before removing eBPF dynamic block for %s: %s", entry.first.toString(), e.what()),
+                        dnsdist::logging::getTopLogger()->withName("dynamic-rules")->error(Logr::Info, e.what(), "Error while getting block count before removing eBPF dynamic block", "dynamic_rule.key", Logging::Loggable(entry.first)));
           }
+
           try {
             g_defaultBPFFilter->unblock(network);
           }
           catch (const std::exception& e) {
-            vinfolog("Error while removing eBPF dynamic block for %s: %s", entry.first.toString(), e.what());
+            VERBOSESLOG(infolog("Error while removing eBPF dynamic block for %s: %s", entry.first.toString(), e.what()),
+                        dnsdist::logging::getTopLogger()->withName("dynamic-rules")->error(Logr::Info, e.what(), "Error while removing eBPF dynamic block", "dynamic_rule.key", Logging::Loggable(entry.first)));
           }
         }
       }
@@ -817,10 +826,12 @@ void DynBlockMaintenance::run()
       }
     }
     catch (const std::exception& e) {
-      warnlog("Error in the dynamic block maintenance thread: %s", e.what());
+      SLOG(warnlog("Error in the dynamic block maintenance thread: %s", e.what()),
+           dnsdist::logging::getTopLogger()->withName("dynamic-rules")->error(Logr::Warning, e.what(), "Error in the dynamic block maintenance thread"));
     }
     catch (...) {
-      vinfolog("Unhandled error in the dynamic block maintenance thread");
+      VERBOSESLOG(infolog("Unhandled error in the dynamic block maintenance thread"),
+                  dnsdist::logging::getTopLogger()->withName("dynamic-rules")->info(Logr::Info, "Unhandled error in the dynamic block maintenance thread"));
     }
   }
 }
index 9db5de80242a8bac01aad5641f5806ab2ef19081..82f6c6a62b02110ae810d06560f5b27de9ff0718 100644 (file)
@@ -71,15 +71,28 @@ static void updateLatencyMetrics(DownstreamState& downstream, int elapsed /* mic
   }
 }
 
+
+static std::shared_ptr<Logr::Logger> getLoggerFromData(const std::shared_ptr<const HealthCheckData>& data)
+{
+  const auto& downstream = data->d_ds;
+  return dnsdist::logging::getTopLogger()->withName("backend-health-check")->withValues("health_check.proto", Logging::Loggable(downstream->doHealthcheckOverTCP() ? (data->d_tcpHandler->isTLS() ? "DoT" : "tcp") : "udp"), "backend.name", Logging::Loggable(downstream->getName()), "backend.address", Logging::Loggable(downstream->d_config.remote), "dns.query.id", Logging::Loggable(data->d_queryID), "dns.query.name", Logging::Loggable(data->d_checkName), "dns.query.type", Logging::Loggable(QType(data->d_checkType)), "dns.query.class", Logging::Loggable(data->d_checkClass));
+}
+
 static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
 {
-  const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
   const auto& downstream = data->d_ds;
+  std::shared_ptr<Logr::Logger> logger;
+  const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
+  if (verboseHealthChecks) {
+    logger = getLoggerFromData(data);
+  }
+
   try {
     if (data->d_buffer.size() < sizeof(dnsheader)) {
       ++data->d_ds->d_healthCheckMetrics.d_parseErrors;
       if (verboseHealthChecks) {
-        infolog("Invalid health check response of size %d from backend %s, expecting at least %d", data->d_buffer.size(), downstream->getNameWithAddr(), sizeof(dnsheader));
+        SLOG(infolog("Invalid health check response of size %d from backend %s, expecting at least %d", data->d_buffer.size(), downstream->getNameWithAddr(), sizeof(dnsheader)),
+             logger->info(Logr::Info, "Invalid health check response", "dns.response.size", Logging::Loggable(data->d_buffer.size())));
       }
       return false;
     }
@@ -88,7 +101,8 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
     if (responseHeader.get()->id != data->d_queryID) {
       ++data->d_ds->d_healthCheckMetrics.d_mismatchErrors;
       if (verboseHealthChecks) {
-        infolog("Invalid health check response id %d from backend %s, expecting %d", responseHeader.get()->id, downstream->getNameWithAddr(), data->d_queryID);
+        SLOG(infolog("Invalid health check response id %d from backend %s, expecting %d", responseHeader.get()->id, downstream->getNameWithAddr(), data->d_queryID),
+             logger->info(Logr::Info, "Invalid health check response id", "dns.response.id", Logging::Loggable(responseHeader.get()->id)));
       }
       return false;
     }
@@ -96,7 +110,8 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
     if (!responseHeader.get()->qr) {
       ++data->d_ds->d_healthCheckMetrics.d_invalidResponseErrors;
       if (verboseHealthChecks) {
-        infolog("Invalid health check response from backend %s, expecting QR to be set", downstream->getNameWithAddr());
+        SLOG(infolog("Invalid health check response from backend %s, expecting QR to be set", downstream->getNameWithAddr()),
+             logger->info(Logr::Info, "Invalid health check response, expecting the QR bit to be set"));
       }
       return false;
     }
@@ -104,7 +119,8 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
     if (responseHeader.get()->rcode == RCode::ServFail) {
       ++data->d_ds->d_healthCheckMetrics.d_invalidResponseErrors;
       if (verboseHealthChecks) {
-        infolog("Backend %s responded to health check with ServFail", downstream->getNameWithAddr());
+        SLOG(infolog("Backend %s responded to health check with ServFail", downstream->getNameWithAddr()),
+             logger->info(Logr::Info, "Backend responded to health check with ServFail", "dns.response.rcode", Logging::Loggable(RCode::to_s(responseHeader.get()->rcode))));
       }
       return false;
     }
@@ -112,7 +128,8 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
     if (downstream->d_config.mustResolve && (responseHeader.get()->rcode == RCode::NXDomain || responseHeader.get()->rcode == RCode::Refused)) {
       ++data->d_ds->d_healthCheckMetrics.d_invalidResponseErrors;
       if (verboseHealthChecks) {
-        infolog("Backend %s responded to health check with %s while mustResolve is set", downstream->getNameWithAddr(), responseHeader.get()->rcode == RCode::NXDomain ? "NXDomain" : "Refused");
+        SLOG(infolog("Backend %s responded to health check with %s while mustResolve is set", downstream->getNameWithAddr(), responseHeader.get()->rcode == RCode::NXDomain ? "NXDomain" : "Refused"),
+             logger->info(Logr::Info, "Backend responded to health check with an invalid code while mustResolve is set", "dns.response.rcode", Logging::Loggable(RCode::to_s(responseHeader.get()->rcode))));
       }
       return false;
     }
@@ -125,7 +142,8 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
     if (receivedName != data->d_checkName || receivedType != data->d_checkType || receivedClass != data->d_checkClass) {
       ++data->d_ds->d_healthCheckMetrics.d_mismatchErrors;
       if (verboseHealthChecks) {
-        infolog("Backend %s responded to health check with an invalid qname (%s vs %s), qtype (%s vs %s) or qclass (%d vs %d)", downstream->getNameWithAddr(), receivedName.toLogString(), data->d_checkName.toLogString(), QType(receivedType).toString(), QType(data->d_checkType).toString(), receivedClass, data->d_checkClass);
+        SLOG(infolog("Backend %s responded to health check with an invalid qname (%s vs %s), qtype (%s vs %s) or qclass (%d vs %d)", downstream->getNameWithAddr(), receivedName.toLogString(), data->d_checkName.toLogString(), QType(receivedType).toString(), QType(data->d_checkType).toString(), receivedClass, data->d_checkClass),
+             logger->info(Logr::Info, "Backend responded to health check with an invalid qname, qtype or qclass", "dns.response.name", Logging::Loggable(receivedName), "dns.response.qtype", Logging::Loggable(QType(receivedType)), "dns.response.class", Logging::Loggable(QClass(receivedClass))));
       }
       return false;
     }
@@ -133,13 +151,15 @@ static bool handleResponse(std::shared_ptr<HealthCheckData>& data)
   catch (const std::exception& e) {
     ++data->d_ds->d_healthCheckMetrics.d_parseErrors;
     if (verboseHealthChecks) {
-      infolog("Error checking the health of backend %s: %s", downstream->getNameWithAddr(), e.what());
+      SLOG(infolog("Error checking the health of backend %s: %s", downstream->getNameWithAddr(), e.what()),
+           logger->error(Logr::Info, e.what(), "Error checking the health of backend"));
     }
     return false;
   }
   catch (...) {
     if (verboseHealthChecks) {
-      infolog("Unknown exception while checking the health of backend %s", downstream->getNameWithAddr());
+      SLOG(infolog("Unknown exception while checking the health of backend %s", downstream->getNameWithAddr()),
+           logger->info(Logr::Info, "Unknown exception while checking the health of backend"));
     }
     return false;
   }
@@ -197,7 +217,11 @@ private:
 static void healthCheckUDPCallback(int descriptor, FDMultiplexer::funcparam_t& param)
 {
   auto data = boost::any_cast<std::shared_ptr<HealthCheckData>>(param);
+  std::shared_ptr<Logr::Logger> logger;
   const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
+  if (verboseHealthChecks) {
+    logger = getLoggerFromData(data);
+  }
 
   ssize_t got = 0;
   ComboAddress from;
@@ -220,7 +244,8 @@ static void healthCheckUDPCallback(int descriptor, FDMultiplexer::funcparam_t& p
       }
 
       if (verboseHealthChecks) {
-        infolog("Error receiving health check response from %s: %s", data->d_ds->d_config.remote.toStringWithPort(), stringerror(savederrno));
+        SLOG(infolog("Error receiving health check response from %s: %s", data->d_ds->d_config.remote.toStringWithPort(), stringerror(savederrno)),
+             logger->error(Logr::Info, savederrno, "Error receiving health check response"));
       }
       ++data->d_ds->d_healthCheckMetrics.d_networkErrors;
       data->d_ds->submitHealthCheckResult(data->d_initial, false);
@@ -234,7 +259,8 @@ static void healthCheckUDPCallback(int descriptor, FDMultiplexer::funcparam_t& p
   /* we are using a connected socket but hey.. */
   if (from != data->d_ds->d_config.remote) {
     if (verboseHealthChecks) {
-      infolog("Invalid health check response received from %s, expecting one from %s", from.toStringWithPort(), data->d_ds->d_config.remote.toStringWithPort());
+      SLOG(infolog("Invalid health check response received from %s, expecting one from %s", from.toStringWithPort(), data->d_ds->d_config.remote.toStringWithPort()),
+           logger->info(Logr::Info, "Invalid health check response received from the wrong address", "network.peer.address", Logging::Loggable(from)));
     }
     ++data->d_ds->d_healthCheckMetrics.d_networkErrors;
     data->d_ds->submitHealthCheckResult(data->d_initial, false);
@@ -249,6 +275,11 @@ static void healthCheckTCPCallback(int descriptor, FDMultiplexer::funcparam_t& p
 {
   (void)descriptor;
   auto data = boost::any_cast<std::shared_ptr<HealthCheckData>>(param);
+  std::shared_ptr<Logr::Logger> logger;
+  const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
+  if (verboseHealthChecks) {
+    logger = getLoggerFromData(data);
+  }
 
   IOStateGuard ioGuard(data->d_ioState);
   try {
@@ -292,7 +323,8 @@ static void healthCheckTCPCallback(int descriptor, FDMultiplexer::funcparam_t& p
           }
         }
         catch (const std::exception& e) {
-          vinfolog("Unable to get a TLS session from the DoT healthcheck: %s", e.what());
+          VERBOSESLOG(infolog("Unable to get a TLS session from the DoT healthcheck: %s", e.what()),
+                      logger->error(Logr::Info, e.what(), "Unable to get a TLS session from the DoT healthcheck"));
         }
       }
     }
@@ -306,16 +338,16 @@ static void healthCheckTCPCallback(int descriptor, FDMultiplexer::funcparam_t& p
   catch (const std::exception& e) {
     ++data->d_ds->d_healthCheckMetrics.d_networkErrors;
     data->d_ds->submitHealthCheckResult(data->d_initial, false);
-    const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
     if (verboseHealthChecks) {
-      infolog("Error checking the health of backend %s: %s", data->d_ds->getNameWithAddr(), e.what());
+      SLOG(infolog("Error checking the health of backend %s: %s", data->d_ds->getNameWithAddr(), e.what()),
+           logger->error(Logr::Info, e.what(), "Error checking the health of backend"));
     }
   }
   catch (...) {
     data->d_ds->submitHealthCheckResult(data->d_initial, false);
-    const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
     if (verboseHealthChecks) {
-      infolog("Unknown exception while checking the health of backend %s", data->d_ds->getNameWithAddr());
+      SLOG(infolog("Unknown exception while checking the health of backend %s", data->d_ds->getNameWithAddr()),
+           logger->info(Logr::Info, "Unknown exception while checking the health of backend"));
     }
   }
 }
@@ -323,6 +355,11 @@ static void healthCheckTCPCallback(int descriptor, FDMultiplexer::funcparam_t& p
 bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared_ptr<DownstreamState>& downstream, bool initialCheck)
 {
   const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
+  std::shared_ptr<Logr::Logger> logger;
+  if (verboseHealthChecks) {
+    logger = dnsdist::logging::getTopLogger()->withName("backend-health-check")->withValues("backend.name", Logging::Loggable(downstream->getName()), "backend.address", Logging::Loggable(downstream->d_config.remote));
+  }
+
   try {
     uint16_t queryID = dnsdist::getRandomDNSID();
     DNSName checkName = downstream->d_config.checkName;
@@ -372,7 +409,9 @@ bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared
     if (!downstream->d_config.sourceItfName.empty()) {
       int res = setsockopt(sock.getHandle(), SOL_SOCKET, SO_BINDTODEVICE, downstream->d_config.sourceItfName.c_str(), downstream->d_config.sourceItfName.length());
       if (res != 0 && verboseHealthChecks) {
-        infolog("Error setting SO_BINDTODEVICE on the health check socket for backend '%s': %s", downstream->getNameWithAddr(), stringerror());
+        int savederror = errno;
+        SLOG(infolog("Error setting SO_BINDTODEVICE on the health check socket for backend '%s': %s", downstream->getNameWithAddr(), stringerror(savederror)),
+             logger->error(Logr::Info, savederror, "Error setting SO_BINDTODEVICE on the health check socket for backend"));
       }
     }
 #endif
@@ -405,7 +444,8 @@ bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared
       if (sent < 0) {
         int ret = errno;
         if (verboseHealthChecks) {
-          infolog("Error while sending a health check query (ID %d) to backend %s: %d", queryID, downstream->getNameWithAddr(), ret);
+          SLOG(infolog("Error while sending a health check query (ID %d) to backend %s: %d", queryID, downstream->getNameWithAddr(), ret),
+               logger->error(Logr::Info, ret, "Error while sending a health check query to backend", "dns.query.id", Logging::Loggable(queryID)));
         }
         return false;
       }
@@ -434,7 +474,8 @@ bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared
           }
         }
         catch (const std::exception& e) {
-          vinfolog("Unable to restore a TLS session for the DoT healthcheck for backend %s: %s", downstream->getNameWithAddr(), e.what());
+          VERBOSESLOG(infolog("Unable to restore a TLS session for the DoT healthcheck for backend %s: %s", downstream->getNameWithAddr(), e.what()),
+                      logger->error(Logr::Info, e.what(), "Unable to restore a TLS session for the DoT healthcheck"));
         }
       }
       data->d_tcpHandler->tryConnect(downstream->d_config.tcpFastOpen, downstream->d_config.remote);
@@ -458,13 +499,15 @@ bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared
   }
   catch (const std::exception& e) {
     if (verboseHealthChecks) {
-      infolog("Error checking the health of backend %s: %s", downstream->getNameWithAddr(), e.what());
+      SLOG(infolog("Error checking the health of backend %s: %s", downstream->getNameWithAddr(), e.what()),
+           logger->error(Logr::Info, e.what(), "Error checking the health of backend"));
     }
     return false;
   }
   catch (...) {
     if (verboseHealthChecks) {
-      infolog("Unknown exception while checking the health of backend %s", downstream->getNameWithAddr());
+      SLOG(infolog("Unknown exception while checking the health of backend %s", downstream->getNameWithAddr()),
+           logger->info(Logr::Info, "Unknown exception while checking the health of backend"));
     }
     return false;
   }
@@ -473,12 +516,18 @@ bool queueHealthCheck(std::unique_ptr<FDMultiplexer>& mplexer, const std::shared
 void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
 {
   const auto verboseHealthChecks = dnsdist::configuration::getCurrentRuntimeConfiguration().d_verboseHealthChecks;
+  std::shared_ptr<Logr::Logger> logger;
+  if (verboseHealthChecks) {
+    logger = dnsdist::logging::getTopLogger()->withName("backend-health-check");
+  }
+
   while (mplexer.getWatchedFDCount(false) > 0 || mplexer.getWatchedFDCount(true) > 0) {
     struct timeval now{};
     int ret = mplexer.run(&now, 100);
     if (ret == -1) {
       if (verboseHealthChecks) {
-        infolog("Error while waiting for the health check response from backends: %d", ret);
+        SLOG(infolog("Error while waiting for the health check response from backends: %d", ret),
+             logger->error(Logr::Info, ret, "Error while waiting for the health check response from backends"));
       }
       break;
     }
@@ -498,6 +547,11 @@ void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
       }
 
       auto data = boost::any_cast<std::shared_ptr<HealthCheckData>>(timeout.second);
+      std::shared_ptr<Logr::Logger> queryLogger;
+      if (verboseHealthChecks) {
+        queryLogger = getLoggerFromData(data);
+      }
+
       try {
         /* UDP does not have an IO state, H2 is handled separately */
         if (data->d_ioState) {
@@ -506,8 +560,10 @@ void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
         else {
           mplexer.removeReadFD(timeout.first);
         }
+
         if (verboseHealthChecks) {
-          infolog("Timeout while waiting for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
+          SLOG(infolog("Timeout while waiting for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr()),
+               queryLogger->info(Logr::Info, "Timeout while waiting for the health check response from backend"));
         }
 
         ++data->d_ds->d_healthCheckMetrics.d_timeOuts;
@@ -518,13 +574,15 @@ void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
            there for us to reach that code, and the submission code should not throw,
            but let's provide a nice error message if it ever does. */
         if (verboseHealthChecks) {
-          infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s: %s", data->d_queryID, data->d_ds->getNameWithAddr(), e.what());
+          SLOG(infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s: %s", data->d_queryID, data->d_ds->getNameWithAddr(), e.what()),
+               queryLogger->error(Logr::Info, e.what(), "Error while dealing with a timeout for the health check response from backend"));
         }
       }
       catch (...) {
         /* this is even less likely to happen */
         if (verboseHealthChecks) {
-          infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
+          SLOG(infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr()),
+               queryLogger->info(Logr::Info, "Error while dealing with a timeout for the health check response from backend"));
         }
       }
     }
@@ -535,11 +593,16 @@ void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
         continue;
       }
       auto data = boost::any_cast<std::shared_ptr<HealthCheckData>>(timeout.second);
+      std::shared_ptr<Logr::Logger> queryLogger;
+      if (verboseHealthChecks) {
+        queryLogger = getLoggerFromData(data);
+      }
       try {
         /* UDP does not block while writing, H2 is handled separately */
         data->d_ioState.reset();
         if (verboseHealthChecks) {
-          infolog("Timeout while waiting for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
+          SLOG(infolog("Timeout while waiting for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr()),
+               queryLogger->info(Logr::Info, "Timeout while waiting for the health check response from backend"));
         }
 
         ++data->d_ds->d_healthCheckMetrics.d_timeOuts;
@@ -549,13 +612,15 @@ void handleQueuedHealthChecks(FDMultiplexer& mplexer, bool initial)
         /* this is not supposed to happen as the submission code should not throw,
            but let's provide a nice error message if it ever does. */
         if (verboseHealthChecks) {
-          infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s: %s", data->d_queryID, data->d_ds->getNameWithAddr(), e.what());
+          SLOG(infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s: %s", data->d_queryID, data->d_ds->getNameWithAddr(), e.what()),
+               queryLogger->error(Logr::Info, e.what(), "Error while dealing with a timeout for the health check response for backend"));
         }
       }
       catch (...) {
         /* this is even less likely to happen */
         if (verboseHealthChecks) {
-          infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr());
+          SLOG(infolog("Error while dealing with a timeout for the health check response (ID %d) from backend %s", data->d_queryID, data->d_ds->getNameWithAddr()),
+               queryLogger->info(Logr::Info, "Error while dealing with a timeout for the health check response from backend"));
         }
       }
     }