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:
Tatsuhiro Tsujikawa 2014-07-05 18:22:40 +09:00
parent 57230b4029
commit 0ce848a611
28 changed files with 561 additions and 275 deletions

View File

@ -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

View File

@ -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()) {

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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;
};

View File

@ -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;

View File

@ -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_;

View File

@ -26,6 +26,7 @@
#include "shrpx_config.h"
#include "shrpx_log.h"
#include "shrpx_worker_config.h"
#include "http2.h"
#include "util.h"

View File

@ -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"

View File

@ -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) {

View File

@ -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();

View File

@ -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);
}

View File

@ -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();

View File

@ -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;

View File

@ -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_;
};

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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));

View File

@ -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;

View File

@ -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 {

View File

@ -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();

View File

@ -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

View File

@ -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

46
src/shrpx_worker_config.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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