86 lines
3.3 KiB
C++
86 lines
3.3 KiB
C++
#pragma once
|
|
|
|
#include <drogon/drogon.h>
|
|
|
|
#include <chrono>
|
|
#include <cstddef>
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
class Access_Logger {
|
|
public:
|
|
static void log(const drogon::HttpRequestPtr& request,
|
|
const drogon::HttpResponsePtr& response,
|
|
const double elapsed_ms) {
|
|
std::cout << "[http access] method=" << request->methodString()
|
|
<< ", path=" << request->path()
|
|
<< ", status=" << static_cast<int>(response->statusCode())
|
|
<< ", cost_ms=" << elapsed_ms << std::endl;
|
|
}
|
|
};
|
|
|
|
class Slow_Request_Monitor {
|
|
public:
|
|
static void log_if_slow(const drogon::HttpRequestPtr& request,
|
|
const drogon::HttpResponsePtr& response,
|
|
const double elapsed_ms,
|
|
const std::size_t threshold_ms) {
|
|
if (elapsed_ms < static_cast<double>(threshold_ms)) return;
|
|
std::cout << "[slow http request] method=" << request->methodString()
|
|
<< ", path=" << request->path()
|
|
<< ", status=" << static_cast<int>(response->statusCode())
|
|
<< ", cost_ms=" << elapsed_ms
|
|
<< ", threshold_ms=" << threshold_ms << std::endl;
|
|
}
|
|
};
|
|
|
|
class Scope_Timer {
|
|
public:
|
|
Scope_Timer(std::string name, const std::size_t threshold_ms)
|
|
: name_(std::move(name)),
|
|
threshold_ms_(threshold_ms),
|
|
start_(std::chrono::steady_clock::now()) {}
|
|
|
|
~Scope_Timer() {
|
|
const auto elapsed_ms =
|
|
std::chrono::duration<double, std::milli>(
|
|
std::chrono::steady_clock::now() - start_).count();
|
|
if (elapsed_ms < static_cast<double>(threshold_ms_)) return;
|
|
std::cout << "[slow scope] name=" << name_
|
|
<< ", cost_ms=" << elapsed_ms
|
|
<< ", threshold_ms=" << threshold_ms_ << std::endl;
|
|
}
|
|
|
|
private:
|
|
std::string name_;
|
|
std::size_t threshold_ms_;
|
|
std::chrono::steady_clock::time_point start_;
|
|
};
|
|
|
|
inline constexpr const char* kHttpRequestStart = "ecap.http_request_start";
|
|
|
|
inline void register_http_performance_monitor(const bool access_log,
|
|
const std::size_t slow_request_threshold_ms) {
|
|
drogon::app().registerSyncAdvice(
|
|
[](const drogon::HttpRequestPtr& request) -> drogon::HttpResponsePtr {
|
|
request->attributes()->insert(kHttpRequestStart, std::chrono::steady_clock::now());
|
|
return {};
|
|
});
|
|
drogon::app().registerPreSendingAdvice(
|
|
[access_log, slow_request_threshold_ms](
|
|
const drogon::HttpRequestPtr& request,
|
|
const drogon::HttpResponsePtr& response) {
|
|
const auto& start =
|
|
request->attributes()->get<std::chrono::steady_clock::time_point>(
|
|
kHttpRequestStart);
|
|
if (start == std::chrono::steady_clock::time_point{}) return;
|
|
const auto elapsed_ms =
|
|
std::chrono::duration<double, std::milli>(
|
|
std::chrono::steady_clock::now() - start).count();
|
|
if (access_log) Access_Logger::log(request, response, elapsed_ms);
|
|
Slow_Request_Monitor::log_if_slow(
|
|
request, response, elapsed_ms, slow_request_threshold_ms);
|
|
});
|
|
}
|