90 lines
3.3 KiB
C++
90 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);
|
|
});
|
|
}
|