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