From 5ea7bb8449a75f96ed6e4d4d1c1f3d31e27040f8 Mon Sep 17 00:00:00 2001 From: Mark Kogan Date: Tue, 18 Feb 2020 12:59:35 +0200 Subject: [PATCH] rgw: add access log to the beast frontend Add to the Beast frontend an access log line similar to CivetWeb. attempting to adhere as much as possible to the Apache Combined Log Format. Fixes: https://tracker.ceph.com/issues/45920 rgw: use beast message for access log (cherry picked from commit 44ec38933cbe6cc864c56332cc99502d86568fdc) Co-authored-by: Casey Bodley Signed-off-by: Mark Kogan --- src/rgw/rgw_asio_frontend.cc | 48 ++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/rgw/rgw_asio_frontend.cc b/src/rgw/rgw_asio_frontend.cc index deab1b0c66fb..fbb2a064b2a7 100644 --- a/src/rgw/rgw_asio_frontend.cc +++ b/src/rgw/rgw_asio_frontend.cc @@ -85,6 +85,34 @@ class StreamIO : public rgw::asio::ClientIO { } }; +// output the http version as a string, ie 'HTTP/1.1' +struct http_version { + unsigned major_ver; + unsigned minor_ver; + explicit http_version(unsigned version) + : major_ver(version / 10), minor_ver(version % 10) {} +}; +std::ostream& operator<<(std::ostream& out, const http_version& v) { + return out << "HTTP/" << v.major_ver << '.' << v.minor_ver; +} + +// log an http header value or '-' if it's missing +struct log_header { + const http::fields& fields; + http::field field; + std::string_view quote; + log_header(const http::fields& fields, http::field field, + std::string_view quote = "") + : fields(fields), field(field), quote(quote) {} +}; +std::ostream& operator<<(std::ostream& out, const log_header& h) { + auto p = h.fields.find(h.field); + if (p == h.fields.end()) { + return out << '-'; + } + return out << h.quote << p->value() << h.quote; +} + using SharedMutex = ceph::async::SharedMutex; template @@ -122,9 +150,9 @@ void handle_connection(boost::asio::io_context& context, ldout(cct, 20) << "failed to read header: " << ec.message() << dendl; return; } + auto& message = parser.get(); if (ec) { ldout(cct, 1) << "failed to read header: " << ec.message() << dendl; - auto& message = parser.get(); http::response response; response.result(http::status::bad_request); response.version(message.version() == 10 ? 10 : 11); @@ -167,8 +195,24 @@ void handle_connection(boost::asio::io_context& context, &real_client)))); RGWRestfulIO client(cct, &real_client_io); auto y = optional_yield{context, yield}; + int http_ret = 0; process_request(env.store, env.rest, &req, env.uri_prefix, - *env.auth_registry, &client, env.olog, y, scheduler); + *env.auth_registry, &client, env.olog, y, + scheduler, &http_ret); + + if (cct->_conf->subsys.should_gather(dout_subsys, 1)) { + // access log line elements begin per Apache Combined Log Format with additions following + const auto now = ceph::coarse_real_clock::now(); + using ceph::operator<<; // for coarse_real_time + ldout(cct, 1) << "beast: " << hex << &req << dec << ": " + << remote_endpoint.address() << " - - [" << now << "] \"" + << message.method_string() << ' ' << message.target() << ' ' + << http_version{message.version()} << "\" " << http_ret << ' ' + << client.get_bytes_sent() + client.get_bytes_received() << ' ' + << log_header{message, http::field::referer, "\""} << ' ' + << log_header{message, http::field::user_agent, "\""} << ' ' + << log_header{message, http::field::range} << dendl; + } } if (!parser.keep_alive()) { -- 2.47.3