• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PowerDNS / pdns / 18834649492

27 Oct 2025 08:32AM UTC coverage: 73.012% (+4.2%) from 68.781%
18834649492

Pull #16368

github

web-flow
Merge a290d76a2 into 82ea647b4
Pull Request #16368: ci(dnsdist): Build and test on arm64/aarch64

38267 of 63120 branches covered (60.63%)

Branch coverage included in aggregate %.

127456 of 163860 relevant lines covered (77.78%)

5005850.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

56.8
/pdns/recursordist/rec-eventtrace.hh
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

24
#include "misc.hh"
25
#include "noinitvector.hh"
26

27
#include <optional>
28
#include <unordered_map>
29
#include <variant>
30
#include "protozero-trace.hh"
31

32
class RecEventTrace
33
{
34
public:
35
  enum EventType : uint8_t
36
  {
37
    // Keep in-syc with dnsmessagge.proto!
38
    // Don't forget to add a new entry to the table in the .cc file!
39
    // Generic events
40
    CustomEvent = 0,
41
    ReqRecv = 1,
42
    PCacheCheck = 2,
43
    AnswerSent = 3,
44

45
    // Recursor specific events
46
    SyncRes = 100,
47
    LuaGetTag = 101,
48
    LuaGetTagFFI = 102,
49
    LuaIPFilter = 103,
50
    LuaPreRPZ = 104,
51
    LuaPreResolve = 105,
52
    LuaPreOutQuery = 106,
53
    LuaPostResolve = 107,
54
    LuaNoData = 108,
55
    LuaNXDomain = 109,
56
    LuaPostResolveFFI = 110,
57

58
    AuthRequest = 120,
59
    PacketParse = 121,
60
    ProcessUDP = 122,
61
    ProcessTCP = 123,
62
  };
63

64
  static const std::unordered_map<EventType, std::string> s_eventNames;
65

66
  RecEventTrace()
67
  {
9,160✔
68
    reset();
9,160✔
69
  }
9,160✔
70

71
  RecEventTrace(const RecEventTrace& old) :
72
    d_events(old.d_events),
73
    d_base(old.d_base),
74
    d_status(old.d_status)
75
  {
7,224✔
76
    // An RecEventTrace object can be copied, but the original will be marked invalid.
77
    // This is do detect (very likely) unintended modifications to the original after
78
    // the ownership changed.
79
    old.d_status = Invalid;
7,224✔
80
  }
7,224✔
81

82
  RecEventTrace(RecEventTrace&& old) noexcept :
83
    d_events(std::move(old.d_events)),
84
    d_base(old.d_base),
85
    d_status(old.d_status)
86
  {
3,612✔
87
    // An RecEventTrace object can be moved, but the original will be marked invalid.
88
    // This is do detect (very likely) unintended modifications to the original after
89
    // the ownership changed.
90
    old.d_status = Invalid;
3,612✔
91
  }
3,612✔
92

93
  RecEventTrace& operator=(const RecEventTrace& old) = delete;
94
  RecEventTrace& operator=(RecEventTrace&& old) noexcept
95
  {
5,554✔
96
    d_events = std::move(old.d_events);
5,554✔
97
    d_base = old.d_base;
5,554✔
98
    d_status = old.d_status;
5,554✔
99
    old.d_status = Invalid;
5,554✔
100
    return *this;
5,554✔
101
  }
5,554✔
102

103
  ~RecEventTrace() = default;
19,977✔
104

105
  // We distinguish between strings and byte arrays. Does not matter in C++, but in Go, Java etc it does
106
  using Value_t = std::variant<std::nullopt_t, bool, int64_t, std::string, PacketBuffer>;
107

108
  static std::string toString(const EventType eventType)
109
  {
17✔
110
    return s_eventNames.at(eventType);
17✔
111
  }
17✔
112

113
  static std::string toString(const Value_t& value)
114
  {
×
115
    if (std::holds_alternative<std::nullopt_t>(value)) {
×
116
      return "";
×
117
    }
×
118
    if (std::holds_alternative<bool>(value)) {
×
119
      return std::to_string(std::get<bool>(value));
×
120
    }
×
121
    if (std::holds_alternative<int64_t>(value)) {
×
122
      return std::to_string(std::get<int64_t>(value));
×
123
    }
×
124
    if (std::holds_alternative<std::string>(value)) {
×
125
      return std::get<std::string>(value);
×
126
    }
×
127
    if (std::holds_alternative<PacketBuffer>(value)) {
×
128
      const auto& packet = std::get<PacketBuffer>(value);
×
129
      return makeHexDump(std::string(reinterpret_cast<const char*>(packet.data()), packet.size())); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
×
130
    }
×
131
    return "?";
×
132
  }
×
133

134
  struct Entry
135
  {
136
    Entry(Value_t&& value, EventType eventType, bool start, int64_t timestamp, size_t parent, size_t match) :
137
      d_value(std::move(value)), d_ts(timestamp), d_parent(parent), d_matching(match), d_event(eventType), d_start(start)
138
    {
34✔
139
    }
34✔
140
    Entry(Value_t&& value, std::string custom, bool start, int64_t timestamp, size_t parent, size_t match) :
141
      d_value(std::move(value)), d_custom(std::move(custom)), d_ts(timestamp), d_parent(parent), d_matching(match), d_event(CustomEvent), d_start(start)
142
    {
×
143
    }
×
144
    Value_t d_value;
145
    std::vector<std::pair<string, Value_t>> d_extraValues;
146
    std::string d_custom;
147
    std::string d_valueName{"arg"};
148
    int64_t d_ts;
149
    size_t d_parent;
150
    size_t d_matching;
151
    EventType d_event;
152
    bool d_start;
153

154
    [[nodiscard]] std::string toString() const
155
    {
×
156
      std::string value = RecEventTrace::toString(d_value);
×
157
      if (!value.empty()) {
×
158
        value = "," + value;
×
159
      }
×
160
      std::string name = RecEventTrace::toString(d_event);
×
161
      if (d_event == EventType::CustomEvent) {
×
162
        name += ":" + d_custom;
×
163
      }
×
164

165
      return name + "(" + std::to_string(d_ts) + value + (d_start ? ")" : ",done)");
×
166
    }
×
167
  };
168

169
  void setEnabled(bool flag)
170
  {
6,255✔
171
    assert(d_status != Invalid);
6,255✔
172
    d_status = flag ? Enabled : Disabled;
6,255✔
173
  }
6,255✔
174

175
  bool enabled() const
176
  {
37,867✔
177
    return d_status == Enabled;
37,867✔
178
  }
37,867✔
179

180
  template <class E>
181
  size_t add(E event, Value_t&& value, bool start, size_t match, int64_t stamp = 0)
182
  {
76,275✔
183
    assert(d_status != Invalid);
76,275✔
184
    if (d_status == Disabled) {
76,283✔
185
      return 0;
76,242✔
186
    }
76,242✔
187

188
    if (stamp == 0) {
2,147,483,681✔
189
      struct timespec theTime{};
34✔
190
      clock_gettime(CLOCK_MONOTONIC, &theTime);
34✔
191
      stamp = theTime.tv_nsec + theTime.tv_sec * 1000000000;
34✔
192
    }
34✔
193
    if (stamp < d_base) {
2,147,483,681!
194
      // If we get a ts before d_base, we adjust d_base and the existing events
195
      // This is possble if we add a kernel provided packet timestamp in the future
196
      // (Though it seems those timestamps do not use CLOCK_MONOTONIC...)
197
      const int64_t adj = d_base - stamp;
×
198
      for (auto& iter : d_events) {
×
199
        iter.d_ts += adj;
×
200
      }
×
201
      // and move to the new base
202
      d_base = stamp;
×
203
    }
×
204
    stamp -= d_base;
2,147,483,681✔
205
    d_events.emplace_back(std::move(value), event, start, stamp, d_parent, match);
2,147,483,681✔
206
    return d_events.size() - 1;
2,147,483,681✔
207
  }
76,275✔
208

209
  template <class E>
210
  size_t add(E eventType)
211
  {
29,872✔
212
    return add(eventType, Value_t(std::nullopt), true, 0, 0);
29,872✔
213
  }
29,872✔
214

215
  // We store uint32 in an int64_t
216
  template <class E>
217
  size_t add(E eventType, uint32_t value, bool start, size_t match)
218
  {
119✔
219
    return add(eventType, static_cast<int64_t>(value), start, match, 0);
119✔
220
  }
119✔
221
  // We store int32 in an int64_t
222
  template <class E>
223
  size_t add(E eventType, int32_t value, bool start, size_t match)
224
  {
11,671✔
225
    return add(eventType, static_cast<int64_t>(value), start, match, 0);
11,671✔
226
  }
11,671✔
227

228
  template <class E, class T>
229
  size_t add(E eventType, T value, bool start, size_t match)
230
  {
34,614✔
231
    return add(eventType, Value_t(value), start, match, 0);
34,614✔
232
  }
34,614✔
233

234
  void setValueName(size_t index, const std::string& name)
235
  {
13,804✔
236
    assert(d_status != Invalid);
13,804✔
237
    if (d_status == Disabled) {
13,804!
238
      return;
13,804✔
239
    }
13,804✔
240
    d_events.at(index).d_valueName = name;
×
241
  }
×
242

243
  void addExtraValues(size_t index, std::vector<std::pair<std::string, Value_t>>&& values)
244
  {
13,804✔
245
    assert(d_status != Invalid);
13,804✔
246
    if (d_status == Disabled) {
13,804✔
247
      return;
13,802✔
248
    }
13,802✔
249
    d_events.at(index).d_extraValues = std::move(values);
2✔
250
  }
2✔
251

252
  void clear()
253
  {
5,403✔
254
    d_events.clear();
5,403✔
255
    reset();
5,403✔
256
  }
5,403✔
257

258
  void reset()
259
  {
14,563✔
260
    struct timespec theTime{};
14,563✔
261
    clock_gettime(CLOCK_MONOTONIC, &theTime);
14,563✔
262
    d_base = theTime.tv_nsec + theTime.tv_sec * 1000000000;
14,563✔
263
    d_status = Disabled;
14,563✔
264
  }
14,563✔
265

266
  std::string toString() const
267
  {
×
268
    assert(d_status != Invalid);
×
269
    if (d_status == Disabled) {
×
270
      return "Disabled\n";
×
271
    }
×
272
    std::string ret = "eventTrace [";
×
273
    bool first = true;
×
274
    for (const auto& event : d_events) {
×
275
      if (first) {
×
276
        first = false;
×
277
      }
×
278
      else {
×
279
        ret += "; ";
×
280
      }
×
281
      ret += event.toString();
×
282
    }
×
283
    ret += ']';
×
284
    return ret;
×
285
  }
×
286

287
  const std::vector<Entry>& getEvents() const
288
  {
×
289
    return d_events;
×
290
  }
×
291

292
  std::vector<pdns::trace::Span> convertToOT(const pdns::trace::InitialSpanInfo& span) const;
293

294
  size_t setParent(size_t parent)
295
  {
10,656✔
296
    size_t old = d_parent;
10,656✔
297
    d_parent = parent;
10,656✔
298
    return old;
10,656✔
299
  }
10,656✔
300

301
  // The EventScope class is used to close (add an end event) automatically upon the scope object
302
  // going out of scope. It is also possible to manually close it, specifying a value to be registered
303
  // at the close event. In that case the dt call will become a no-op.
304
  class EventScope
305
  {
306
  public:
307
    EventScope(size_t oldParent, RecEventTrace& eventTrace) :
308
      d_eventTrace(eventTrace),
309
      d_oldParent(oldParent)
310
    {
10,646✔
311
      if (d_eventTrace.enabled() && !d_eventTrace.d_events.empty()) {
10,646!
312
        d_event = d_eventTrace.d_events.back().d_event;
5✔
313
        d_match = d_eventTrace.d_events.size() - 1;
5✔
314
      }
5✔
315
    }
10,646✔
316

317
    // Only int64_t for now needed, might become a template in the future.
318
    void close(int64_t val)
319
    {
21,028✔
320
      if (!d_eventTrace.enabled() || d_closed) {
21,035✔
321
        return;
21,024✔
322
      }
21,024✔
323
      d_eventTrace.setParent(d_oldParent);
2,147,483,652✔
324
      d_eventTrace.add(d_event, val, false, d_match);
2,147,483,652✔
325
      d_closed = true;
2,147,483,652✔
326
    }
2,147,483,652✔
327

328
    ~EventScope()
329
    {
10,644✔
330
      // If the dt is called after an explicit close(), value does not matter.
331
      // Otherwise, it signals a implicit close, e.g. an exception was thrown
332
      close(-1);
10,644✔
333
    }
10,644✔
334
    EventScope(const EventScope&) = delete;
335
    EventScope(EventScope&&) = delete;
336
    EventScope& operator=(const EventScope&) = delete;
337
    EventScope& operator=(EventScope&&) = delete;
338

339
  private:
340
    RecEventTrace& d_eventTrace;
341
    size_t d_oldParent;
342
    size_t d_match{0};
343
    EventType d_event{EventType::CustomEvent};
344
    bool d_closed{false};
345
  };
346

347
private:
348
  std::vector<Entry> d_events;
349
  int64_t d_base{0};
350
  size_t d_parent{0};
351
  enum Status : uint8_t
352
  {
353
    Disabled,
354
    Invalid,
355
    Enabled
356
  };
357
  mutable Status d_status{Disabled};
358
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc