Coverage Report

Created: 2026-10-23 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/trafficserver/include/proxy/logging/LogField.h
Line
Count
Source
1
/** @file
2
3
  A brief file description
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 <functional>
27
#include <memory>
28
#include <optional>
29
#include <string_view>
30
#include <string>
31
#include <variant>
32
#include <tuple>
33
#include <vector>
34
35
#include "tscore/ink_inet.h"
36
#include "tscore/ink_platform.h"
37
#include "tscore/List.h"
38
#include "proxy/logging/LogFieldAliasMap.h"
39
#include "proxy/Milestones.h"
40
41
enum LogEscapeType { LOG_ESCAPE_NONE, LOG_ESCAPE_JSON };
42
43
class LogAccess;
44
45
struct LogSlice {
46
  bool m_enable;
47
  int  m_start;
48
  int  m_end;
49
50
  LogSlice()
51
0
  {
52
0
    m_enable = false;
53
0
    m_start  = 0;
54
0
    m_end    = INT_MAX;
55
0
  }
56
57
  //
58
  // Initialize LogSlice by slice notation,
59
  // the str looks like: "xxx[0:30]".
60
  //
61
  explicit LogSlice(char *str);
62
63
  //
64
  // Convert slice notation to target string's offset,
65
  // return the available length belongs to this slice.
66
  //
67
  // Use the offset and return value, we can locate the
68
  // string content indicated by this slice.
69
  //
70
  int toStrOffset(int strlen, int *offset);
71
};
72
73
/*-------------------------------------------------------------------------
74
  LogField
75
76
  This class represents a field that can be logged.  To construct a new
77
  field, we need to know its name, its symbol, its datatype, and the
78
  pointer to its LogAccess marshalling routine.  Example:
79
80
      LogField ("client_host_ip", "chi", LogField::INT,
81
                &LogAccess::marshal_client_host_ip);
82
  -------------------------------------------------------------------------*/
