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.
This commit is contained in:
parent
57230b4029
commit
0ce848a611
|
@ -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
|
||||
|
|
112
src/shrpx.cc
112
src/shrpx.cc
|
@ -35,6 +35,7 @@
|
|||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <syslog.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <limits>
|
||||
#include <cstdlib>
|
||||
|
@ -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<ListenHandler*>(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. <LEVEL>
|
||||
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=<PATH>
|
||||
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=<PATH>
|
||||
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=<FACILITY>
|
||||
Set syslog facility to <FACILITY>.
|
||||
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()) {
|
||||
|
|
|
@ -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 <syslog.h>
|
||||
|
||||
#include <ctime>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#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
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<char[]> verify_client_cacert;
|
||||
std::unique_ptr<char[]> client_private_key_file;
|
||||
std::unique_ptr<char[]> client_cert_file;
|
||||
std::unique_ptr<char[]> accesslog_file;
|
||||
std::unique_ptr<char[]> 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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "shrpx_config.h"
|
||||
#include "shrpx_log.h"
|
||||
#include "shrpx_worker_config.h"
|
||||
#include "http2.h"
|
||||
#include "util.h"
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<Downstream*>(htp->data);
|
||||
|
||||
downstream->add_response_bodylen(len);
|
||||
|
||||
return downstream->get_upstream()->on_downstream_body
|
||||
(downstream, reinterpret_cast<const uint8_t*>(data), len, true);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<WorkerStat>()),
|
||||
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;
|
||||
|
|
|
@ -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> http2session_;
|
||||
bufferevent_rate_limit_group *rate_limit_group_;
|
||||
std::unique_ptr<WorkerStat> worker_stat_;
|
||||
size_t num_worker_;
|
||||
unsigned int worker_round_robin_cnt_;
|
||||
};
|
||||
|
||||
|
|
194
src/shrpx_log.cc
194
src/shrpx_log.cc
|
@ -25,11 +25,20 @@
|
|||
#include "shrpx_log.h"
|
||||
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
#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<size_t>(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<size_t>(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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<char *>(&val), sizeof(val));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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, decltype(&event_base_free)>
|
||||
(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();
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 <stdint.h>
|
||||
#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
|
|
@ -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
|
14
src/util.cc
14
src/util.cc
|
@ -28,6 +28,8 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue