Line data Source code
1 : #pragma once 2 : 3 : #include <cstdint> 4 : #include <string> 5 : #include <vector> 6 : 7 : #include "envoy/access_log/access_log.h" 8 : #include "envoy/access_log/access_log_config.h" 9 : #include "envoy/common/random_generator.h" 10 : #include "envoy/config/accesslog/v3/accesslog.pb.h" 11 : #include "envoy/config/typed_config.h" 12 : #include "envoy/runtime/runtime.h" 13 : #include "envoy/type/v3/percent.pb.h" 14 : 15 : #include "source/common/common/matchers.h" 16 : #include "source/common/common/utility.h" 17 : #include "source/common/config/utility.h" 18 : #include "source/common/formatter/http_specific_formatter.h" 19 : #include "source/common/grpc/status.h" 20 : #include "source/common/http/header_utility.h" 21 : #include "source/common/protobuf/protobuf.h" 22 : 23 : #include "absl/container/node_hash_set.h" 24 : #include "absl/hash/hash.h" 25 : 26 : namespace Envoy { 27 : namespace AccessLog { 28 : 29 : /** 30 : * Access log filter factory that reads from proto. 31 : */ 32 : class FilterFactory { 33 : public: 34 : /** 35 : * Read a filter definition from proto and instantiate a concrete filter class. 36 : */ 37 : static FilterPtr fromProto(const envoy::config::accesslog::v3::AccessLogFilter& config, 38 : Server::Configuration::FactoryContext& context); 39 : }; 40 : 41 : /** 42 : * Base implementation of an access log filter that performs comparisons. 43 : */ 44 : class ComparisonFilter : public Filter { 45 : protected: 46 : ComparisonFilter(const envoy::config::accesslog::v3::ComparisonFilter& config, 47 : Runtime::Loader& runtime); 48 : 49 : bool compareAgainstValue(uint64_t lhs) const; 50 : 51 : envoy::config::accesslog::v3::ComparisonFilter config_; 52 : Runtime::Loader& runtime_; 53 : }; 54 : 55 : /** 56 : * Filter on response status code. 57 : */ 58 : class StatusCodeFilter : public ComparisonFilter { 59 : public: 60 : StatusCodeFilter(const envoy::config::accesslog::v3::StatusCodeFilter& config, 61 : Runtime::Loader& runtime) 62 0 : : ComparisonFilter(config.comparison(), runtime) {} 63 : 64 : // AccessLog::Filter 65 : bool evaluate(const Formatter::HttpFormatterContext& context, 66 : const StreamInfo::StreamInfo& info) const override; 67 : }; 68 : 69 : /** 70 : * Filter on total request/response duration. 71 : */ 72 : class DurationFilter : public ComparisonFilter { 73 : public: 74 : DurationFilter(const envoy::config::accesslog::v3::DurationFilter& config, 75 : Runtime::Loader& runtime) 76 0 : : ComparisonFilter(config.comparison(), runtime) {} 77 : 78 : // AccessLog::Filter 79 : bool evaluate(const Formatter::HttpFormatterContext& context, 80 : const StreamInfo::StreamInfo& info) const override; 81 : }; 82 : 83 : /** 84 : * Base operator filter, compose other filters with operation 85 : */ 86 : class OperatorFilter : public Filter { 87 : public: 88 : OperatorFilter( 89 : const Protobuf::RepeatedPtrField<envoy::config::accesslog::v3::AccessLogFilter>& configs, 90 : Server::Configuration::FactoryContext& context); 91 : 92 : protected: 93 : std::vector<FilterPtr> filters_; 94 : }; 95 : 96 : /** 97 : * *And* operator filter, apply logical *and* operation to all of the sub filters. 98 : */ 99 : class AndFilter : public OperatorFilter { 100 : public: 101 : AndFilter(const envoy::config::accesslog::v3::AndFilter& config, 102 : Server::Configuration::FactoryContext& context); 103 : 104 : // AccessLog::Filter 105 : bool evaluate(const Formatter::HttpFormatterContext& context, 106 : const StreamInfo::StreamInfo& info) const override; 107 : }; 108 : 109 : /** 110 : * *Or* operator filter, apply logical *or* operation to all of the sub filters. 111 : */ 112 : class OrFilter : public OperatorFilter { 113 : public: 114 : OrFilter(const envoy::config::accesslog::v3::OrFilter& config, 115 : Server::Configuration::FactoryContext& context); 116 : 117 : // AccessLog::Filter 118 : bool evaluate(const Formatter::HttpFormatterContext& context, 119 : const StreamInfo::StreamInfo& info) const override; 120 : }; 121 : 122 : /** 123 : * Filter out health check requests. 124 : */ 125 : class NotHealthCheckFilter : public Filter { 126 : public: 127 70 : NotHealthCheckFilter() = default; 128 : 129 : // AccessLog::Filter 130 : bool evaluate(const Formatter::HttpFormatterContext& context, 131 : const StreamInfo::StreamInfo& info) const override; 132 : }; 133 : 134 : /** 135 : * Filter traceable requests. 136 : */ 137 : class TraceableRequestFilter : public Filter { 138 : public: 139 : // AccessLog::Filter 140 : bool evaluate(const Formatter::HttpFormatterContext& context, 141 : const StreamInfo::StreamInfo& info) const override; 142 : }; 143 : 144 : /** 145 : * Filter that uses a runtime feature key to check if the log should be written. 146 : */ 147 : class RuntimeFilter : public Filter { 148 : public: 149 : RuntimeFilter(const envoy::config::accesslog::v3::RuntimeFilter& config, Runtime::Loader& runtime, 150 : Random::RandomGenerator& random); 151 : 152 : // AccessLog::Filter 153 : bool evaluate(const Formatter::HttpFormatterContext& context, 154 : const StreamInfo::StreamInfo& info) const override; 155 : 156 : private: 157 : Runtime::Loader& runtime_; 158 : Random::RandomGenerator& random_; 159 : const std::string runtime_key_; 160 : const envoy::type::v3::FractionalPercent percent_; 161 : const bool use_independent_randomness_; 162 : }; 163 : 164 : /** 165 : * Filter based on headers. 166 : */ 167 : class HeaderFilter : public Filter { 168 : public: 169 : HeaderFilter(const envoy::config::accesslog::v3::HeaderFilter& config); 170 : 171 : // AccessLog::Filter 172 : bool evaluate(const Formatter::HttpFormatterContext& context, 173 : const StreamInfo::StreamInfo& info) const override; 174 : 175 : private: 176 : const Http::HeaderUtility::HeaderDataPtr header_data_; 177 : }; 178 : 179 : /** 180 : * Filter requests that had a response with an Envoy response flag set. 181 : */ 182 : class ResponseFlagFilter : public Filter { 183 : public: 184 : ResponseFlagFilter(const envoy::config::accesslog::v3::ResponseFlagFilter& config); 185 : 186 : // AccessLog::Filter 187 : bool evaluate(const Formatter::HttpFormatterContext& context, 188 : const StreamInfo::StreamInfo& info) const override; 189 : 190 : private: 191 : uint64_t configured_flags_{}; 192 : }; 193 : 194 : /** 195 : * Filters requests that have a response with a gRPC status. Because the gRPC protocol does not 196 : * guarantee a gRPC status code, if a gRPC status code is not available, then the filter will infer 197 : * the gRPC status code from an HTTP status code if available. 198 : */ 199 : class GrpcStatusFilter : public Filter { 200 : public: 201 : using GrpcStatusHashSet = 202 : absl::node_hash_set<Grpc::Status::GrpcStatus, absl::Hash<Grpc::Status::GrpcStatus>>; 203 : 204 : GrpcStatusFilter(const envoy::config::accesslog::v3::GrpcStatusFilter& config); 205 : 206 : // AccessLog::Filter 207 : bool evaluate(const Formatter::HttpFormatterContext& context, 208 : const StreamInfo::StreamInfo& info) const override; 209 : 210 : private: 211 : GrpcStatusHashSet statuses_; 212 : bool exclude_; 213 : 214 : /** 215 : * Converts a Protobuf representation of a gRPC status into the equivalent code version of a gRPC 216 : * status. 217 : */ 218 : Grpc::Status::GrpcStatus 219 : protoToGrpcStatus(envoy::config::accesslog::v3::GrpcStatusFilter::Status status) const; 220 : }; 221 : 222 : /** 223 : * Filters requests based on access log type 224 : */ 225 : class LogTypeFilter : public Filter { 226 : public: 227 : using LogTypeHashSet = absl::flat_hash_set<AccessLogType>; 228 : 229 : LogTypeFilter(const envoy::config::accesslog::v3::LogTypeFilter& filter_config); 230 : 231 : bool evaluate(const Formatter::HttpFormatterContext& context, 232 : const StreamInfo::StreamInfo& info) const override; 233 : 234 : private: 235 : LogTypeHashSet types_; 236 : bool exclude_; 237 : }; 238 : 239 : /** 240 : * Filters requests based on dynamic metadata 241 : */ 242 : class MetadataFilter : public Filter { 243 : public: 244 : MetadataFilter(const envoy::config::accesslog::v3::MetadataFilter& filter_config); 245 : 246 : bool evaluate(const Formatter::HttpFormatterContext& context, 247 : const StreamInfo::StreamInfo& info) const override; 248 : 249 : private: 250 : Matchers::ValueMatcherConstSharedPtr present_matcher_; 251 : Matchers::ValueMatcherConstSharedPtr value_matcher_; 252 : 253 : std::vector<std::string> path_; 254 : 255 : const bool default_match_; 256 : const std::string filter_; 257 : }; 258 : 259 : /** 260 : * Access log factory that reads the configuration from proto. 261 : */ 262 : class AccessLogFactory { 263 : public: 264 : /** 265 : * Read a filter definition from proto and instantiate an Instance. This method is used 266 : * to create access log instances that need access to listener properties. 267 : */ 268 : static InstanceSharedPtr fromProto(const envoy::config::accesslog::v3::AccessLog& config, 269 : Server::Configuration::FactoryContext& context); 270 : 271 : /** 272 : * Template method to create an access log filter from proto configuration for non-HTTP access 273 : * loggers. 274 : */ 275 : template <class Context> 276 : static FilterBasePtr<Context> 277 : accessLogFilterFromProto(const envoy::config::accesslog::v3::AccessLogFilter& config, 278 : Server::Configuration::FactoryContext& context) { 279 : if (!config.has_extension_filter()) { 280 : ExceptionUtil::throwEnvoyException( 281 : "Access log filter: only extension filter is supported by non-HTTP access loggers."); 282 : } 283 : 284 : auto& factory = Config::Utility::getAndCheckFactory<ExtensionFilterFactoryBase<Context>>( 285 : config.extension_filter()); 286 : return factory.createFilter(config.extension_filter(), context); 287 : } 288 : 289 : /** 290 : * Template method to create an access logger instance from proto configuration for non-HTTP 291 : * access loggers. 292 : */ 293 : template <class Context> 294 : static InstanceBaseSharedPtr<Context> 295 : accessLoggerFromProto(const envoy::config::accesslog::v3::AccessLog& config, 296 : Server::Configuration::FactoryContext& context) { 297 : FilterBasePtr<Context> filter; 298 : if (config.has_filter()) { 299 : filter = accessLogFilterFromProto<Context>(config.filter(), context); 300 : } 301 : 302 : auto& factory = 303 : Config::Utility::getAndCheckFactory<AccessLogInstanceFactoryBase<Context>>(config); 304 : ProtobufTypes::MessagePtr message = Config::Utility::translateToFactoryConfig( 305 : config, context.messageValidationVisitor(), factory); 306 : 307 : return factory.createAccessLogInstance(*message, std::move(filter), context); 308 : } 309 : }; 310 : 311 : } // namespace AccessLog 312 : } // namespace Envoy