diff --git a/runtime/interface.cpp b/runtime/interface.cpp index 7cf80c0400..2e1caaac16 100644 --- a/runtime/interface.cpp +++ b/runtime/interface.cpp @@ -346,6 +346,10 @@ static void header(const char* str, int str_len, bool replace = true, int http_r } } +int& get_http_return_code() noexcept { + return http_return_code; +} + void f$header(const string& str, bool replace, int64_t http_response_code) { header(str.c_str(), (int)str.size(), replace, static_cast(http_response_code)); } diff --git a/runtime/interface.h b/runtime/interface.h index 5cedcad033..6b87dc3ae2 100644 --- a/runtime/interface.h +++ b/runtime/interface.h @@ -52,6 +52,8 @@ Optional& get_dummy_headers_sent_filename() noexcept; Optional& get_dummy_headers_sent_line() noexcept; bool f$headers_sent(Optional& filename = get_dummy_headers_sent_filename(), Optional& line = get_dummy_headers_sent_line()); +int& get_http_return_code() noexcept; + void f$header(const string& str, bool replace = true, int64_t http_response_code = 0); array f$headers_list(); diff --git a/server/php-engine.cpp b/server/php-engine.cpp index ab6221f29f..7a321574f7 100644 --- a/server/php-engine.cpp +++ b/server/php-engine.cpp @@ -490,6 +490,7 @@ void http_return(connection *c, const char *str, int len) { if (len < 0) { len = (int)strlen(str); } + get_http_return_code() = 500; write_basic_http_header(c, 500, 0, len, no_cache_headers, "text/plain; charset=UTF-8"); write_out(&c->Out, str, len); } diff --git a/server/statshouse/statshouse-manager.cpp b/server/statshouse/statshouse-manager.cpp index 30ea442d36..a1af3a1806 100644 --- a/server/statshouse/statshouse-manager.cpp +++ b/server/statshouse/statshouse-manager.cpp @@ -17,6 +17,7 @@ #include "common/resolver.h" #include "common/wrappers/overloaded.h" #include "runtime/instance-cache.h" +#include "runtime/interface.h" #include "runtime/runtime-builtin-stats.h" #include "server/confdata-stats.h" #include "server/job-workers/shared-memory-manager.h" @@ -126,7 +127,7 @@ void StatsHouseManager::add_request_stats(uint64_t script_time_ns, uint64_t net_ client.metric("kphp_request_cpu_time").tag("system").tag(worker_type).tag(status).write_value(script_system_time_ns); client.metric("kphp_request_init_time").tag(worker_type).tag(status).write_value(script_init_time); if (process_type == ProcessType::http_worker) { - client.metric("kphp_http_connection_process_time").tag(status).write_value(http_connection_process_time); + client.metric("kphp_http_connection_process_time").tag("return_code", std::to_string(get_http_return_code())).tag(status).write_value(http_connection_process_time); } client.metric("kphp_by_host_request_time", true).tag("script").tag(worker_type).write_value(script_time_ns); @@ -135,7 +136,7 @@ void StatsHouseManager::add_request_stats(uint64_t script_time_ns, uint64_t net_ client.metric("kphp_by_host_request_cpu_time", true).tag("system").tag(worker_type).tag(status).write_value(script_system_time_ns); client.metric("kphp_by_host_request_init_time", true).tag(worker_type).tag(status).write_value(script_init_time); if (process_type == ProcessType::http_worker) { - client.metric("kphp_by_host_http_connection_process_time", true).tag(status).write_value(http_connection_process_time); + client.metric("kphp_by_host_http_connection_process_time", true).tag("return_code", std::to_string(get_http_return_code())).tag(status).write_value(http_connection_process_time); } if (error != script_error_t::no_error) { diff --git a/third-party/statshouse.h b/third-party/statshouse.h index 83acec13e1..6046b627d1 100644 --- a/third-party/statshouse.h +++ b/third-party/statshouse.h @@ -442,7 +442,16 @@ class TransportUDPBase { return 0; // if even more tags added, we do not care, so empty string is good enough. return names[i]; } - static char * pack_string(char * begin, const char * end, const char * str, size_t len) { + // GCC 8 inlines copies of this function into the caller and merges them + // (cross-jumping), after which it loses the relation between `len` and the + // source object and emits false positive -Warray-bounds for small string + // literals. noinline prevents the merge and keeps each call analyzable. +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 8 +#define STATSHOUSE_PACK_STRING_NOINLINE __attribute__((noinline)) +#else +#define STATSHOUSE_PACK_STRING_NOINLINE +#endif + static STATSHOUSE_PACK_STRING_NOINLINE char * pack_string(char * begin, const char * end, const char * str, size_t len) { if (STATSHOUSE_UNLIKELY(len > TL_MAX_TINY_STRING_LEN)) { if (STATSHOUSE_UNLIKELY(len > TL_BIG_STRING_LEN)) { len = TL_BIG_STRING_LEN; @@ -467,6 +476,7 @@ class TransportUDPBase { } return begin; } +#undef STATSHOUSE_PACK_STRING_NOINLINE char * pack_header(uint32_t now, size_t min_space, const MetricBuilder & metric, double counter, uint32_t tsUnixSec, size_t fields_mask) { if (STATSHOUSE_UNLIKELY(metric.did_not_fit)) {