Perfetto tracing for /ok. Header parsing not complete
This commit is contained in:
@@ -136,8 +136,14 @@ set(SOURCES
|
|||||||
|
|
||||||
add_executable(weaseldb ${SOURCES})
|
add_executable(weaseldb ${SOURCES})
|
||||||
add_dependencies(weaseldb generate_json_tokens)
|
add_dependencies(weaseldb generate_json_tokens)
|
||||||
target_link_libraries(weaseldb Threads::Threads toml11::toml11 weaseljson
|
target_link_libraries(
|
||||||
simdutf::simdutf llhttp_static)
|
weaseldb
|
||||||
|
Threads::Threads
|
||||||
|
toml11::toml11
|
||||||
|
weaseljson
|
||||||
|
simdutf::simdutf
|
||||||
|
llhttp_static
|
||||||
|
perfetto)
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
@@ -165,7 +171,7 @@ add_executable(
|
|||||||
test_http_handler tests/test_http_handler.cpp src/http_handler.cpp
|
test_http_handler tests/test_http_handler.cpp src/http_handler.cpp
|
||||||
src/arena_allocator.cpp src/connection.cpp)
|
src/arena_allocator.cpp src/connection.cpp)
|
||||||
target_link_libraries(test_http_handler doctest::doctest llhttp_static
|
target_link_libraries(test_http_handler doctest::doctest llhttp_static
|
||||||
Threads::Threads)
|
Threads::Threads perfetto)
|
||||||
target_include_directories(test_http_handler PRIVATE src)
|
target_include_directories(test_http_handler PRIVATE src)
|
||||||
target_compile_definitions(test_http_handler
|
target_compile_definitions(test_http_handler
|
||||||
PRIVATE DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN)
|
PRIVATE DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "http_handler.hpp"
|
#include "http_handler.hpp"
|
||||||
#include "arena_allocator.hpp"
|
#include "arena_allocator.hpp"
|
||||||
|
#include "perfetto_categories.hpp"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
@@ -213,6 +214,8 @@ void HttpHandler::handleGetMetrics(Connection &conn,
|
|||||||
|
|
||||||
void HttpHandler::handleGetOk(Connection &conn,
|
void HttpHandler::handleGetOk(Connection &conn,
|
||||||
const HttpConnectionState &state) {
|
const HttpConnectionState &state) {
|
||||||
|
TRACE_EVENT("http", "GET /ok", perfetto::Flow::Global(state.request_id));
|
||||||
|
|
||||||
sendResponse(conn, 200, "text/plain", "OK", state.connection_close);
|
sendResponse(conn, 200, "text/plain", "OK", state.connection_close);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,6 +257,8 @@ void HttpHandler::sendResponse(Connection &conn, int status_code,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto *state = static_cast<HttpConnectionState *>(conn.user_data);
|
||||||
|
|
||||||
response += "\r\n";
|
response += "\r\n";
|
||||||
response += "Content-Type: ";
|
response += "Content-Type: ";
|
||||||
response += content_type;
|
response += content_type;
|
||||||
@@ -261,6 +266,9 @@ void HttpHandler::sendResponse(Connection &conn, int status_code,
|
|||||||
response += "Content-Length: ";
|
response += "Content-Length: ";
|
||||||
response += std::to_string(body.size());
|
response += std::to_string(body.size());
|
||||||
response += "\r\n";
|
response += "\r\n";
|
||||||
|
response += "X-Response-ID: ";
|
||||||
|
response += std::to_string(state->request_id);
|
||||||
|
response += "\r\n";
|
||||||
|
|
||||||
if (close_connection) {
|
if (close_connection) {
|
||||||
response += "Connection: close\r\n";
|
response += "Connection: close\r\n";
|
||||||
@@ -322,6 +330,20 @@ int HttpHandler::onHeaderValue(llhttp_t *parser, const char *at,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for X-Request-Id header
|
||||||
|
if (state->current_header_field.size() == 12 &&
|
||||||
|
strncasecmp(state->current_header_field.data(), "x-request-id", 12) ==
|
||||||
|
0) {
|
||||||
|
uint64_t id = 0;
|
||||||
|
for (int i = 0; i < int(length); ++i) {
|
||||||
|
auto c = at[i];
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
id = id * 10 + (c - '0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state->request_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,4 +370,4 @@ int HttpHandler::onMessageComplete(llhttp_t *parser) {
|
|||||||
auto *state = static_cast<HttpConnectionState *>(parser->data);
|
auto *state = static_cast<HttpConnectionState *>(parser->data);
|
||||||
state->message_complete = true;
|
state->message_complete = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ struct HttpConnectionState {
|
|||||||
bool connection_close = false; // Client requested connection close
|
bool connection_close = false; // Client requested connection close
|
||||||
HttpRoute route = HttpRoute::NotFound;
|
HttpRoute route = HttpRoute::NotFound;
|
||||||
std::string_view current_header_field; // Current header being parsed
|
std::string_view current_header_field; // Current header being parsed
|
||||||
|
uint64_t request_id = 0; // X-Request-Id header value
|
||||||
|
|
||||||
explicit HttpConnectionState(ArenaAllocator &arena);
|
explicit HttpConnectionState(ArenaAllocator &arena);
|
||||||
};
|
};
|
||||||
@@ -95,4 +96,4 @@ private:
|
|||||||
static void sendErrorResponse(Connection &conn, int status_code,
|
static void sendErrorResponse(Connection &conn, int status_code,
|
||||||
std::string_view message,
|
std::string_view message,
|
||||||
bool close_connection = false);
|
bool close_connection = false);
|
||||||
};
|
};
|
||||||
|
|||||||
10
src/main.cpp
10
src/main.cpp
@@ -2,11 +2,14 @@
|
|||||||
#include "connection.hpp"
|
#include "connection.hpp"
|
||||||
#include "connection_handler.hpp"
|
#include "connection_handler.hpp"
|
||||||
#include "http_handler.hpp"
|
#include "http_handler.hpp"
|
||||||
|
#include "perfetto_categories.hpp"
|
||||||
#include "server.hpp"
|
#include "server.hpp"
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
PERFETTO_TRACK_EVENT_STATIC_STORAGE();
|
||||||
|
|
||||||
// TODO this should be scoped to a particular Server, and it's definition should
|
// TODO this should be scoped to a particular Server, and it's definition should
|
||||||
// be in server.cpp or connection.cpp
|
// be in server.cpp or connection.cpp
|
||||||
std::atomic<int> activeConnections{0};
|
std::atomic<int> activeConnections{0};
|
||||||
@@ -41,6 +44,13 @@ void print_help(const char *program_name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
#if ENABLE_PERFETTO
|
||||||
|
perfetto::TracingInitArgs args;
|
||||||
|
args.backends |= perfetto::kSystemBackend;
|
||||||
|
perfetto::Tracing::Initialize(args);
|
||||||
|
perfetto::TrackEvent::Register();
|
||||||
|
#endif
|
||||||
|
|
||||||
std::string config_file = "config.toml";
|
std::string config_file = "config.toml";
|
||||||
|
|
||||||
// Parse command line arguments
|
// Parse command line arguments
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
#include "arena_allocator.hpp"
|
#include "arena_allocator.hpp"
|
||||||
#include "http_handler.hpp"
|
#include "http_handler.hpp"
|
||||||
|
#include "perfetto_categories.hpp"
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <doctest/doctest.h>
|
#include <doctest/doctest.h>
|
||||||
|
|
||||||
|
// Perfetto static storage for tests
|
||||||
|
PERFETTO_TRACK_EVENT_STATIC_STORAGE();
|
||||||
|
|
||||||
// Global variable needed by Connection
|
// Global variable needed by Connection
|
||||||
std::atomic<int> activeConnections{0};
|
std::atomic<int> activeConnections{0};
|
||||||
|
|
||||||
@@ -34,6 +38,7 @@ TEST_CASE("HttpHandler route parsing") {
|
|||||||
CHECK(HttpHandler::parseRoute("GET", "/v1/retention") ==
|
CHECK(HttpHandler::parseRoute("GET", "/v1/retention") ==
|
||||||
HttpRoute::GET_retention);
|
HttpRoute::GET_retention);
|
||||||
CHECK(HttpHandler::parseRoute("GET", "/metrics") == HttpRoute::GET_metrics);
|
CHECK(HttpHandler::parseRoute("GET", "/metrics") == HttpRoute::GET_metrics);
|
||||||
|
CHECK(HttpHandler::parseRoute("GET", "/ok") == HttpRoute::GET_ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
SUBCASE("POST routes") {
|
SUBCASE("POST routes") {
|
||||||
|
|||||||
@@ -23,22 +23,8 @@
|
|||||||
|
|
||||||
#include <llhttp.h>
|
#include <llhttp.h>
|
||||||
|
|
||||||
#ifndef __has_feature
|
// Use shared perfetto categories
|
||||||
#define __has_feature(x) 0
|
#include "../src/perfetto_categories.hpp"
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ENABLE_PERFETTO 1
|
|
||||||
|
|
||||||
#if ENABLE_PERFETTO
|
|
||||||
#include <perfetto.h>
|
|
||||||
#else
|
|
||||||
#define PERFETTO_DEFINE_CATEGORIES(...)
|
|
||||||
#define PERFETTO_TRACK_EVENT_STATIC_STORAGE(...)
|
|
||||||
#define TRACE_EVENT(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PERFETTO_DEFINE_CATEGORIES(
|
|
||||||
perfetto::Category("network").SetDescription("Network"));
|
|
||||||
|
|
||||||
PERFETTO_TRACK_EVENT_STATIC_STORAGE();
|
PERFETTO_TRACK_EVENT_STATIC_STORAGE();
|
||||||
|
|
||||||
@@ -264,7 +250,7 @@ struct Connection {
|
|||||||
request = request.substr(w, request.size() - w);
|
request = request.substr(w, request.size() - w);
|
||||||
if (request.empty()) {
|
if (request.empty()) {
|
||||||
++requestsSent;
|
++requestsSent;
|
||||||
TRACE_EVENT("network", "send request",
|
TRACE_EVENT("http", "Send request",
|
||||||
perfetto::Flow::Global(currentRequestId));
|
perfetto::Flow::Global(currentRequestId));
|
||||||
if (requestsSent == g_config.requests_per_connection) {
|
if (requestsSent == g_config.requests_per_connection) {
|
||||||
return true;
|
return true;
|
||||||
@@ -307,8 +293,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int on_message_complete() {
|
int on_message_complete() {
|
||||||
TRACE_EVENT("network", "receive response",
|
TRACE_EVENT("http", "Receive response", perfetto::Flow::Global(responseId));
|
||||||
perfetto::Flow::Global(responseId));
|
|
||||||
responseId = 0;
|
responseId = 0;
|
||||||
++responsesReceived;
|
++responsesReceived;
|
||||||
initRequest();
|
initRequest();
|
||||||
|
|||||||
Reference in New Issue
Block a user