/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 | | }; |