Coverage Report

Created: 2026-08-13 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pdns/pdns/dnsdistdist/dolog.hh
Line
Count
Source
1
/*
2
 * This file is part of PowerDNS or dnsdist.
3
 * Copyright -- PowerDNS.COM B.V. and its contributors
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of version 2 of the GNU General Public License as
7
 * published by the Free Software Foundation.
8
 *
9
 * In addition, for the avoidance of any doubt, permission is granted to
10
 * link this program with OpenSSL and to (re)distribute the binaries
11
 * produced as the result of such linking.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
 */
22
#pragma once
23
#include <array>
24
#include <fstream>
25
#include <iomanip>
26
#include <iostream>
27
#include <optional>
28
#include <sstream>
29
#include "config.h"
30
#if !defined(RECURSOR)
31
#include <syslog.h>
32
#else
33
#include "logger.hh"
34
#endif // RECURSOR
35
36
#if defined(DNSDIST)
37
#include "dnsdist-logging.hh"
38
#endif /* defined(DNSDIST) */
39
40
/* This file is intended not to be metronome specific, and is simple example of C++2011
41
   variadic templates in action.
42
43
   The goal is rapid easy to use logging to console & syslog.
44
45
   Usage:
46
          string address="localhost";
47
          vinfolog("Got TCP connection from %s", remote);
48
          infolog("Bound to %s port %d", address, port);
49
          warnlog("Query took %d milliseconds", 1232.4); // yes, %d
50
          errlog("Unable to bind to %s: %s", ca.toStringWithPort(), strerr(errno));
51
52
   Will log to stdout. Will syslog in any case with LOG_INFO,
53
   LOG_WARNING, LOG_ERR respectively. If verbose=false, vinfolog is a noop.
54
   More generically, dolog(someiostream, "Hello %s", stream) will log to someiostream
55
56
   This will happily print a string to %d! Doesn't do further format processing.
57
*/
58
template <typename O>
59
inline void dolog(O& outputStream, const char* str)
60
{
61
  outputStream << str;
62
}
63
64
template <typename O, typename T, typename... Args>
65
void dolog(O& outputStream, const char* formatStr, T value, const Args&... args)
66
{
67
  while (*formatStr) {
68
    if (*formatStr == '%') {
69
      // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
70
      if (*(formatStr + 1) == '%') {
71
        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
72
        ++formatStr;
73
      }
74
      else {
75
        outputStream << value;
76
        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
77
        formatStr += 2;
78
        dolog(outputStream, formatStr, args...);
79
        return;
80
      }
81
    }
82
    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
83
    outputStream << *formatStr++;
84
  }
85
}
86
87
#if !defined(RECURSOR)
88
#ifdef DNSDIST
89
namespace dnsdist::logging
90
{
91
class LoggingConfiguration
92
{
93
public:
94
  static void setSyslog(bool value = true)
95
0
  {
96
0
    s_syslog = value;
97
0
  }
98
  static void setLogTimestamps(bool value = true)
99
0
  {
100
0
    s_logTimestamps = value;
101
0
  }
102
  static void setVerboseStream(std::ofstream&& stream)
103
0
  {
104
0
    s_verboseStream = std::move(stream);
105
0
  }
106
  static bool getSyslog()
107
0
  {
108
0
    return s_syslog;
109
0
  }
110
  static bool getLogTimestamps()
111
0
  {
112
0
    return s_logTimestamps;
113
0
  }
114
  static std::optional<std::ofstream>& getVerboseStream()
115
0
  {
116
0
    return s_verboseStream;
117
0
  }
118
119
private:
120
  static std::optional<std::ofstream> s_verboseStream;
121
  static bool s_logTimestamps;
122
  static bool s_syslog;
123
};
124
125
extern void logTime(std::ostream& stream);
126
}
127
#endif
128
129
inline void setSyslogFacility(int facility)
130
0
{
131
0
  /* we always call openlog() right away at startup */
132
0
  closelog();
133
0
  openlog("dnsdist", LOG_PID | LOG_NDELAY, facility);
134
0
}
135
136
namespace
137
{
138
inline const char* syslogLevelToStr(int level)
139
0
{
140
0
  static constexpr std::array levelStrs{
141
0
    "Emergency",
142
0
    "Alert",
143
0
    "Critical",
144
0
    "Error",
145
0
    "Warning",
146
0
    "Notice",
147
0
    "Info",
148
0
    "Debug"};
149
0
  return levelStrs.at(level);
150
0
}
Unexecuted instantiation: dnsdist-cache.cc:(anonymous namespace)::syslogLevelToStr(int)
Unexecuted instantiation: dnsdist-ecs.cc:(anonymous namespace)::syslogLevelToStr(int)
Unexecuted instantiation: dnsdist-dnsquestion.cc:(anonymous namespace)::syslogLevelToStr(int)
Unexecuted instantiation: dnsdist-idstate.cc:(anonymous namespace)::syslogLevelToStr(int)
151
}
152
153
template <typename... Args>
154
void genlog(std::ostream& stream, [[maybe_unused]] int level, [[maybe_unused]] bool skipSyslog, const char* formatStr, const Args&... args)
155
{
156
  std::ostringstream str;
157
  dolog(str, formatStr, args...);
158
159
  auto output = str.str();
160
161
#ifdef DNSDIST
162
  if (!skipSyslog && dnsdist::logging::LoggingConfiguration::getSyslog()) {
163
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg): syslog is what it is
164
    syslog(level, "%s", output.c_str());
165
  }