83
84
class LogField
85
{
86
public:
87
  using MarshalFunc            = int (LogAccess::*)(char *);
88
  using UnmarshalFunc          = int (*)(char **, char *, int);
89
  using UnmarshalFuncWithSlice = int (*)(char **, char *, int, LogSlice *, LogEscapeType);
90
  using UnmarshalFuncWithMap   = int (*)(char **, char *, int, const Ptr<LogFieldAliasMap> &);
91
  using SetFunc                = void (LogAccess::*)(char *, int);
92
  using CustomMarshalFunc      = std::function<int(void *, char *)>;
93
  using CustomUnmarshalFunc    = std::tuple<int, int> (*)(char **, char *, int);
94
95
  using VarUnmarshalFuncSliceOnly = std::variant<UnmarshalFunc, UnmarshalFuncWithSlice>;
96
  using VarUnmarshalFunc          = std::variant<decltype(nullptr), UnmarshalFunc, UnmarshalFuncWithSlice, UnmarshalFuncWithMap>;
97
98
  /** Field value type.
99
100
      These values are also the on-wire type codes of the v3 binary log schema
101
      (see LogBufferHeader::fmt_fieldtypes() and the v3 format docs under
102
      doc/developer-guide/logging-architecture/), so they are a published
103
      contract: append before N_TYPES, never renumber. 0 is reserved for INVALID
104
      so a zero-filled schema byte can't pass as a real type. The code describes
105
      only framing (how to walk/skip a field), never the value's meaning.
106
  */
107
  enum class Type : uint8_t {
108
    INVALID = 0, ///< Reserved: never written; a reader treats 0 (or any unknown code) as unframmable and stops.
109
    sINT    = 1, ///< one int64_t, 8 bytes (host byte order).
110
    dINT    = 2, ///< two int64_t (16 bytes).
111
    STRING  = 3, ///< NUL-terminated, 8-byte padded.
112
    IP      = 4, ///< uint16_t family + family-sized address, 8-byte padded.
113
    N_TYPES = 5, ///< Internal bound (asserts / name table); NOT a wire code.
114
  };
115
116
  enum Container {
117
    NO_CONTAINER = 0,
118
    CQH,
119
    PSH,
120
    PQH,
121
    SSH,
122
    CSSH,
123
    ECQH,
124
    EPSH,
125
    EPQH,
126
    ESSH,
127
    ECSSH,
128
    ICFG,
129
    SCFG,
130
    RECORD,
131
    MS,
132
    MSDMS,
133
    N_CONTAINERS,
134
  };
135
136
  enum Aggregate {
137
    NO_AGGREGATE = 0,
138
    eCOUNT,
139
    eSUM,
140
    eAVG,
141
    eFIRST,
142
    eLAST,
143
    N_AGGREGATES,
144
  };
145
146
  struct HeaderField {
147
    std::string name;
148
    Container   container = NO_CONTAINER;
149
    LogSlice    slice;
150
  };
151
152
  LogField(const char *name, const char *symbol, Type type, MarshalFunc marshal, VarUnmarshalFuncSliceOnly unmarshal,
153
           SetFunc _setFunc = nullptr);
154
155
  LogField(const char *name, const char *symbol, Type type, MarshalFunc marshal, UnmarshalFuncWithMap unmarshal,
156
           const Ptr<LogFieldAliasMap> &map, SetFunc _setFunc = nullptr);
157
158
  LogField(const char *name, const char *symbol, Type type, CustomMarshalFunc custom_marshal, CustomUnmarshalFunc custom_unmarshal);
159
160
  LogField(const char *field, Container container);
161
  LogField(const char *symbol, std::vector<HeaderField> header_fields, std::unique_ptr<LogField> fallback_field = nullptr,
162
           std::optional<std::string> fallback_default = std::nullopt);
163
  LogField(const LogField &rhs);
164
  ~LogField();
165
166
  unsigned marshal_len(LogAccess *lad);
167
  unsigned marshal(LogAccess *lad, char *buf);
168
  unsigned marshal_agg(char *buf);
169
  unsigned unmarshal(char **buf, char *dest, int len, LogEscapeType escape_type = LOG_ESCAPE_NONE);
170
  void     display(FILE *fd = stdout);
171
  bool     operator==(LogField &rhs);
172
  void     updateField(LogAccess *lad, char *val, int len);
173
174
  const char *
175
  name() const
176
0
  {
177
0
    return m_name;
178
0
  }
179
180
  const char *
181
  symbol() const
182
0
  {
183
0
    return m_symbol;
184
0
  }
185
186
  Type
187
  type() const
188
0
  {
189
0
    return m_type;
190
0
  }
191
192
  Ptr<LogFieldAliasMap>
193
  map()
194
0
  {
195
0
    return m_alias_map;
196
0
  }
197
198
  Aggregate
199
  aggregate() const
200
0
  {
201
0
    return m_agg_op;
202
0
  }
203
204
  bool
205
  is_time_field() const
206
0
  {
207
0
    return m_time_field;
208
0
  }
209
210
  void set_http_header_field(LogAccess *lad, LogField::Container container, char *field, char *buf, int len);
211
  void set_aggregate_op(Aggregate agg_op);
212
  void update_aggregate(int64_t val);
213
214
  static void      init_milestone_container();
215
  static Container valid_container_name(char *name);
216
  static Aggregate valid_aggregate_name(char *name);
217
  static bool      fieldlist_contains_aggregates(const char *fieldlist);
218
  static bool      isHeaderContainer(Container container);
219
  static bool      isContainerUpdateFieldSupported(Container container);
220
221
private:
222
  char                      *m_name;
223
  char                      *m_symbol;
224
  Type                       m_type;
225
  Container                  m_container;
226
  MarshalFunc                m_marshal_func;   // place data into buffer
227
  VarUnmarshalFunc           m_unmarshal_func; // create a string of the data
228
  Aggregate                  m_agg_op;
229
  int64_t                    m_agg_cnt;
230
  int64_t                    m_agg_val;
231
  TSMilestonesType           m_milestone1; ///< Used for MS and MSDMS as the first (or only) milestone.
232
  TSMilestonesType           m_milestone2; ///< Second milestone for MSDMS
233
  bool                       m_time_field;
234
  Ptr<LogFieldAliasMap>      m_alias_map; // map sINT <--> string
235
  SetFunc                    m_set_func;
236
  TSMilestonesType           milestone_from_m_name();
237
  int                        milestones_from_m_name(TSMilestonesType *m1, TSMilestonesType *m2);
238
  CustomMarshalFunc          m_custom_marshal_func;
239
  CustomUnmarshalFunc        m_custom_unmarshal_func = nullptr;
240
  std::vector<HeaderField>   m_fallback_header_fields;
241
  std::unique_ptr<LogField>  m_fallback_field;
242
  std::optional<std::string> m_fallback_default;
243
  bool                       is_field_fallback() const;
244
  int                        select_fallback_selector(LogAccess *lad) const;
245
  unsigned                   marshal_fallback_header_field(LogAccess *lad, const HeaderField &field, char *buf) const;
246
  unsigned                   marshal_fallback_default(char *buf) const;
247
248
  static constexpr int FALLBACK_DEFAULT_SELECTOR = -1;
249
  static constexpr int FALLBACK_FIELD_SELECTOR   = -2;
250
251
public:
252
  LINK(LogField, link);
253
  LogSlice m_slice;
254
255
  // noncopyable
256
  // -- member functions that are not allowed --
257
  LogField &operator=(const LogField &rhs) = delete;
258
259
private:
260
  LogField();
261
};
262
263
/*-------------------------------------------------------------------------
264
  LogFieldList
265
266
  This class maintains a list of LogField objects (tah-dah).
267
  -------------------------------------------------------------------------*/
