| /** @file | |
| A brief file description | |
| @section license License | |
| Licensed to the Apache Software Foundation (ASF) under one | |
| or more contributor license agreements. See the NOTICE file | |
| distributed with this work for additional information | |
| regarding copyright ownership. The ASF licenses this file | |
| to you under the Apache License, Version 2.0 (the | |
| "License"); you may not use this file except in compliance | |
| with the License. You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| */ | |
| #pragma once | |
| #include <functional> | |
| #include <memory> | |
| #include <optional> | |
| #include <string_view> | |
| #include <string> | |
| #include <variant> | |
| #include <tuple> | |
| #include <vector> | |
| #include "tscore/ink_inet.h" | |
| #include "tscore/ink_platform.h" | |
| #include "tscore/List.h" | |
| #include "proxy/logging/LogFieldAliasMap.h" | |
| #include "proxy/Milestones.h" | |
| enum LogEscapeType { LOG_ESCAPE_NONE, LOG_ESCAPE_JSON }; | |
| class LogAccess; | |
| struct LogSlice { | |
| bool m_enable; | |
| int m_start; | |
| int m_end; | |
| LogSlice() | |
| { | |
| m_enable = false; | |
| m_start = 0; | |
| m_end = INT_MAX; | |
| } | |
| // | |
| // Initialize LogSlice by slice notation, | |
| // the str looks like: "xxx[0:30]". | |
| // | |
| explicit LogSlice(char *str); | |
| // | |
| // Convert slice notation to target string's offset, | |
| // return the available length belongs to this slice. | |
| // | |
| // Use the offset and return value, we can locate the | |
| // string content indicated by this slice. | |
| // | |
| int toStrOffset(int strlen, int *offset); | |
| }; | |
| /*------------------------------------------------------------------------- | |
| LogField | |
| This class represents a field that can be logged. To construct a new | |
| field, we need to know its name, its symbol, its datatype, and the | |
| pointer to its LogAccess marshalling routine. Example: | |
| LogField ("client_host_ip", "chi", LogField::INT, | |
| &LogAccess::marshal_client_host_ip); | |
| -------------------------------------------------------------------------*/ | |
| class LogField | |
| { | |
| public: | |
| using MarshalFunc = int (LogAccess::*)(char *); | |
| using UnmarshalFunc = int (*)(char **, char *, int); | |
| using UnmarshalFuncWithSlice = int (*)(char **, char *, int, LogSlice *, LogEscapeType); | |
| using UnmarshalFuncWithMap = int (*)(char **, char *, int, const Ptr<LogFieldAliasMap> &); | |
| using SetFunc = void (LogAccess::*)(char *, int); | |
| using CustomMarshalFunc = std::function<int(void *, char *)>; | |
| using CustomUnmarshalFunc = std::tuple<int, int> (*)(char **, char *, int); | |
| using VarUnmarshalFuncSliceOnly = std::variant<UnmarshalFunc, UnmarshalFuncWithSlice>; | |
| using VarUnmarshalFunc = std::variant<decltype(nullptr), UnmarshalFunc, UnmarshalFuncWithSlice, UnmarshalFuncWithMap>; | |
| /** Field value type. | |
| These values are also the on-wire type codes of the v3 binary log schema | |
| (see LogBufferHeader::fmt_fieldtypes() and the v3 format docs under | |
| doc/developer-guide/logging-architecture/), so they are a published | |
| contract: append before N_TYPES, never renumber. 0 is reserved for INVALID | |
| so a zero-filled schema byte can't pass as a real type. The code describes | |
| only framing (how to walk/skip a field), never the value's meaning. | |
| */ | |
| enum class Type : uint8_t { | |
| INVALID = 0, ///< Reserved: never written; a reader treats 0 (or any unknown code) as unframmable and stops. | |
| sINT = 1, ///< one int64_t, 8 bytes (host byte order). | |
| dINT = 2, ///< two int64_t (16 bytes). | |
| STRING = 3, ///< NUL-terminated, 8-byte padded. | |
| IP = 4, ///< uint16_t family + family-sized address, 8-byte padded. | |
| N_TYPES = 5, ///< Internal bound (asserts / name table); NOT a wire code. | |
| }; | |
| enum Container { | |
| NO_CONTAINER = 0, | |
| CQH, | |
| PSH, | |
| PQH, | |
| SSH, | |
| CSSH, | |
| ECQH, | |
| EPSH, | |
| EPQH, | |
| ESSH, | |
| ECSSH, | |
| ICFG, | |
| SCFG, | |
| RECORD, | |
| MS, | |
| MSDMS, | |
| N_CONTAINERS, | |
| }; | |
| enum Aggregate { | |
| NO_AGGREGATE = 0, | |
| eCOUNT, | |
| eSUM, | |
| eAVG, | |
| eFIRST, | |
| eLAST, | |
| N_AGGREGATES, | |
| }; | |
| struct HeaderField { | |
| std::string name; | |
| Container container = NO_CONTAINER; | |
| LogSlice slice; | |
| }; | |
| LogField(const char *name, const char *symbol, Type type, MarshalFunc marshal, VarUnmarshalFuncSliceOnly unmarshal, | |
| SetFunc _setFunc = nullptr); | |
| LogField(const char *name, const char *symbol, Type type, MarshalFunc marshal, UnmarshalFuncWithMap unmarshal, | |
| const Ptr<LogFieldAliasMap> &map, SetFunc _setFunc = nullptr); | |
| LogField(const char *name, const char *symbol, Type type, CustomMarshalFunc custom_marshal, CustomUnmarshalFunc custom_unmarshal); | |
| LogField(const char *field, Container container); | |
| LogField(const char *symbol, std::vector<HeaderField> header_fields, std::unique_ptr<LogField> fallback_field = nullptr, | |
| std::optional<std::string> fallback_default = std::nullopt); | |
| LogField(const LogField &rhs); | |
| ~LogField(); | |
| unsigned marshal_len(LogAccess *lad); | |
| unsigned marshal(LogAccess *lad, char *buf); | |
| unsigned marshal_agg(char *buf); | |
| unsigned unmarshal(char **buf, char *dest, int len, LogEscapeType escape_type = LOG_ESCAPE_NONE); | |
| void display(FILE *fd = stdout); | |
| bool operator==(LogField &rhs); | |
| void updateField(LogAccess *lad, char *val, int len); | |
| const char * | |
| name() const | |
| { | |
| return m_name; | |
| } | |
| const char * | |
| symbol() const | |
| { | |
| return m_symbol; | |
| } | |
| Type | |
| type() const | |
| { | |
| return m_type; | |
| } | |
| Ptr<LogFieldAliasMap> | |
| map() | |
| { | |
| return m_alias_map; | |
| } | |
| Aggregate | |
| aggregate() const | |
| { | |
| return m_agg_op; | |
| } | |
| bool | |
| is_time_field() const | |
| { | |
| return m_time_field; | |
| } | |
| void set_http_header_field(LogAccess *lad, LogField::Container container, char *field, char *buf, int len); | |
| void set_aggregate_op(Aggregate agg_op); | |
| void update_aggregate(int64_t val); | |
| static void init_milestone_container(); | |
| static Container valid_container_name(char *name); | |
| static Aggregate valid_aggregate_name(char *name); | |
| static bool fieldlist_contains_aggregates(const char *fieldlist); | |
| static bool isHeaderContainer(Container container); | |
| static bool isContainerUpdateFieldSupported(Container container); | |
| private: | |
| char *m_name; | |
| char *m_symbol; | |
| Type m_type; | |
| Container m_container; | |
| MarshalFunc m_marshal_func; // place data into buffer | |
| VarUnmarshalFunc m_unmarshal_func; // create a string of the data | |
| Aggregate m_agg_op; | |
| int64_t m_agg_cnt; | |
| int64_t m_agg_val; | |
| TSMilestonesType m_milestone1; ///< Used for MS and MSDMS as the first (or only) milestone. | |
| TSMilestonesType m_milestone2; ///< Second milestone for MSDMS | |
| bool m_time_field; | |
| Ptr<LogFieldAliasMap> m_alias_map; // map sINT <--> string | |
| SetFunc m_set_func; | |
| TSMilestonesType milestone_from_m_name(); | |
| int milestones_from_m_name(TSMilestonesType *m1, TSMilestonesType *m2); | |
| CustomMarshalFunc m_custom_marshal_func; | |
| CustomUnmarshalFunc m_custom_unmarshal_func = nullptr; | |
| std::vector<HeaderField> m_fallback_header_fields; | |
| std::unique_ptr<LogField> m_fallback_field; | |
| std::optional<std::string> m_fallback_default; | |
| bool is_field_fallback() const; | |
| int select_fallback_selector(LogAccess *lad) const; | |
| unsigned marshal_fallback_header_field(LogAccess *lad, const HeaderField &field, char *buf) const; | |
| unsigned marshal_fallback_default(char *buf) const; | |
| static constexpr int FALLBACK_DEFAULT_SELECTOR = -1; | |
| static constexpr int FALLBACK_FIELD_SELECTOR = -2; | |
| public: | |
| LINK(LogField, link); | |
| LogSlice m_slice; | |
| // noncopyable | |
| // -- member functions that are not allowed -- | |
| LogField &operator=(const LogField &rhs) = delete; | |
| private: | |
| LogField(); | |
| }; | |
| /*------------------------------------------------------------------------- | |
| LogFieldList | |
| This class maintains a list of LogField objects (tah-dah). | |
| -------------------------------------------------------------------------*/ | |
| class LogFieldList | |
| { | |
| public: | |
| LogFieldList(); | |
| ~LogFieldList(); | |
| void clear(); | |
| void add(LogField *field); | |
| void remove(LogField *field); | |
| LogField *find_by_name(const char *name) const; | |
| LogField *find_by_symbol(const char *symbol) const; | |
| unsigned marshal_len(LogAccess *lad); | |
| unsigned marshal(LogAccess *lad, char *buf); | |
| unsigned marshal_agg(char *buf); | |
| LogField * | |
| first() const | |
| { | |
| return m_field_list.head; | |
| } | |
| LogField * | |
| next(LogField *here) const | |
| { | |
| return (here->link).next; | |
| } | |
| unsigned count(); | |
| void display(FILE *fd = stdout); | |
| // Add a bad symbol seen in the log format to the list of bad symbols. | |
| // | |
| void addBadSymbol(std::string_view badSymbol); | |
| // Return blank-separated list of added bad symbols. | |
| // | |
| std::string_view | |
| badSymbols() const | |
| { | |
| return _badSymbols; | |
| } | |
| // noncopyable | |
| // -- member functions that are not allowed -- | |
| LogFieldList(const LogFieldList &rhs) = delete; | |
| LogFieldList &operator=(const LogFieldList &rhs) = delete; | |
| private: | |
| unsigned m_marshal_len = 0; | |
| Queue<LogField> m_field_list; | |
| std::string _badSymbols; | |
| }; | |
| /** Base IP address data. | |
| To unpack an IP address, the generic memory is first cast to | |
| this type to get the family. That pointer can then be static_cast | |
| to the appropriate subtype to get the actual address data. | |
| @note We don't use our own enum for the family. Instead we use | |
| @c AF_INET and @c AF_INET6. | |
| */ | |
| struct LogFieldIp { | |
| uint16_t _family; ///< IP address family. | |
| }; | |
| /// IPv4 address as log field. | |
| struct LogFieldIp4 : public LogFieldIp { | |
| in_addr_t _addr; ///< IPv4 address. | |
| }; | |
| /// IPv6 address as log field. | |
| struct LogFieldIp6 : public LogFieldIp { | |
| in6_addr _addr; ///< IPv6 address. | |
| }; | |
| /// Unix address as log field. | |
| struct LogFieldUn : public LogFieldIp { | |
| char _path[TS_UNIX_SIZE]; ///< Unix domain path | |
| }; | |
| /// Something big enough to hold any of the IP field types. | |
| union LogFieldIpStorage { | |
| LogFieldIp _ip; | |
| LogFieldIp4 _ip4; | |
| LogFieldIp6 _ip6; | |
| LogFieldUn _un; | |
| }; |