From 0ce848a611880ca19ac5bdfdfcd848148b7ff853 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 5 Jul 2014 18:22:40 +0900 Subject: [PATCH] nghttpx: Rewrite logging system This change rewrites logging system of nghttpx. Previously access log and error log are written to stderr or syslog and there was no option to change stderr to something else. With this change, file path of access log and error log can be configured separately and logging to regular file is now added. To support rotating log, if SIGUSR1 signal is received by nghttpx, it closes the current log files and reopen it with the same name. The format of access log is changed and has same look of apache's. But not all columns are not supported yet. --- src/Makefile.am | 2 +- src/shrpx.cc | 112 ++++++++-- src/shrpx_accesslog.cc | 146 ------------- src/shrpx_client_handler.cc | 1 - src/shrpx_config.cc | 34 ++- src/shrpx_config.h | 18 +- src/shrpx_downstream.cc | 21 ++ src/shrpx_downstream.h | 7 + src/shrpx_http.cc | 1 + src/shrpx_http2_downstream_connection.cc | 1 + src/shrpx_http2_session.cc | 3 + src/shrpx_http2_upstream.cc | 23 ++- src/shrpx_http_downstream_connection.cc | 6 +- src/shrpx_https_upstream.cc | 42 ++-- src/shrpx_listen_handler.cc | 47 +++-- src/shrpx_listen_handler.h | 2 +- src/shrpx_log.cc | 194 ++++++++++++++++-- src/shrpx_log.h | 11 +- src/shrpx_spdy_upstream.cc | 29 ++- src/shrpx_ssl.cc | 5 - src/shrpx_thread_event_receiver.cc | 13 ++ src/shrpx_thread_event_receiver.h | 16 +- src/shrpx_worker.cc | 13 +- src/shrpx_worker.h | 4 +- ...rpx_accesslog.h => shrpx_worker_config.cc} | 20 +- src/shrpx_worker_config.h | 46 +++++ src/util.cc | 14 ++ src/util.h | 5 + 28 files changed, 561 insertions(+), 275 deletions(-) delete mode 100644 src/shrpx_accesslog.cc rename src/{shrpx_accesslog.h => shrpx_worker_config.cc} (76%) create mode 100644 src/shrpx_worker_config.h diff --git a/src/Makefile.am b/src/Makefile.am index 97488022..f6b2612c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -113,7 +113,7 @@ NGHTTPX_SRCS = \ shrpx_ssl.cc shrpx_ssl.h \ shrpx_thread_event_receiver.cc shrpx_thread_event_receiver.h \ shrpx_worker.cc shrpx_worker.h \ - shrpx_accesslog.cc shrpx_accesslog.h + shrpx_worker_config.cc shrpx_worker_config.h if HAVE_SPDYLAY NGHTTPX_SRCS += shrpx_spdy_upstream.cc shrpx_spdy_upstream.h diff --git a/src/shrpx.cc b/src/shrpx.cc index 7303e57a..1659b24c 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -52,6 +53,7 @@ #include "shrpx_config.h" #include "shrpx_listen_handler.h" #include "shrpx_ssl.h" +#include "shrpx_worker_config.h" #include "util.h" #include "app_helper.h" #include "ssl.h" @@ -60,6 +62,10 @@ using namespace nghttp2; namespace shrpx { +namespace { +const int REOPEN_LOG_SIGNAL = SIGUSR1; +} // namespace + namespace { void ssl_acceptcb(evconnlistener *listener, int fd, sockaddr *addr, int addrlen, void *arg) @@ -252,9 +258,28 @@ void save_pid() } } // namespace +namespace { +void reopen_log_signal_cb(evutil_socket_t sig, short events, void *arg) +{ + auto listener_handler = static_cast(arg); + + if(LOG_ENABLED(INFO)) { + LOG(INFO) << "Reopening log files: worker_info(" << &worker_config << ")"; + } + + (void)reopen_log_files(); + + if(get_config()->num_worker > 1) { + listener_handler->worker_reopen_log_files(); + } +} +} // namespace + namespace { int event_loop() { + int rv; + auto evbase = event_base_new(); if(!evbase) { LOG(FATAL) << "event_base_new() failed"; @@ -298,16 +323,47 @@ int event_loop() // After that, we drop the root privileges if needed. drop_privileges(); + sigset_t signals; + sigemptyset(&signals); + sigaddset(&signals, REOPEN_LOG_SIGNAL); + + rv = pthread_sigmask(SIG_BLOCK, &signals, nullptr); + if(rv != 0) { + LOG(ERROR) << "Blocking REOPEN_LOG_SIGNAL failed: " << strerror(rv); + } + if(get_config()->num_worker > 1) { listener_handler->create_worker_thread(get_config()->num_worker); } else if(get_config()->downstream_proto == PROTO_HTTP2) { listener_handler->create_http2_session(); } + rv = pthread_sigmask(SIG_UNBLOCK, &signals, nullptr); + if(rv != 0) { + LOG(ERROR) << "Unblocking REOPEN_LOG_SIGNAL failed: " << strerror(rv); + } + + auto reopen_log_signal_event = evsignal_new(evbase, REOPEN_LOG_SIGNAL, + reopen_log_signal_cb, + listener_handler); + + if(!reopen_log_signal_event) { + LOG(ERROR) << "evsignal_new failed"; + } else { + rv = event_add(reopen_log_signal_event, nullptr); + if(rv < 0) { + LOG(ERROR) << "event_add for reopen_log_signal_event failed"; + } + } + if(LOG_ENABLED(INFO)) { LOG(INFO) << "Entering event loop"; } event_base_loop(evbase, 0); + + if(reopen_log_signal_event) { + event_free(reopen_log_signal_event); + } if(evlistener4) { evconnlistener_free(evlistener4); } @@ -399,11 +455,12 @@ void fill_default_config() mod_config()->http2_max_concurrent_streams = 100; mod_config()->add_x_forwarded_for = false; mod_config()->no_via = false; - mod_config()->accesslog = false; + mod_config()->accesslog_file = nullptr; + mod_config()->accesslog_syslog = false; + mod_config()->errorlog_file = strcopy("/dev/stderr"); + mod_config()->errorlog_syslog = false; mod_config()->conf_path = strcopy("/etc/nghttpx/nghttpx.conf"); - mod_config()->syslog = false; mod_config()->syslog_facility = LOG_DAEMON; - mod_config()->use_syslog = false; // Default accept() backlog mod_config()->backlog = -1; mod_config()->ciphers = nullptr; @@ -419,7 +476,6 @@ void fill_default_config() mod_config()->gid = 0; mod_config()->backend_ipv4 = false; mod_config()->backend_ipv6 = false; - mod_config()->tty = isatty(fileno(stderr)); mod_config()->cert_tree = nullptr; mod_config()->downstream_http_proxy_userinfo = nullptr; mod_config()->downstream_http_proxy_host = nullptr; @@ -719,8 +775,19 @@ Logging: Set the severity level of log output. must be one of INFO, WARNING, ERROR and FATAL. Default: WARNING - --accesslog Print simple accesslog to stderr. - --syslog Send log messages to syslog. + --accesslog-file= + Set path to write access log. To reopen file, + send USR1 signal to nghttpx. + --accesslog-syslog + Send access log to syslog. If this option is + used, --access-file option is ignored. + --errorlog-file= + Set path to write error log. To reopen file, + send USR1 signal to nghttpx. + Default: )" + << get_config()->errorlog_file.get() << R"( + --errorlog-syslog Send error log to syslog. If this option is + used, --errorlog-file option is ignored. --syslog-facility= Set syslog facility to . Default: )" @@ -807,13 +874,12 @@ int main(int argc, char **argv) {"frontend-write-timeout", required_argument, &flag, 4}, {"backend-read-timeout", required_argument, &flag, 5}, {"backend-write-timeout", required_argument, &flag, 6}, - {"accesslog", no_argument, &flag, 7}, + {"accesslog-file", required_argument, &flag, 7}, {"backend-keep-alive-timeout", required_argument, &flag, 8}, {"frontend-http2-window-bits", required_argument, &flag, 9}, {"pid-file", required_argument, &flag, 10}, {"user", required_argument, &flag, 11}, {"conf", required_argument, &flag, 12}, - {"syslog", no_argument, &flag, 13}, {"syslog-facility", required_argument, &flag, 14}, {"backlog", required_argument, &flag, 15}, {"ciphers", required_argument, &flag, 16}, @@ -850,6 +916,9 @@ int main(int argc, char **argv) {"altsvc", required_argument, &flag, 54}, {"add-response-header", required_argument, &flag, 55}, {"worker-frontend-connections", required_argument, &flag, 56}, + {"accesslog-syslog", no_argument, &flag, 57}, + {"errorlog-file", required_argument, &flag, 58}, + {"errorlog-syslog", no_argument, &flag, 59}, {nullptr, 0, nullptr, 0 } }; @@ -930,7 +999,7 @@ int main(int argc, char **argv) cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_WRITE_TIMEOUT, optarg); break; case 7: - cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG, "yes"); + cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_FILE, optarg); break; case 8: // --backend-keep-alive-timeout @@ -950,10 +1019,6 @@ int main(int argc, char **argv) // --conf mod_config()->conf_path = strcopy(optarg); break; - case 13: - // --syslog - cmdcfgs.emplace_back(SHRPX_OPT_SYSLOG, "yes"); - break; case 14: // --syslog-facility cmdcfgs.emplace_back(SHRPX_OPT_SYSLOG_FACILITY, optarg); @@ -1102,6 +1167,18 @@ int main(int argc, char **argv) // --worker-frontend-connections cmdcfgs.emplace_back(SHRPX_OPT_WORKER_FRONTEND_CONNECTIONS, optarg); break; + case 57: + // --accesslog-syslog + cmdcfgs.emplace_back(SHRPX_OPT_ACCESSLOG_SYSLOG, "yes"); + break; + case 58: + // --errorlog-file + cmdcfgs.emplace_back(SHRPX_OPT_ERRORLOG_FILE, optarg); + break; + case 59: + // --errorlog-syslog + cmdcfgs.emplace_back(SHRPX_OPT_ERRORLOG_SYSLOG, "yes"); + break; default: break; } @@ -1140,11 +1217,14 @@ int main(int argc, char **argv) } } - if(get_config()->syslog) { + if(get_config()->accesslog_syslog || get_config()->errorlog_syslog) { openlog("nghttpx", LOG_NDELAY | LOG_NOWAIT | LOG_PID, get_config()->syslog_facility); - mod_config()->use_syslog = true; - mod_config()->tty = false; + } + + if(reopen_log_files() != 0) { + LOG(FATAL) << "Failed to open log file"; + exit(EXIT_FAILURE); } if(get_config()->npn_list.empty()) { diff --git a/src/shrpx_accesslog.cc b/src/shrpx_accesslog.cc deleted file mode 100644 index 34d4f765..00000000 --- a/src/shrpx_accesslog.cc +++ /dev/null @@ -1,146 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2012 Tatsuhiro Tsujikawa - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "shrpx_accesslog.h" - -#include - -#include -#include -#include - -#include "shrpx_config.h" -#include "shrpx_downstream.h" - -namespace shrpx { - -namespace { -std::string get_datestr() -{ - char buf[64]; - time_t now = time(0); - if(ctime_r(&now, buf) == 0) { - buf[0] = '\0'; - } else { - size_t len = strlen(buf); - if(len == 0) { - buf[0] = '\0'; - } else { - buf[strlen(buf)-1] = '\0'; - } - } - return buf; -} -} // namespace - -void upstream_connect(const std::string& client_ip) -{ - if(get_config()->use_syslog) { - syslog(LOG_INFO, "%s ACCEPT\n", client_ip.c_str()); - - return; - } - - fprintf(stderr, "%s [%s] ACCEPT\n", client_ip.c_str(), - get_datestr().c_str()); - - fflush(stderr); -} - -namespace { -const char* status_code_color(unsigned int status_code) -{ - if(status_code <= 199) { - return "\033[1;36m"; - } else if(status_code <= 299) { - return "\033[1;32m"; - } else if(status_code <= 399) { - return "\033[1;34m"; - } else if(status_code <= 499) { - return "\033[1;31m"; - } else if(status_code <= 599) { - return "\033[1;35m"; - } else { - return ""; - } -} -} // namespace - -void upstream_response(const std::string& client_ip, unsigned int status_code, - Downstream *downstream) -{ - if(!downstream) { - if(get_config()->use_syslog) { - syslog(LOG_INFO, "%s %u 0 \"-\"\n", client_ip.c_str(), status_code); - - return; - } - - fprintf(stderr, "%s%s [%s] %u%s 0 \"-\"\n", - get_config()->tty ? status_code_color(status_code) : "", - client_ip.c_str(), get_datestr().c_str(), - status_code, - get_config()->tty ? "\033[0m" : ""); - - fflush(stderr); - - return; - } - - const char *path; - - if(downstream->get_request_path().empty()) { - path = downstream->get_request_http2_authority().c_str(); - } else { - path = downstream->get_request_path().c_str(); - } - - if(get_config()->use_syslog) { - syslog(LOG_INFO, "%s %u %d \"%s %s HTTP/%u.%u\"", - client_ip.c_str(), - status_code, - downstream->get_stream_id(), - downstream->get_request_method().c_str(), - path, - downstream->get_request_major(), - downstream->get_request_minor()); - - return; - } - - fprintf(stderr, "%s [%s] %s%u%s stream(%d) \"%s %s HTTP/%u.%u\"\n", - client_ip.c_str(), get_datestr().c_str(), - get_config()->tty ? status_code_color(status_code) : "", - status_code, - get_config()->tty ? "\033[0m" : "", - downstream->get_stream_id(), - downstream->get_request_method().c_str(), - path, - downstream->get_request_major(), - downstream->get_request_minor()); - - fflush(stderr); -} - -} // namespace shrpx diff --git a/src/shrpx_client_handler.cc b/src/shrpx_client_handler.cc index fe2c790e..8bafd537 100644 --- a/src/shrpx_client_handler.cc +++ b/src/shrpx_client_handler.cc @@ -33,7 +33,6 @@ #include "shrpx_config.h" #include "shrpx_http_downstream_connection.h" #include "shrpx_http2_downstream_connection.h" -#include "shrpx_accesslog.h" #include "shrpx_ssl.h" #include "shrpx_worker.h" #ifdef HAVE_SPDYLAY diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 2b2a35c5..fe16a87a 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -74,7 +74,10 @@ const char SHRPX_OPT_FRONTEND_READ_TIMEOUT[] = "frontend-read-timeout"; const char SHRPX_OPT_FRONTEND_WRITE_TIMEOUT[] = "frontend-write-timeout"; const char SHRPX_OPT_BACKEND_READ_TIMEOUT[] = "backend-read-timeout"; const char SHRPX_OPT_BACKEND_WRITE_TIMEOUT[] = "backend-write-timeout"; -const char SHRPX_OPT_ACCESSLOG[] = "accesslog"; +const char SHRPX_OPT_ACCESSLOG_FILE[] = "accesslog-file"; +const char SHRPX_OPT_ACCESSLOG_SYSLOG[] = "accesslog-syslog"; +const char SHRPX_OPT_ERRORLOG_FILE[] = "errorlog-file"; +const char SHRPX_OPT_ERRORLOG_SYSLOG[] = "errorlog-syslog"; const char SHRPX_OPT_BACKEND_KEEP_ALIVE_TIMEOUT[] = "backend-keep-alive-timeout"; const char @@ -89,7 +92,6 @@ const char SHRPX_OPT_BACKEND_NO_TLS[] = "backend-no-tls"; const char SHRPX_OPT_BACKEND_TLS_SNI_FIELD[] = "backend-tls-sni-field"; const char SHRPX_OPT_PID_FILE[] = "pid-file"; const char SHRPX_OPT_USER[] = "user"; -const char SHRPX_OPT_SYSLOG[] = "syslog"; const char SHRPX_OPT_SYSLOG_FACILITY[] = "syslog-facility"; const char SHRPX_OPT_BACKLOG[] = "backlog"; const char SHRPX_OPT_CIPHERS[] = "ciphers"; @@ -401,8 +403,26 @@ int parse_config(const char *opt, const char *optarg) return 0; } - if(util::strieq(opt, SHRPX_OPT_ACCESSLOG)) { - mod_config()->accesslog = util::strieq(optarg, "yes"); + if(util::strieq(opt, SHRPX_OPT_ACCESSLOG_FILE)) { + mod_config()->accesslog_file = strcopy(optarg); + + return 0; + } + + if(util::strieq(opt, SHRPX_OPT_ACCESSLOG_SYSLOG)) { + mod_config()->accesslog_syslog = util::strieq(optarg, "yes"); + + return 0; + } + + if(util::strieq(opt, SHRPX_OPT_ERRORLOG_FILE)) { + mod_config()->errorlog_file = strcopy(optarg); + + return 0; + } + + if(util::strieq(opt, SHRPX_OPT_ERRORLOG_SYSLOG)) { + mod_config()->errorlog_syslog = util::strieq(optarg, "yes"); return 0; } @@ -540,12 +560,6 @@ int parse_config(const char *opt, const char *optarg) return 0; } - if(util::strieq(opt, SHRPX_OPT_SYSLOG)) { - mod_config()->syslog = util::strieq(optarg, "yes"); - - return 0; - } - if(util::strieq(opt, SHRPX_OPT_SYSLOG_FACILITY)) { int facility = int_syslog_facility(optarg); if(facility == -1) { diff --git a/src/shrpx_config.h b/src/shrpx_config.h index 64657689..4cdbc366 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -70,7 +70,10 @@ extern const char SHRPX_OPT_FRONTEND_READ_TIMEOUT[]; extern const char SHRPX_OPT_FRONTEND_WRITE_TIMEOUT[]; extern const char SHRPX_OPT_BACKEND_READ_TIMEOUT[]; extern const char SHRPX_OPT_BACKEND_WRITE_TIMEOUT[]; -extern const char SHRPX_OPT_ACCESSLOG[]; +extern const char SHRPX_OPT_ACCESSLOG_FILE[]; +extern const char SHRPX_OPT_ACCESSLOG_SYSLOG[]; +extern const char SHRPX_OPT_ERRORLOG_FILE[]; +extern const char SHRPX_OPT_ERRORLOG_SYSLOG[]; extern const char SHRPX_OPT_BACKEND_KEEP_ALIVE_TIMEOUT[]; extern const char SHRPX_OPT_FRONTEND_HTTP2_WINDOW_BITS[]; extern const char SHRPX_OPT_BACKEND_HTTP2_WINDOW_BITS[]; @@ -80,7 +83,6 @@ extern const char SHRPX_OPT_FRONTEND_NO_TLS[]; extern const char SHRPX_OPT_BACKEND_NO_TLS[]; extern const char SHRPX_OPT_PID_FILE[]; extern const char SHRPX_OPT_USER[]; -extern const char SHRPX_OPT_SYSLOG[]; extern const char SHRPX_OPT_SYSLOG_FACILITY[]; extern const char SHRPX_OPT_BACKLOG[]; extern const char SHRPX_OPT_CIPHERS[]; @@ -192,6 +194,8 @@ struct Config { std::unique_ptr verify_client_cacert; std::unique_ptr client_private_key_file; std::unique_ptr client_cert_file; + std::unique_ptr accesslog_file; + std::unique_ptr errorlog_file; FILE *http2_upstream_dump_request_header; FILE *http2_upstream_dump_response_header; nghttp2_option *http2_option; @@ -235,20 +239,18 @@ struct Config { bool client_proxy; bool add_x_forwarded_for; bool no_via; - bool accesslog; bool upstream_no_tls; bool downstream_no_tls; - bool syslog; - // This member finally decides syslog is used or not - bool use_syslog; + // Send accesslog to syslog, ignoring accesslog_file. + bool accesslog_syslog; + // Send errorlog to syslog, ignoring errorlog_file. + bool errorlog_syslog; bool client; // true if --client or --client-proxy are enabled. bool client_mode; bool insecure; bool backend_ipv4; bool backend_ipv6; - // true if stderr refers to a terminal and syslog is not used - bool tty; bool http2_no_cookie_crumbling; bool upstream_frame_debug; }; diff --git a/src/shrpx_downstream.cc b/src/shrpx_downstream.cc index 41c47134..6c1c26b5 100644 --- a/src/shrpx_downstream.cc +++ b/src/shrpx_downstream.cc @@ -40,6 +40,7 @@ namespace shrpx { Downstream::Downstream(Upstream *upstream, int stream_id, int priority) : request_bodylen_(0), + response_bodylen_(0), upstream_(upstream), dconn_(nullptr), response_body_buf_(nullptr), @@ -408,6 +409,16 @@ void Downstream::set_request_connection_close(bool f) request_connection_close_ = f; } +void Downstream::set_request_user_agent(std::string user_agent) +{ + request_user_agent_ = std::move(user_agent); +} + +const std::string& Downstream::get_request_user_agent() const +{ + return request_user_agent_; +} + bool Downstream::get_request_http2_expect_body() const { return request_http2_expect_body_; @@ -675,6 +686,16 @@ evbuffer* Downstream::get_response_body_buf() return response_body_buf_; } +void Downstream::add_response_bodylen(size_t amount) +{ + response_bodylen_ += amount; +} + +int64_t Downstream::get_response_bodylen() const +{ + return response_bodylen_; +} + void Downstream::set_priority(int32_t pri) { priority_ = pri; diff --git a/src/shrpx_downstream.h b/src/shrpx_downstream.h index 91bfd387..c69c53d3 100644 --- a/src/shrpx_downstream.h +++ b/src/shrpx_downstream.h @@ -140,6 +140,8 @@ public: void set_chunked_request(bool f); bool get_request_connection_close() const; void set_request_connection_close(bool f); + void set_request_user_agent(std::string user_agent); + const std::string& get_request_user_agent() const; bool get_request_http2_expect_body() const; void set_request_http2_expect_body(bool f); bool get_expect_100_continue() const; @@ -207,6 +209,8 @@ public: int get_response_state() const; int init_response_body_buf(); evbuffer* get_response_body_buf(); + void add_response_bodylen(size_t amount); + int64_t get_response_bodylen() const; nghttp2_error_code get_response_rst_stream_error_code() const; void set_response_rst_stream_error_code(nghttp2_error_code error_code); // Inspects HTTP/1 response. This checks tranfer-encoding etc. @@ -230,6 +234,7 @@ private: std::string request_method_; std::string request_path_; + std::string request_user_agent_; std::string request_http2_scheme_; std::string request_http2_authority_; std::string assembled_request_cookie_; @@ -237,6 +242,8 @@ private: // the length of request body int64_t request_bodylen_; + // the length of response body + int64_t response_bodylen_; Upstream *upstream_; DownstreamConnection *dconn_; diff --git a/src/shrpx_http.cc b/src/shrpx_http.cc index 8fb0eac2..76c459e0 100644 --- a/src/shrpx_http.cc +++ b/src/shrpx_http.cc @@ -26,6 +26,7 @@ #include "shrpx_config.h" #include "shrpx_log.h" +#include "shrpx_worker_config.h" #include "http2.h" #include "util.h" diff --git a/src/shrpx_http2_downstream_connection.cc b/src/shrpx_http2_downstream_connection.cc index b3e668e5..91dba637 100644 --- a/src/shrpx_http2_downstream_connection.cc +++ b/src/shrpx_http2_downstream_connection.cc @@ -39,6 +39,7 @@ #include "shrpx_error.h" #include "shrpx_http.h" #include "shrpx_http2_session.h" +#include "shrpx_worker_config.h" #include "http2.h" #include "util.h" diff --git a/src/shrpx_http2_session.cc b/src/shrpx_http2_session.cc index 8912c5df..aff15436 100644 --- a/src/shrpx_http2_session.cc +++ b/src/shrpx_http2_session.cc @@ -40,6 +40,7 @@ #include "shrpx_client_handler.h" #include "shrpx_ssl.h" #include "shrpx_http.h" +#include "shrpx_worker_config.h" #include "http2.h" #include "util.h" #include "base64.h" @@ -1120,6 +1121,8 @@ int on_data_chunk_recv_callback(nghttp2_session *session, return 0; } + downstream->add_response_bodylen(len); + auto upstream = downstream->get_upstream(); rv = upstream->on_downstream_body(downstream, data, len, false); if(rv != 0) { diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index a0c88a0f..8464c601 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -35,7 +35,7 @@ #include "shrpx_downstream_connection.h" #include "shrpx_config.h" #include "shrpx_http.h" -#include "shrpx_accesslog.h" +#include "shrpx_worker_config.h" #include "http2.h" #include "util.h" #include "base64.h" @@ -310,6 +310,8 @@ int on_request_headers(Http2Upstream *upstream, auto path = http2::get_unique_header(nva, ":path"); auto method = http2::get_unique_header(nva, ":method"); auto scheme = http2::get_unique_header(nva, ":scheme"); + auto user_agent = http2::get_header(nva, "user-agent"); + bool is_connect = method && "CONNECT" == method->value; bool having_host = http2::non_empty_value(host); bool having_authority = http2::non_empty_value(authority); @@ -345,7 +347,7 @@ int on_request_headers(Http2Upstream *upstream, downstream->set_request_http2_scheme(http2::value_to_str(scheme)); downstream->set_request_http2_authority(http2::value_to_str(authority)); downstream->set_request_path(http2::value_to_str(path)); - + downstream->set_request_user_agent(http2::value_to_str(user_agent)); if(!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) { downstream->set_request_http2_expect_body(true); @@ -1015,6 +1017,10 @@ ssize_t downstream_data_read_callback(nghttp2_session *session, if(!downstream->get_upgraded()) { *data_flags |= NGHTTP2_DATA_FLAG_EOF; + upstream_accesslog(upstream->get_client_handler()->get_ipaddr(), + downstream->get_response_http_status(), + downstream); + if(nghttp2_session_get_stream_remote_close(session, stream_id) == 0) { upstream->rst_stream(downstream, NGHTTP2_NO_ERROR); } @@ -1044,6 +1050,7 @@ int Http2Upstream::error_reply(Downstream *downstream, { int rv; auto html = http::create_error_html(status_code); + downstream->set_response_http_status(status_code); downstream->init_response_body_buf(); auto body = downstream->get_response_body_buf(); rv = evbuffer_add(body, html.c_str(), html.size()); @@ -1073,10 +1080,6 @@ int Http2Upstream::error_reply(Downstream *downstream, << nghttp2_strerror(rv); DIE(); } - if(get_config()->accesslog) { - upstream_response(get_client_handler()->get_ipaddr(), - status_code, downstream); - } return 0; } @@ -1188,10 +1191,10 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) ULOG(FATAL, this) << "nghttp2_submit_response() failed"; return -1; } - if(get_config()->accesslog) { - upstream_response(get_client_handler()->get_ipaddr(), - downstream->get_response_http_status(), - downstream); + + if(downstream->get_upgraded()) { + upstream_accesslog(get_client_handler()->get_ipaddr(), + downstream->get_response_http_status(), downstream); } downstream->clear_response_headers(); diff --git a/src/shrpx_http_downstream_connection.cc b/src/shrpx_http_downstream_connection.cc index d1627919..9d748391 100644 --- a/src/shrpx_http_downstream_connection.cc +++ b/src/shrpx_http_downstream_connection.cc @@ -30,6 +30,7 @@ #include "shrpx_config.h" #include "shrpx_error.h" #include "shrpx_http.h" +#include "shrpx_worker_config.h" #include "http2.h" #include "util.h" @@ -234,7 +235,7 @@ int HttpDownstreamConnection::push_request_headers() if(LOG_ENABLED(INFO)) { const char *hdrp; std::string nhdrs; - if(get_config()->tty) { + if(worker_config.errorlog_tty) { nhdrs = http::colorizeHeaders(hdrs.c_str()); hdrp = nhdrs.c_str(); } else { @@ -492,6 +493,9 @@ namespace { int htp_bodycb(http_parser *htp, const char *data, size_t len) { auto downstream = static_cast(htp->data); + + downstream->add_response_bodylen(len); + return downstream->get_upstream()->on_downstream_body (downstream, reinterpret_cast(data), len, true); } diff --git a/src/shrpx_https_upstream.cc b/src/shrpx_https_upstream.cc index 6864ca76..0dd47b32 100644 --- a/src/shrpx_https_upstream.cc +++ b/src/shrpx_https_upstream.cc @@ -35,7 +35,7 @@ #include "shrpx_http.h" #include "shrpx_config.h" #include "shrpx_error.h" -#include "shrpx_accesslog.h" +#include "shrpx_worker_config.h" #include "http2.h" #include "util.h" @@ -150,8 +150,6 @@ int htp_hdrs_completecb(http_parser *htp) downstream->set_request_connection_close(!http_should_keep_alive(htp)); - downstream->inspect_http1_request(); - if(LOG_ENABLED(INFO)) { std::stringstream ss; ss << downstream->get_request_method() << " " @@ -166,6 +164,15 @@ int htp_hdrs_completecb(http_parser *htp) ULOG(INFO, upstream) << "HTTP request headers\n" << ss.str(); } + downstream->normalize_request_headers(); + auto& nva = downstream->get_request_headers(); + + auto user_agent = http2::get_header(nva, "user-agent"); + + downstream->set_request_user_agent(http2::value_to_str(user_agent)); + + downstream->inspect_http1_request(); + if(get_config()->client_proxy && downstream->get_request_method() != "CONNECT") { // Make sure that request path is an absolute URI. @@ -658,6 +665,12 @@ void https_downstream_eventcb(bufferevent *bev, short events, void *ptr) int HttpsUpstream::error_reply(unsigned int status_code) { auto html = http::create_error_html(status_code); + auto downstream = get_downstream(); + + if(downstream) { + downstream->set_response_http_status(status_code); + } + std::string header; header.reserve(512); header += "HTTP/1.1 "; @@ -677,14 +690,11 @@ int HttpsUpstream::error_reply(unsigned int status_code) ULOG(FATAL, this) << "evbuffer_add() failed"; return -1; } - auto downstream = get_downstream(); + if(downstream) { downstream->set_response_state(Downstream::MSG_COMPLETE); } - if(get_config()->accesslog) { - upstream_response(this->get_client_handler()->get_ipaddr(), status_code, - downstream); - } + return 0; } @@ -811,7 +821,7 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) if(LOG_ENABLED(INFO)) { const char *hdrp; std::string nhdrs; - if(get_config()->tty) { + if(worker_config.errorlog_tty) { nhdrs = http::colorizeHeaders(hdrs.c_str()); hdrp = nhdrs.c_str(); } else { @@ -824,9 +834,10 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) ULOG(FATAL, this) << "evbuffer_add() failed"; return -1; } - if(get_config()->accesslog) { - upstream_response(this->get_client_handler()->get_ipaddr(), - downstream->get_response_http_status(), downstream); + + if(downstream->get_upgraded()) { + upstream_accesslog(this->get_client_handler()->get_ipaddr(), + downstream->get_response_http_status(), downstream); } downstream->clear_response_headers(); @@ -879,6 +890,13 @@ int HttpsUpstream::on_downstream_body_complete(Downstream *downstream) if(LOG_ENABLED(INFO)) { DLOG(INFO, downstream) << "HTTP response completed"; } + + if(!downstream->get_upgraded()) { + upstream_accesslog(get_client_handler()->get_ipaddr(), + downstream->get_response_http_status(), + downstream); + } + if(downstream->get_request_connection_close() || downstream->get_response_connection_close()) { auto handler = get_client_handler(); diff --git a/src/shrpx_listen_handler.cc b/src/shrpx_listen_handler.cc index 5c81ac2f..c6903122 100644 --- a/src/shrpx_listen_handler.cc +++ b/src/shrpx_listen_handler.cc @@ -52,7 +52,6 @@ ListenHandler::ListenHandler(event_base *evbase, SSL_CTX *sv_ssl_ctx, rate_limit_group_(bufferevent_rate_limit_group_new (evbase, get_config()->worker_rate_limit_cfg)), worker_stat_(util::make_unique()), - num_worker_(0), worker_round_robin_cnt_(0) {} @@ -61,22 +60,33 @@ ListenHandler::~ListenHandler() bufferevent_rate_limit_group_free(rate_limit_group_); } +void ListenHandler::worker_reopen_log_files() +{ + WorkerEvent wev; + + memset(&wev, 0, sizeof(wev)); + wev.type = REOPEN_LOG; + + for(auto& info : workers_) { + bufferevent_write(info.bev, &wev, sizeof(wev)); + } +} + void ListenHandler::create_worker_thread(size_t num) { - workers_.resize(num); - num_worker_ = 0; + workers_.resize(0); for(size_t i = 0; i < num; ++i) { int rv; - auto info = &workers_[num_worker_]; - rv = socketpair(AF_UNIX, SOCK_STREAM, 0, info->sv); + auto info = WorkerInfo(); + rv = socketpair(AF_UNIX, SOCK_STREAM, 0, info.sv); if(rv == -1) { LLOG(ERROR, this) << "socketpair() failed: errno=" << errno; continue; } - evutil_make_socket_nonblocking(info->sv[0]); - evutil_make_socket_nonblocking(info->sv[1]); - info->sv_ssl_ctx = sv_ssl_ctx_; - info->cl_ssl_ctx = cl_ssl_ctx_; + evutil_make_socket_nonblocking(info.sv[0]); + evutil_make_socket_nonblocking(info.sv[1]); + info.sv_ssl_ctx = sv_ssl_ctx_; + info.cl_ssl_ctx = cl_ssl_ctx_; try { auto thread = std::thread{start_threaded_worker, info}; thread.detach(); @@ -84,24 +94,26 @@ void ListenHandler::create_worker_thread(size_t num) LLOG(ERROR, this) << "Could not start thread: code=" << error.code() << " msg=" << error.what(); for(size_t j = 0; j < 2; ++j) { - close(info->sv[j]); + close(info.sv[j]); } continue; } - auto bev = bufferevent_socket_new(evbase_, info->sv[0], + auto bev = bufferevent_socket_new(evbase_, info.sv[0], BEV_OPT_DEFER_CALLBACKS); if(!bev) { LLOG(ERROR, this) << "bufferevent_socket_new() failed"; for(size_t j = 0; j < 2; ++j) { - close(info->sv[j]); + close(info.sv[j]); } continue; } - info->bev = bev; + info.bev = bev; + + workers_.push_back(info); + if(LOG_ENABLED(INFO)) { - LLOG(INFO, this) << "Created thread #" << num_worker_; + LLOG(INFO, this) << "Created thread #" << workers_.size() - 1; } - ++num_worker_; } } @@ -111,7 +123,7 @@ int ListenHandler::accept_connection(evutil_socket_t fd, if(LOG_ENABLED(INFO)) { LLOG(INFO, this) << "Accepted connection. fd=" << fd; } - if(num_worker_ == 0) { + if(get_config()->num_worker == 1) { if(worker_stat_->num_connections >= get_config()->worker_frontend_connections) { @@ -138,10 +150,11 @@ int ListenHandler::accept_connection(evutil_socket_t fd, client->set_http2_session(http2session_.get()); return 0; } - size_t idx = worker_round_robin_cnt_ % num_worker_; + size_t idx = worker_round_robin_cnt_ % workers_.size(); ++worker_round_robin_cnt_; WorkerEvent wev; memset(&wev, 0, sizeof(wev)); + wev.type = NEW_CONNECTION; wev.client_fd = fd; memcpy(&wev.client_addr, addr, addrlen); wev.client_addrlen = addrlen; diff --git a/src/shrpx_listen_handler.h b/src/shrpx_listen_handler.h index eba51fc7..97426e4d 100644 --- a/src/shrpx_listen_handler.h +++ b/src/shrpx_listen_handler.h @@ -56,6 +56,7 @@ public: ~ListenHandler(); int accept_connection(evutil_socket_t fd, sockaddr *addr, int addrlen); void create_worker_thread(size_t num); + void worker_reopen_log_files(); event_base* get_evbase() const; int create_http2_session(); private: @@ -70,7 +71,6 @@ private: std::unique_ptr http2session_; bufferevent_rate_limit_group *rate_limit_group_; std::unique_ptr worker_stat_; - size_t num_worker_; unsigned int worker_round_robin_cnt_; }; diff --git a/src/shrpx_log.cc b/src/shrpx_log.cc index 5f12f1a9..e8a4f674 100644 --- a/src/shrpx_log.cc +++ b/src/shrpx_log.cc @@ -25,11 +25,20 @@ #include "shrpx_log.h" #include +#include +#include #include #include +#include +#include #include "shrpx_config.h" +#include "shrpx_downstream.h" +#include "shrpx_worker_config.h" +#include "util.h" + +using namespace nghttp2; namespace shrpx { @@ -48,6 +57,28 @@ const char *SEVERITY_COLOR[] = { }; } // namespace +namespace { +std::string get_datestr() +{ + return ""; + // Format data like this: + // 03/Jul/2014:00:19:38 +0900 + char buf[64]; + struct tm tms; + auto now = time(nullptr); + + if(localtime_r(&now, &tms) == nullptr) { + return ""; + } + + if(strftime(buf, sizeof(buf), "%d/%b/%Y:%T %z", &tms) == 0) { + return ""; + } + + return buf; +} +} // namespace + int Log::severity_thres_ = WARNING; void Log::set_severity_level(int severity) @@ -90,26 +121,163 @@ Log::Log(int severity, const char *filename, int linenum) Log::~Log() { - if(!log_enabled(severity_)) { + int rv; + + if(!log_enabled(severity_) || + (worker_config.errorlog_fd == -1 && !get_config()->errorlog_syslog)) { return; } - if(get_config()->use_syslog) { - syslog(severity_to_syslog_level(severity_), "%s (%s:%d)", - stream_.str().c_str(), filename_, linenum_); + if(get_config()->errorlog_syslog) { + syslog(severity_to_syslog_level(severity_), "[%s] %s (%s:%d)", + SEVERITY_STR[severity_], stream_.str().c_str(), + filename_, linenum_); return; } - fprintf(stderr, "[%s%s%s] %s\n %s(%s:%d)%s\n", - get_config()->tty ? SEVERITY_COLOR[severity_] : "", - SEVERITY_STR[severity_], - get_config()->tty ? "\033[0m" : "", - stream_.str().c_str(), - get_config()->tty ? "\033[1;30m" : "", - filename_, linenum_, - get_config()->tty ? "\033[0m" : ""); - fflush(stderr); + char buf[4096]; + auto tty = worker_config.errorlog_tty; + + rv = snprintf(buf, sizeof(buf), + "%s [%s%s%s] %s\n %s(%s:%d)%s\n", + get_datestr().c_str(), + tty ? SEVERITY_COLOR[severity_] : "", + SEVERITY_STR[severity_], + tty ? "\033[0m" : "", + stream_.str().c_str(), + tty ? "\033[1;30m" : "", + filename_, linenum_, + tty ? "\033[0m" : ""); + + if(rv < 0) { + return; + } + + auto nwrite = std::min(static_cast(rv), sizeof(buf) - 1); + + write(worker_config.errorlog_fd, buf, nwrite); +} + +void upstream_accesslog(const std::string& client_ip, unsigned int status_code, + Downstream *downstream) +{ + if(worker_config.accesslog_fd == -1 && !get_config()->accesslog_syslog) { + return; + } + + char buf[1024]; + int rv; + + const char *path; + const char *method; + unsigned int major, minor; + const char *user_agent; + int64_t response_bodylen; + + if(!downstream) { + path = "-"; + method = "-"; + major = 1; + minor = 0; + user_agent = "-"; + response_bodylen = 0; + } else { + if(downstream->get_request_path().empty()) { + path = downstream->get_request_http2_authority().c_str(); + } else { + path = downstream->get_request_path().c_str(); + } + + method = downstream->get_request_method().c_str(); + major = downstream->get_request_major(); + minor = downstream->get_request_minor(); + user_agent = downstream->get_request_user_agent().c_str(); + response_bodylen = downstream->get_response_bodylen(); + } + + static const char fmt[] = + "%s - - [%s] \"%s %s HTTP/%u.%u\" %u %" PRId64 " \"-\" \"%s\"\n"; + + rv = snprintf(buf, sizeof(buf), fmt, + client_ip.c_str(), + get_datestr().c_str(), + method, + path, + major, + minor, + status_code, + response_bodylen, + user_agent); + + if(rv < 0) { + return; + } + + auto nwrite = std::min(static_cast(rv), sizeof(buf) - 1); + + if(get_config()->accesslog_syslog) { + syslog(LOG_INFO, "%s", buf); + + return; + } + + write(worker_config.accesslog_fd, buf, nwrite); +} + +int reopen_log_files() +{ + int res = 0; + + if(worker_config.accesslog_fd != -1) { + close(worker_config.accesslog_fd); + worker_config.accesslog_fd = -1; + } + + if(!get_config()->accesslog_syslog && get_config()->accesslog_file) { + + worker_config.accesslog_fd = + util::reopen_log_file(get_config()->accesslog_file.get()); + + if(worker_config.accesslog_fd == -1) { + LOG(ERROR) << "Failed to open accesslog file " + << get_config()->accesslog_file.get(); + res = -1; + } + } + + int new_errorlog_fd = -1; + + if(!get_config()->errorlog_syslog && get_config()->errorlog_file) { + + new_errorlog_fd = util::reopen_log_file(get_config()->errorlog_file.get()); + + if(new_errorlog_fd == -1) { + if(worker_config.errorlog_fd != -1) { + LOG(ERROR) << "Failed to open errorlog file " + << get_config()->errorlog_file.get(); + } else { + std::cerr << "Failed to open errorlog file " + << get_config()->errorlog_file.get() + << std::endl; + } + + res = -1; + } + } + + if(worker_config.errorlog_fd != -1) { + close(worker_config.errorlog_fd); + worker_config.errorlog_fd = -1; + worker_config.errorlog_tty = false; + } + + if(new_errorlog_fd != -1) { + worker_config.errorlog_fd = new_errorlog_fd; + worker_config.errorlog_tty = isatty(worker_config.errorlog_fd); + } + + return res; } } // namespace shrpx diff --git a/src/shrpx_log.h b/src/shrpx_log.h index dd8e1c54..ddf5dc1f 100644 --- a/src/shrpx_log.h +++ b/src/shrpx_log.h @@ -31,6 +31,8 @@ namespace shrpx { +class Downstream; + #define ENABLE_LOG 1 #define LOG_ENABLED(SEVERITY) (ENABLE_LOG && Log::log_enabled(SEVERITY)) @@ -95,8 +97,13 @@ private: static int severity_thres_; }; -#define TTY_HTTP_HD (get_config()->tty ? "\033[1;34m" : "") -#define TTY_RST (get_config()->tty ? "\033[0m" : "") +#define TTY_HTTP_HD (worker_config.errorlog_tty ? "\033[1;34m" : "") +#define TTY_RST (worker_config.errorlog_tty ? "\033[0m" : "") + +void upstream_accesslog(const std::string& client_ip, unsigned int status_code, + Downstream *downstream); + +int reopen_log_files(); } // namespace shrpx diff --git a/src/shrpx_spdy_upstream.cc b/src/shrpx_spdy_upstream.cc index f5485231..4032004f 100644 --- a/src/shrpx_spdy_upstream.cc +++ b/src/shrpx_spdy_upstream.cc @@ -36,7 +36,7 @@ #include "shrpx_downstream_connection.h" #include "shrpx_config.h" #include "shrpx_http.h" -#include "shrpx_accesslog.h" +#include "shrpx_worker_config.h" #include "http2.h" #include "util.h" @@ -164,7 +164,9 @@ void on_ctrl_recv_callback const char *scheme = nullptr; const char *host = nullptr; const char *method = nullptr; - const char *content_length = 0; + const char *content_length = nullptr; + const char *user_agent = nullptr; + for(size_t i = 0; nv[i]; i += 2) { if(strcmp(nv[i], ":path") == 0) { path = nv[i+1]; @@ -177,6 +179,8 @@ void on_ctrl_recv_callback } else if(nv[i][0] != ':') { if(strcmp(nv[i], "content-length") == 0) { content_length = nv[i+1]; + } else if(strcmp(nv[i], "user-agent") == 0) { + user_agent = nv[i+1]; } downstream->add_request_header(nv[i], nv[i+1]); } @@ -204,6 +208,10 @@ void on_ctrl_recv_callback downstream->set_request_path(path); } + if(user_agent) { + downstream->set_request_user_agent(user_agent); + } + if(!(frame->syn_stream.hd.flags & SPDYLAY_CTRL_FLAG_FIN)) { downstream->set_request_http2_expect_body(true); } @@ -773,6 +781,9 @@ ssize_t spdy_data_read_callback(spdylay_session *session, downstream->get_response_state() == Downstream::MSG_COMPLETE) { if(!downstream->get_upgraded()) { *eof = 1; + + upstream_accesslog(upstream->get_client_handler()->get_ipaddr(), + downstream->get_response_http_status(), downstream); } else { // For tunneling, issue RST_STREAM to finish the stream. if(LOG_ENABLED(INFO)) { @@ -800,6 +811,7 @@ int SpdyUpstream::error_reply(Downstream *downstream, unsigned int status_code) { int rv; auto html = http::create_error_html(status_code); + downstream->set_response_http_status(status_code); downstream->init_response_body_buf(); auto body = downstream->get_response_body_buf(); rv = evbuffer_add(body, html.c_str(), html.size()); @@ -831,10 +843,7 @@ int SpdyUpstream::error_reply(Downstream *downstream, unsigned int status_code) << spdylay_strerror(rv); DIE(); } - if(get_config()->accesslog) { - upstream_response(get_client_handler()->get_ipaddr(), - status_code, downstream); - } + return 0; } @@ -949,10 +958,10 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) ULOG(FATAL, this) << "spdylay_submit_response() failed"; return -1; } - if(get_config()->accesslog) { - upstream_response(get_client_handler()->get_ipaddr(), - downstream->get_response_http_status(), - downstream); + + if(downstream->get_upgraded()) { + upstream_accesslog(get_client_handler()->get_ipaddr(), + downstream->get_response_http_status(), downstream); } downstream->clear_response_headers(); diff --git a/src/shrpx_ssl.cc b/src/shrpx_ssl.cc index e6273fa9..2155aaf8 100644 --- a/src/shrpx_ssl.cc +++ b/src/shrpx_ssl.cc @@ -48,7 +48,6 @@ #include "shrpx_log.h" #include "shrpx_client_handler.h" #include "shrpx_config.h" -#include "shrpx_accesslog.h" #include "shrpx_worker.h" #include "util.h" #include "ssl.h" @@ -476,10 +475,6 @@ ClientHandler* accept_connection return nullptr; } - if(get_config()->accesslog) { - upstream_connect(host); - } - int val = 1; rv = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&val), sizeof(val)); diff --git a/src/shrpx_thread_event_receiver.cc b/src/shrpx_thread_event_receiver.cc index 9a86df05..23c352c2 100644 --- a/src/shrpx_thread_event_receiver.cc +++ b/src/shrpx_thread_event_receiver.cc @@ -31,6 +31,7 @@ #include "shrpx_client_handler.h" #include "shrpx_http2_session.h" #include "shrpx_worker.h" +#include "shrpx_worker_config.h" #include "util.h" using namespace nghttp2; @@ -68,6 +69,18 @@ void ThreadEventReceiver::on_read(bufferevent *bev) << sizeof(wev) << " Actual:" << nread; continue; } + + if(wev.type == REOPEN_LOG) { + if(LOG_ENABLED(INFO)) { + LOG(INFO) << "Reopening log files: worker_info(" + << &worker_config << ")"; + } + + reopen_log_files(); + + continue; + } + if(LOG_ENABLED(INFO)) { TLOG(INFO, this) << "WorkerEvent: client_fd=" << wev.client_fd << ", addrlen=" << wev.client_addrlen; diff --git a/src/shrpx_thread_event_receiver.h b/src/shrpx_thread_event_receiver.h index 8c361582..a5e02f5a 100644 --- a/src/shrpx_thread_event_receiver.h +++ b/src/shrpx_thread_event_receiver.h @@ -40,10 +40,20 @@ namespace shrpx { class Http2Session; struct WorkerStat; +enum WorkerEventType { + NEW_CONNECTION = 0x01, + REOPEN_LOG = 0x02 +}; + struct WorkerEvent { - sockaddr_union client_addr; - size_t client_addrlen; - evutil_socket_t client_fd; + WorkerEventType type; + union { + struct { + sockaddr_union client_addr; + size_t client_addrlen; + evutil_socket_t client_fd; + }; + }; }; class ThreadEventReceiver { diff --git a/src/shrpx_worker.cc b/src/shrpx_worker.cc index e0fca922..5219fa0a 100644 --- a/src/shrpx_worker.cc +++ b/src/shrpx_worker.cc @@ -36,16 +36,17 @@ #include "shrpx_thread_event_receiver.h" #include "shrpx_log.h" #include "shrpx_http2_session.h" +#include "shrpx_worker_config.h" #include "util.h" using namespace nghttp2; namespace shrpx { -Worker::Worker(WorkerInfo *info) - : sv_ssl_ctx_(info->sv_ssl_ctx), - cl_ssl_ctx_(info->cl_ssl_ctx), - fd_(info->sv[1]) +Worker::Worker(const WorkerInfo& info) + : sv_ssl_ctx_(info.sv_ssl_ctx), + cl_ssl_ctx_(info.cl_ssl_ctx), + fd_(info.sv[1]) {} Worker::~Worker() @@ -76,6 +77,8 @@ void eventcb(bufferevent *bev, short events, void *arg) void Worker::run() { + (void)reopen_log_files(); + auto evbase = std::unique_ptr (event_base_new(), event_base_free); if(!evbase) { @@ -105,7 +108,7 @@ void Worker::run() event_base_loop(evbase.get(), 0); } -void start_threaded_worker(WorkerInfo *info) +void start_threaded_worker(WorkerInfo info) { Worker worker(info); worker.run(); diff --git a/src/shrpx_worker.h b/src/shrpx_worker.h index 38d863f1..a766e192 100644 --- a/src/shrpx_worker.h +++ b/src/shrpx_worker.h @@ -42,7 +42,7 @@ struct WorkerStat { class Worker { public: - Worker(WorkerInfo *info); + Worker(const WorkerInfo& info); ~Worker(); void run(); private: @@ -52,7 +52,7 @@ private: int fd_; }; -void start_threaded_worker(WorkerInfo *info); +void start_threaded_worker(WorkerInfo info); } // namespace shrpx diff --git a/src/shrpx_accesslog.h b/src/shrpx_worker_config.cc similarity index 76% rename from src/shrpx_accesslog.h rename to src/shrpx_worker_config.cc index ac08f10d..f20ac7db 100644 --- a/src/shrpx_accesslog.h +++ b/src/shrpx_worker_config.cc @@ -1,7 +1,7 @@ /* * nghttp2 - HTTP/2 C Library * - * Copyright (c) 2012 Tatsuhiro Tsujikawa + * Copyright (c) 2014 Tatsuhiro Tsujikawa * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -22,21 +22,17 @@ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef SHRPX_ACCESSLOG_H -#define SHRPX_ACCESSLOG_H - -#include "shrpx.h" - -#include +#include "shrpx_worker_config.h" namespace shrpx { -class Downstream; +WorkerConfig::WorkerConfig() + : accesslog_fd(-1), + errorlog_fd(-1), + errorlog_tty(false) +{} -void upstream_connect(const std::string& client_ip); -void upstream_response(const std::string& client_ip, unsigned int status_code, - Downstream *downstream); +thread_local WorkerConfig worker_config; } // namespace shrpx -#endif // SHRPX_LOG_H diff --git a/src/shrpx_worker_config.h b/src/shrpx_worker_config.h new file mode 100644 index 00000000..416c67f8 --- /dev/null +++ b/src/shrpx_worker_config.h @@ -0,0 +1,46 @@ +/* + * nghttp2 - HTTP/2 C Library + * + * Copyright (c) 2014 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef SHRPX_WORKER_CONFIG_H +#define SHRPX_WORKER_CONFIG_H + +#include "shrpx.h" + +namespace shrpx { + +struct WorkerConfig { + int accesslog_fd; + int errorlog_fd; + // true if errorlog_fd is referring to a terminal. + bool errorlog_tty; + + WorkerConfig(); +}; + +// We need WorkerConfig per thread +extern thread_local WorkerConfig worker_config; + +} // namespace shrpx + +#endif // SHRPX_WORKER_CONFIG_H diff --git a/src/util.cc b/src/util.cc index 59bf12a6..4100d055 100644 --- a/src/util.cc +++ b/src/util.cc @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include @@ -585,6 +587,18 @@ bool numeric_host(const char *hostname) return true; } +int reopen_log_file(const char *path) +{ + auto fd = open(path, O_WRONLY | O_APPEND | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + if(fd == -1) { + return -1; + } + + return fd; +} + } // namespace util } // namespace nghttp2 diff --git a/src/util.h b/src/util.h index 2c5f9362..0f7771c6 100644 --- a/src/util.h +++ b/src/util.h @@ -478,6 +478,11 @@ private: bool numeric_host(const char *hostname); +// Opens |path| with O_APPEND enabled. If file does not exist, it is +// created first. This function returns file descriptor referring the +// opened file if it succeeds, or -1. +int reopen_log_file(const char *path); + } // namespace util } // namespace nghttp2