From 86b14363f4794a7bc0bf377471b48f1373758b99 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 (cherry picked from commit 5ea7bb8449a75f96ed6e4d4d1c1f3d31e27040f8) --- 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 9377458b2ccf1..dc24ce66e7628 100644 --- a/src/rgw/rgw_asio_frontend.cc +++ b/src/rgw/rgw_asio_frontend.cc @@ -82,6 +82,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 @@ -119,9 +147,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); @@ -164,8 +192,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.39.5