166
167
  if (dnsdist::logging::LoggingConfiguration::getLogTimestamps()) {
168
    dnsdist::logging::logTime(stream);
169
  }
170
171
#endif
172
  stream << output << std::endl;
173
}
174
175
template <typename... Args>
176
void verboselog(const char* formatStr, const Args&... args)
177
{
178
#ifdef DNSDIST
179
  if (auto& stream = dnsdist::logging::LoggingConfiguration::getVerboseStream()) {
180
    genlog(*stream, LOG_DEBUG, true, formatStr, args...);
181
  }
182
  else {
183
#endif /* DNSDIST */
184
    genlog(std::cout, LOG_DEBUG, false, formatStr, args...);
185
#ifdef DNSDIST
186
  }
187
#endif /* DNSDIST */
188
}
189
190
#ifdef DNSDIST
191
#include "dnsdist-configuration.hh"
192
193
#define vinfolog                                                          \
194
  if (dnsdist::configuration::getCurrentRuntimeConfiguration().d_verbose) \
195
  verboselog
196
#else
197
#define vinfolog \
198
  infolog
199
#endif
200
201
template <typename... Args>
202
void infolog(const char* formatStr, const Args&... args)
203
{
204
  genlog(std::cout, LOG_INFO, false, formatStr, args...);
205
}
206
207
template <typename... Args>
208
void warnlog(const char* formatStr, const Args&... args)
209
{
210
  genlog(std::cout, LOG_WARNING, false, formatStr, args...);
211
}
212
213
template <typename... Args>
214
void errlog(const char* formatStr, const Args&... args)
215
{
216
  genlog(std::cout, LOG_ERR, false, formatStr, args...);
217
}
218
219
#else // RECURSOR
220
#define vinfolog \
221
  if (false)     \
222
  infolog
223
224
template <typename... Args>
225
void infolog(const char* formatStr, const Args&... args)
226
{
227
  g_log << Logger::Info;
228
  dolog(g_log, formatStr, args...);
229
}
230
231
template <typename... Args>
232
void warnlog(const char* formatStr, const Args&... args)
233
{
234
  g_log << Logger::Warning;
235
  dolog(g_log, formatStr, args...);
236
}
237
238
template <typename... Args>
239
void errlog(const char* formatStr, const Args&... args)
240
{
241
  g_log << Logger::Error;
242
  dolog(g_log, formatStr, args...);
243
}
244
245
#endif