diff --git a/gennghttpxfun.py b/gennghttpxfun.py index 0db75875..1be4d56c 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -205,6 +205,10 @@ LOGVARS = [ "tls_client_serial", "backend_host", "backend_port", + "method", + "path", + "path_without_query", + "protocol_version", ] if __name__ == '__main__': diff --git a/src/shrpx.cc b/src/shrpx.cc index 4ff5e478..363d564c 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -2607,6 +2607,14 @@ Logging: request. "-" if backend host is not available. * $backend_port: backend port used to fulfill the request. "-" if backend host is not available. + * $method: HTTP method + * $path: Request path including query. For CONNECT + request, authority is recorded. + * $path_without_query: $path up to the first '?' + character. For CONNECT request, authority is + recorded. + * $protocol_version: HTTP version (e.g., HTTP/1.1, + HTTP/2) The variable can be enclosed by "{" and "}" for disambiguation (e.g., ${remote_addr}). diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 769ad9b8..8f5cd507 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -387,6 +387,11 @@ LogFragmentType log_var_lookup_token(const char *name, size_t namelen) { break; case 4: switch (name[3]) { + case 'h': + if (util::strieq_l("pat", name, 3)) { + return LogFragmentType::PATH; + } + break; case 'n': if (util::strieq_l("alp", name, 3)) { return LogFragmentType::ALPN; @@ -396,6 +401,11 @@ LogFragmentType log_var_lookup_token(const char *name, size_t namelen) { break; case 6: switch (name[5]) { + case 'd': + if (util::strieq_l("metho", name, 5)) { + return LogFragmentType::METHOD; + } + break; case 's': if (util::strieq_l("statu", name, 5)) { return LogFragmentType::STATUS; @@ -502,6 +512,15 @@ LogFragmentType log_var_lookup_token(const char *name, size_t namelen) { break; } break; + case 16: + switch (name[15]) { + case 'n': + if (util::strieq_l("protocol_versio", name, 15)) { + return LogFragmentType::PROTOCOL_VERSION; + } + break; + } + break; case 17: switch (name[16]) { case 'l': @@ -521,6 +540,11 @@ LogFragmentType log_var_lookup_token(const char *name, size_t namelen) { return LogFragmentType::TLS_SESSION_REUSED; } break; + case 'y': + if (util::strieq_l("path_without_quer", name, 17)) { + return LogFragmentType::PATH_WITHOUT_QUERY; + } + break; } break; case 22: diff --git a/src/shrpx_log.cc b/src/shrpx_log.cc index cc5d018b..3789c779 100644 --- a/src/shrpx_log.cc +++ b/src/shrpx_log.cc @@ -603,6 +603,11 @@ void upstream_accesslog(const std::vector &lfv, ? StringRef::from_lit("*") : StringRef::from_lit("-") : req.path; + auto path_without_query = + req.method == HTTP_CONNECT + ? path + : StringRef{std::begin(path), + std::find(std::begin(path), std::end(path), '?')}; auto p = std::begin(buf); auto last = std::end(buf) - 2; @@ -632,6 +637,24 @@ void upstream_accesslog(const std::vector &lfv, std::tie(p, last) = copy(req.http_minor, p, last); } break; + case LogFragmentType::METHOD: + std::tie(p, last) = copy(method, p, last); + std::tie(p, last) = copy(' ', p, last); + break; + case LogFragmentType::PATH: + std::tie(p, last) = copy_escape(path, p, last); + break; + case LogFragmentType::PATH_WITHOUT_QUERY: + std::tie(p, last) = copy_escape(path_without_query, p, last); + break; + case LogFragmentType::PROTOCOL_VERSION: + std::tie(p, last) = copy_l("HTTP/", p, last); + std::tie(p, last) = copy(req.http_major, p, last); + if (req.http_major < 2) { + std::tie(p, last) = copy('.', p, last); + std::tie(p, last) = copy(req.http_minor, p, last); + } + break; case LogFragmentType::STATUS: std::tie(p, last) = copy(resp.http_status, p, last); break; diff --git a/src/shrpx_log.h b/src/shrpx_log.h index 7b0b914e..81035b2e 100644 --- a/src/shrpx_log.h +++ b/src/shrpx_log.h @@ -249,6 +249,10 @@ enum class LogFragmentType { TLS_CLIENT_SUBJECT_NAME, BACKEND_HOST, BACKEND_PORT, + METHOD, + PATH, + PATH_WITHOUT_QUERY, + PROTOCOL_VERSION, }; struct LogFragment {