Coverage Report

Created: 2026-03-28 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/trafficserver/include/tsutil/DbgCtl.h
Line
Count
Source
1
/** @file
2
3
  DbgCtl class header file.
4
5
  @section license License
6
7
  Licensed to the Apache Software Foundation (ASF) under one
8
  or more contributor license agreements.  See the NOTICE file
9
  distributed with this work for additional information
10
  regarding copyright ownership.  The ASF licenses this file
11
  to you under the Apache License, Version 2.0 (the
12
  "License"); you may not use this file except in compliance
13
  with the License.  You may obtain a copy of the License at
14
15
      http://www.apache.org/licenses/LICENSE-2.0
16
17
  Unless required by applicable law or agreed to in writing, software
18
  distributed under the License is distributed on an "AS IS" BASIS,
19
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
  See the License for the specific language governing permissions and
21
  limitations under the License.
22
 */
23
24
#pragma once
25
26
#include "tsutil/SourceLocation.h"
27
#include "tsutil/ts_diag_levels.h"
28
#include "swoc/BufferWriter.h"
29
#include <atomic>
30
#include <utility>
31
#include <functional>
32
33
#include <ts/apidefs.h> // For TS_PRINTFLIKE
34
35
class DiagsConfigState;
36
37
enum DiagsShowLocation { SHOW_LOCATION_NONE = 0, SHOW_LOCATION_DEBUG, SHOW_LOCATION_ALL };
38
39
class DebugInterface
40
{
41
public:
42
5.52k
  virtual ~DebugInterface()                            = default;
43
  virtual bool debug_tag_activated(const char *) const = 0;
44
  virtual bool get_override() const                    = 0;
45
  virtual void print_va(const char *debug_tag, DiagsLevel diags_level, const SourceLocation *loc, const char *format_string,
46
                        va_list ap) const              = 0;
47
48
  static DebugInterface *get_instance();
49
  static void            set_instance(DebugInterface *);
50
51
  // Generate the default diagnostics format string for the given parameters.
52
  // @return The offset in the format string of the timestamp (in case the caller doesn't want to include that)
53
  static size_t generate_format_string(swoc::LocalBufferWriter<1024> &format_writer, const char *debug_tag, DiagsLevel diags_level,
54
                                       const SourceLocation *loc, DiagsShowLocation show_location, const char *format_string);
55
  static const char *level_name(DiagsLevel dl);
56
};
57
58
class DbgCtl
59
{
60
public:
61
  // Tag is a debug tag.  Debug output associated with this control will be output when debug output
62
  // is enabled globally, and the tag matches the configured debug tag regular expression.
63
  //
64
6
  DbgCtl(char const *tag) : _ptr{_new_reference(tag)} {}
65
66
  // As instance with no tag will always be off.
67
  //
68
0
  DbgCtl() : _ptr{&_No_tag_dummy()} {}
69
70
  // Default destructor: the registry uses a "leaky singleton" pattern to avoid
71
  // use-after-free crashes during shutdown due to undefined static destruction
72
  // order. See issue #12776.
73
  ~DbgCtl() = default;
74
75
  // No copying. Only moving from a tagged to a tagless instance allowed.
76
  //
77
  DbgCtl(DbgCtl const &)            = delete;
78
  DbgCtl &operator=(DbgCtl const &) = delete;
79
  DbgCtl(DbgCtl &&);
80
  DbgCtl &operator=(DbgCtl &&);
81
82
  // A shorthand.
83
  //
84
  void
85
  set(char const *tag)
86
0
  {
87
0
    *this = DbgCtl{tag};
88
0
  }
89
90
  bool
91
  tag_on() const
92
0
  {
93
0
    return _ptr->second;
94
0
  }
95
96
  char const *
97
  tag() const
98
0
  {
99
0
    return _ptr->first;
100
0
  }
101
102
  bool
103
  on() const
104
6.85k
  {
105
6.85k
    auto m{_config_mode.load(std::memory_order_relaxed)};
106
6.85k
    if (!m) {
107
6.85k
      return false;
108
6.85k
    }
109
0
    if (!_ptr->second) {
110
0
      return false;
111
0
    }
112
0
    if (m & 1) {
113
0
      return true;
114
0
    }
115
0
    return (2 == m) && (_override_global_on());
116
0
  }
117
118
  static bool
119
  global_on()
120
0
  {
121
0
    auto m{_config_mode.load(std::memory_order_relaxed)};
122
0
    if (!m) {
123
0
      return false;
124
0
    }
125
0
    if (m & 1) {
126
0
      return true;
127
0
    }
128
0
    return (2 == m) && (_override_global_on());
129
0
  }
130
131
  // Call this when the compiled regex to enable tags may have changed.
132
  //
133
  static void update(const std::function<bool(const char *)> &f);
134
135
  // For use in DbgPrint() only.
136
  //
137
  static void print(char const *tag, char const *file, char const *function, int line, char const *fmt_str, ...)
138
    TS_PRINTFLIKE(5, 6);
139
140
private:
141
  using _TagData = std::pair<char const *const, bool>;
142
143
  _TagData const *_ptr;
144
145
  static const _TagData &
146
  _No_tag_dummy()
147
0
  {
148
0
    static DbgCtl::_TagData const ntd{nullptr, false};
149
0
    return ntd;
150
0
  }
151
152
  static const _TagData *_new_reference(char const *tag);
153
154
  // Deprecated: backward compatibility stub, no-op since we now use leaky singleton.
155
  // TODO: This can be removed in 11.x because we don't have to worry about
156
  // compatibility there.
157
  static void _rm_reference();
158
159
  class _RegistryAccessor;
160
161
  static std::atomic<int> _config_mode;
162
163
  static bool _override_global_on();
164
165
  friend class DiagsConfigState;
166
};
167
168
// Always generates output when called.
169
//
170
0
#define DbgPrint(CTL, ...) (DbgCtl::print((CTL).tag(), __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__))
171
172
#define Dbg(CTL, ...)               \
173
6.85k
  do {                              \
174
6.85k
    if ((CTL).on()) {               \
175
0
      DbgPrint((CTL), __VA_ARGS__); \
176
0
    }                               \
177
6.85k
  } while (false)
178
179
// Same as Dbg above, but this allows a positive override of the DbgCtl, if FLAG is true.
180
//
181
#define SpecificDbg(FLAG, CTL, ...)   \
182
  do {                                \
183
    if (DbgCtl::global_on()) {        \
184
      if ((FLAG) || ((CTL).on())) {   \
185
        DbgPrint((CTL), __VA_ARGS__); \
186
      }                               \
187
    }                                 \
188
  } while (false)