268
269
class LogFieldList
270
{
271
public:
272
  LogFieldList();
273
  ~LogFieldList();
274
275
  void      clear();
276
  void      add(LogField *field);
277
  void      remove(LogField *field);
278
  LogField *find_by_name(const char *name) const;
279
  LogField *find_by_symbol(const char *symbol) const;
280
  unsigned  marshal_len(LogAccess *lad);
281
  unsigned  marshal(LogAccess *lad, char *buf);
282
  unsigned  marshal_agg(char *buf);
283
284
  LogField *
285
  first() const
286
0
  {
287
0
    return m_field_list.head;
288
0
  }
289
  LogField *
290
  next(LogField *here) const
291
0
  {
292
0
    return (here->link).next;
293
0
  }
294
  unsigned count();
295
  void     display(FILE *fd = stdout);
296
297
  // Add a bad symbol seen in the log format to the list of bad symbols.
298
  //
299
  void addBadSymbol(std::string_view badSymbol);
300
301
  // Return blank-separated list of added bad symbols.
302
  //
303
  std::string_view
304
  badSymbols() const
305
0
  {
306
0
    return _badSymbols;
307
0
  }
308
309
  // noncopyable
310
  // -- member functions that are not allowed --
311
  LogFieldList(const LogFieldList &rhs)            = delete;
312
  LogFieldList &operator=(const LogFieldList &rhs) = delete;
313
314
private:
315
  unsigned        m_marshal_len = 0;
316
  Queue<LogField> m_field_list;
317
  std::string     _badSymbols;
318
};
319
320
/** Base IP address data.
321
    To unpack an IP address, the generic memory is first cast to
322
    this type to get the family. That pointer can then be static_cast
323
    to the appropriate subtype to get the actual address data.
324
325
    @note We don't use our own enum for the family. Instead we use
326
    @c AF_INET and @c AF_INET6.
327
*/
328
struct LogFieldIp {
329
  uint16_t _family; ///< IP address family.
330
};
331
/// IPv4 address as log field.
332
struct LogFieldIp4 : public LogFieldIp {
333
  in_addr_t _addr; ///< IPv4 address.
334
};
335
/// IPv6 address as log field.
336
struct LogFieldIp6 : public LogFieldIp {
337
  in6_addr _addr; ///< IPv6 address.
338
};
339
/// Unix address as log field.
340
struct LogFieldUn : public LogFieldIp {
341
  char _path[TS_UNIX_SIZE]; ///< Unix domain path
342
};
343
/// Something big enough to hold any of the IP field types.
344
union LogFieldIpStorage {
345
  LogFieldIp  _ip;
346
  LogFieldIp4 _ip4;
347
  LogFieldIp6 _ip6;
348
  LogFieldUn  _un;
349
};