mirror of
https://github.com/drogonframework/drogon.git
synced 2025-07-18 00:00:46 -04:00
Compare commits
No commits in common. "cedeeb59f4704fd025dbc81eea694e3836c480b4" and "e2e5d6d57f26b79bab83e87d1d3596d077925603" have entirely different histories.
cedeeb59f4
...
e2e5d6d57f
@ -230,18 +230,12 @@ endif (BUILD_BROTLI)
|
|||||||
|
|
||||||
set(DROGON_SOURCES
|
set(DROGON_SOURCES
|
||||||
lib/src/AOPAdvice.cc
|
lib/src/AOPAdvice.cc
|
||||||
lib/src/AccessLogger.cc
|
|
||||||
lib/src/CacheFile.cc
|
lib/src/CacheFile.cc
|
||||||
lib/src/ConfigAdapterManager.cc
|
|
||||||
lib/src/ConfigLoader.cc
|
lib/src/ConfigLoader.cc
|
||||||
lib/src/Cookie.cc
|
lib/src/Cookie.cc
|
||||||
lib/src/DrClassMap.cc
|
lib/src/DrClassMap.cc
|
||||||
lib/src/DrTemplateBase.cc
|
lib/src/DrTemplateBase.cc
|
||||||
lib/src/FiltersFunction.cc
|
lib/src/FiltersFunction.cc
|
||||||
lib/src/FixedWindowRateLimiter.cc
|
|
||||||
lib/src/GlobalFilters.cc
|
|
||||||
lib/src/Histogram.cc
|
|
||||||
lib/src/Hodor.cc
|
|
||||||
lib/src/HttpAppFrameworkImpl.cc
|
lib/src/HttpAppFrameworkImpl.cc
|
||||||
lib/src/HttpBinder.cc
|
lib/src/HttpBinder.cc
|
||||||
lib/src/HttpClientImpl.cc
|
lib/src/HttpClientImpl.cc
|
||||||
@ -257,29 +251,33 @@ set(DROGON_SOURCES
|
|||||||
lib/src/HttpUtils.cc
|
lib/src/HttpUtils.cc
|
||||||
lib/src/HttpViewData.cc
|
lib/src/HttpViewData.cc
|
||||||
lib/src/IntranetIpFilter.cc
|
lib/src/IntranetIpFilter.cc
|
||||||
lib/src/JsonConfigAdapter.cc
|
|
||||||
lib/src/ListenerManager.cc
|
lib/src/ListenerManager.cc
|
||||||
lib/src/LocalHostFilter.cc
|
lib/src/LocalHostFilter.cc
|
||||||
lib/src/MultiPart.cc
|
lib/src/MultiPart.cc
|
||||||
lib/src/NotFound.cc
|
lib/src/NotFound.cc
|
||||||
lib/src/PluginsManager.cc
|
lib/src/PluginsManager.cc
|
||||||
lib/src/PromExporter.cc
|
|
||||||
lib/src/RangeParser.cc
|
lib/src/RangeParser.cc
|
||||||
lib/src/RateLimiter.cc
|
|
||||||
lib/src/RealIpResolver.cc
|
|
||||||
lib/src/SecureSSLRedirector.cc
|
lib/src/SecureSSLRedirector.cc
|
||||||
|
lib/src/GlobalFilters.cc
|
||||||
|
lib/src/AccessLogger.cc
|
||||||
|
lib/src/RealIpResolver.cc
|
||||||
lib/src/SessionManager.cc
|
lib/src/SessionManager.cc
|
||||||
lib/src/SlashRemover.cc
|
|
||||||
lib/src/SlidingWindowRateLimiter.cc
|
|
||||||
lib/src/StaticFileRouter.cc
|
lib/src/StaticFileRouter.cc
|
||||||
lib/src/TaskTimeoutFlag.cc
|
lib/src/TaskTimeoutFlag.cc
|
||||||
lib/src/TokenBucketRateLimiter.cc
|
|
||||||
lib/src/Utilities.cc
|
lib/src/Utilities.cc
|
||||||
lib/src/WebSocketClientImpl.cc
|
lib/src/WebSocketClientImpl.cc
|
||||||
lib/src/WebSocketConnectionImpl.cc
|
lib/src/WebSocketConnectionImpl.cc
|
||||||
lib/src/WebsocketControllersRouter.cc
|
lib/src/WebsocketControllersRouter.cc
|
||||||
lib/src/YamlConfigAdapter.cc
|
lib/src/RateLimiter.cc
|
||||||
lib/src/drogon_test.cc)
|
lib/src/FixedWindowRateLimiter.cc
|
||||||
|
lib/src/SlidingWindowRateLimiter.cc
|
||||||
|
lib/src/TokenBucketRateLimiter.cc
|
||||||
|
lib/src/Hodor.cc
|
||||||
|
lib/src/SlashRemover.cc
|
||||||
|
lib/src/drogon_test.cc
|
||||||
|
lib/src/ConfigAdapterManager.cc
|
||||||
|
lib/src/JsonConfigAdapter.cc
|
||||||
|
lib/src/YamlConfigAdapter.cc)
|
||||||
set(private_headers
|
set(private_headers
|
||||||
lib/src/AOPAdvice.h
|
lib/src/AOPAdvice.h
|
||||||
lib/src/CacheFile.h
|
lib/src/CacheFile.h
|
||||||
@ -691,23 +689,10 @@ set(DROGON_UTIL_HEADERS
|
|||||||
lib/inc/drogon/utils/FunctionTraits.h
|
lib/inc/drogon/utils/FunctionTraits.h
|
||||||
lib/inc/drogon/utils/HttpConstraint.h
|
lib/inc/drogon/utils/HttpConstraint.h
|
||||||
lib/inc/drogon/utils/OStringStream.h
|
lib/inc/drogon/utils/OStringStream.h
|
||||||
lib/inc/drogon/utils/Utilities.h
|
lib/inc/drogon/utils/Utilities.h)
|
||||||
lib/inc/drogon/utils/monitoring.h)
|
|
||||||
install(FILES ${DROGON_UTIL_HEADERS}
|
install(FILES ${DROGON_UTIL_HEADERS}
|
||||||
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/utils)
|
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/utils)
|
||||||
|
|
||||||
set(DROGON_MONITORING_HEADERS
|
|
||||||
lib/inc/drogon/utils/monitoring/Counter.h
|
|
||||||
lib/inc/drogon/utils/monitoring/Metric.h
|
|
||||||
lib/inc/drogon/utils/monitoring/Registry.h
|
|
||||||
lib/inc/drogon/utils/monitoring/Collector.h
|
|
||||||
lib/inc/drogon/utils/monitoring/Sample.h
|
|
||||||
lib/inc/drogon/utils/monitoring/Gauge.h
|
|
||||||
lib/inc/drogon/utils/monitoring/Histogram.h)
|
|
||||||
|
|
||||||
install(FILES ${DROGON_MONITORING_HEADERS}
|
|
||||||
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/utils/monitoring)
|
|
||||||
|
|
||||||
set(DROGON_PLUGIN_HEADERS
|
set(DROGON_PLUGIN_HEADERS
|
||||||
lib/inc/drogon/plugins/Plugin.h
|
lib/inc/drogon/plugins/Plugin.h
|
||||||
lib/inc/drogon/plugins/SecureSSLRedirector.h
|
lib/inc/drogon/plugins/SecureSSLRedirector.h
|
||||||
@ -715,8 +700,7 @@ set(DROGON_PLUGIN_HEADERS
|
|||||||
lib/inc/drogon/plugins/RealIpResolver.h
|
lib/inc/drogon/plugins/RealIpResolver.h
|
||||||
lib/inc/drogon/plugins/Hodor.h
|
lib/inc/drogon/plugins/Hodor.h
|
||||||
lib/inc/drogon/plugins/SlashRemover.h
|
lib/inc/drogon/plugins/SlashRemover.h
|
||||||
lib/inc/drogon/plugins/GlobalFilters.h
|
lib/inc/drogon/plugins/GlobalFilters.h)
|
||||||
lib/inc/drogon/plugins/PromExporter.h)
|
|
||||||
|
|
||||||
install(FILES ${DROGON_PLUGIN_HEADERS}
|
install(FILES ${DROGON_PLUGIN_HEADERS}
|
||||||
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/plugins)
|
DESTINATION ${INSTALL_INCLUDE_DIR}/drogon/plugins)
|
||||||
@ -728,8 +712,7 @@ target_sources(${PROJECT_NAME} PRIVATE
|
|||||||
${ORM_HEADERS}
|
${ORM_HEADERS}
|
||||||
${DROGON_UTIL_HEADERS}
|
${DROGON_UTIL_HEADERS}
|
||||||
${DROGON_PLUGIN_HEADERS}
|
${DROGON_PLUGIN_HEADERS}
|
||||||
${NOSQL_HEADERS}
|
${NOSQL_HEADERS})
|
||||||
${DROGON_MONITORING_HEADERS})
|
|
||||||
|
|
||||||
source_group("Public API"
|
source_group("Public API"
|
||||||
FILES
|
FILES
|
||||||
@ -737,8 +720,7 @@ source_group("Public API"
|
|||||||
${ORM_HEADERS}
|
${ORM_HEADERS}
|
||||||
${DROGON_UTIL_HEADERS}
|
${DROGON_UTIL_HEADERS}
|
||||||
${DROGON_PLUGIN_HEADERS}
|
${DROGON_PLUGIN_HEADERS}
|
||||||
${NOSQL_HEADERS}
|
${NOSQL_HEADERS})
|
||||||
${DROGON_MONITORING_HEADERS})
|
|
||||||
source_group("Private Headers"
|
source_group("Private Headers"
|
||||||
FILES
|
FILES
|
||||||
${private_headers})
|
${private_headers})
|
||||||
|
@ -244,19 +244,19 @@
|
|||||||
//0 means cache forever, the negative value means no cache
|
//0 means cache forever, the negative value means no cache
|
||||||
"static_files_cache_time": 5,
|
"static_files_cache_time": 5,
|
||||||
//simple_controllers_map: Used to configure mapping from path to simple controller
|
//simple_controllers_map: Used to configure mapping from path to simple controller
|
||||||
//"simple_controllers_map": [
|
"simple_controllers_map": [
|
||||||
// {
|
{
|
||||||
// "path": "/path/name",
|
"path": "/path/name",
|
||||||
// "controller": "controllerClassName",
|
"controller": "controllerClassName",
|
||||||
// "http_methods": [
|
"http_methods": [
|
||||||
// "get",
|
"get",
|
||||||
// "post"
|
"post"
|
||||||
// ],
|
],
|
||||||
// "filters": [
|
"filters": [
|
||||||
// "FilterClassName"
|
"FilterClassName"
|
||||||
// ]
|
]
|
||||||
// }
|
}
|
||||||
//],
|
],
|
||||||
//idle_connection_timeout: Defaults to 60 seconds, the lifetime
|
//idle_connection_timeout: Defaults to 60 seconds, the lifetime
|
||||||
//of the connection without read or write
|
//of the connection without read or write
|
||||||
"idle_connection_timeout": 60,
|
"idle_connection_timeout": 60,
|
||||||
@ -307,13 +307,16 @@
|
|||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
//name: The class name of the plugin
|
//name: The class name of the plugin
|
||||||
"name": "drogon::plugin::PromExporter",
|
//"name": "drogon::plugin::SecureSSLRedirector",
|
||||||
//dependencies: Plugins that the plugin depends on. It can be commented out
|
//dependencies: Plugins that the plugin depends on. It can be commented out
|
||||||
"dependencies": [],
|
"dependencies": [],
|
||||||
//config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
|
//config: The configuration of the plugin. This json object is the parameter to initialize the plugin.
|
||||||
//It can be commented out
|
//It can be commented out
|
||||||
"config": {
|
"config": {
|
||||||
"path": "/metrics"
|
"ssl_redirect_exempt": [
|
||||||
|
".*\\.jpg"
|
||||||
|
],
|
||||||
|
"secure_ssl_host": "localhost:8849"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -115,16 +115,6 @@ class HttpBinder : public HttpBinderBase
|
|||||||
const HttpRequestPtr &req,
|
const HttpRequestPtr &req,
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback) override
|
std::function<void(const HttpResponsePtr &)> &&callback) override
|
||||||
{
|
{
|
||||||
if (!pathArguments.empty())
|
|
||||||
{
|
|
||||||
std::vector<std::string> args;
|
|
||||||
args.reserve(pathArguments.size());
|
|
||||||
for (auto &arg : pathArguments)
|
|
||||||
{
|
|
||||||
args.emplace_back(arg);
|
|
||||||
}
|
|
||||||
req->setRoutingParameters(std::move(args));
|
|
||||||
}
|
|
||||||
run(pathArguments, req, std::move(callback));
|
run(pathArguments, req, std::move(callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,13 +247,6 @@ class DROGON_EXPORT HttpRequest
|
|||||||
matchedPathPatternLength());
|
matchedPathPatternLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the matched path pattern after routing (including matched parameters
|
|
||||||
/// in the query string)
|
|
||||||
virtual const std::vector<std::string> &getRoutingParameters() const = 0;
|
|
||||||
|
|
||||||
/// This method usually is called by the framework.
|
|
||||||
virtual void setRoutingParameters(std::vector<std::string> &¶ms) = 0;
|
|
||||||
|
|
||||||
virtual const char *matchedPathPatternData() const = 0;
|
virtual const char *matchedPathPatternData() const = 0;
|
||||||
virtual size_t matchedPathPatternLength() const = 0;
|
virtual size_t matchedPathPatternLength() const = 0;
|
||||||
|
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
#include <drogon/plugins/Hodor.h>
|
#include <drogon/plugins/Hodor.h>
|
||||||
#include <drogon/plugins/SlashRemover.h>
|
#include <drogon/plugins/SlashRemover.h>
|
||||||
#include <drogon/plugins/GlobalFilters.h>
|
#include <drogon/plugins/GlobalFilters.h>
|
||||||
#include <drogon/plugins/PromExporter.h>
|
|
||||||
#include <drogon/IntranetIpFilter.h>
|
#include <drogon/IntranetIpFilter.h>
|
||||||
#include <drogon/LocalHostFilter.h>
|
#include <drogon/LocalHostFilter.h>
|
||||||
#include <drogon/Cookie.h>
|
#include <drogon/Cookie.h>
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file PromExporter.h
|
|
||||||
* @author An Tao
|
|
||||||
*
|
|
||||||
* Copyright 2018, An Tao. All rights reserved.
|
|
||||||
* https://github.com/an-tao/drogon
|
|
||||||
* Use of this source code is governed by a MIT license
|
|
||||||
* that can be found in the License file.
|
|
||||||
*
|
|
||||||
* Drogon
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <drogon/plugins/Plugin.h>
|
|
||||||
#include <drogon/utils/monitoring/Registry.h>
|
|
||||||
#include <drogon/utils/monitoring/Collector.h>
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
namespace drogon
|
|
||||||
{
|
|
||||||
namespace plugin
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @brief The PromExporter plugin implements a prometheus exporter.
|
|
||||||
* The json configuration is as follows:
|
|
||||||
* @code
|
|
||||||
{
|
|
||||||
"name": "drogon::plugin::PromExporter",
|
|
||||||
"dependencies": [],
|
|
||||||
"config": {
|
|
||||||
// The path of the metrics. the default value is "/metrics".
|
|
||||||
"path": "/metrics",
|
|
||||||
// The list of collectors.
|
|
||||||
"collectors":[
|
|
||||||
{
|
|
||||||
// The name of the collector.
|
|
||||||
"name": "http_requests_total",
|
|
||||||
// The help message of the collector.
|
|
||||||
"help": "The total number of http requests",
|
|
||||||
// The type of the collector. The default value is "counter".
|
|
||||||
// The other possible value is as following:
|
|
||||||
// "gauge", "histogram".
|
|
||||||
"type": "counter",
|
|
||||||
// The labels of the collector.
|
|
||||||
"labels": ["method", "status"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@endcode
|
|
||||||
* */
|
|
||||||
class DROGON_EXPORT PromExporter
|
|
||||||
: public drogon::Plugin<PromExporter>,
|
|
||||||
public std::enable_shared_from_this<PromExporter>,
|
|
||||||
public drogon::monitoring::Registry
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PromExporter()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void initAndStart(const Json::Value &config) override;
|
|
||||||
|
|
||||||
void shutdown() override
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~PromExporter() override
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerCollector(
|
|
||||||
const std::shared_ptr<drogon::monitoring::CollectorBase> &collector)
|
|
||||||
override;
|
|
||||||
|
|
||||||
std::shared_ptr<drogon::monitoring::CollectorBase> getCollector(
|
|
||||||
const std::string &name) const noexcept(false);
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
std::shared_ptr<drogon::monitoring::Collector<T>> getCollector(
|
|
||||||
const std::string &name) const
|
|
||||||
{
|
|
||||||
return std::dynamic_pointer_cast<drogon::monitoring::Collector<T>>(
|
|
||||||
getCollector(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
mutable std::mutex mutex_;
|
|
||||||
std::unordered_map<std::string,
|
|
||||||
std::shared_ptr<drogon::monitoring::CollectorBase>>
|
|
||||||
collectors_;
|
|
||||||
std::string path_{"/metrics"};
|
|
||||||
std::string exportMetrics();
|
|
||||||
};
|
|
||||||
} // namespace plugin
|
|
||||||
} // namespace drogon
|
|
@ -1,18 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* monitoring.h
|
|
||||||
* An Tao
|
|
||||||
*
|
|
||||||
* Copyright 2018, An Tao. All rights reserved.
|
|
||||||
* https://github.com/an-tao/drogon
|
|
||||||
* Use of this source code is governed by a MIT license
|
|
||||||
* that can be found in the License file.
|
|
||||||
*
|
|
||||||
* Drogon
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#include <drogon/utils/monitoring/Metric.h>
|
|
||||||
#include <drogon/utils/monitoring/Registry.h>
|
|
||||||
#include <drogon/utils/monitoring/Collector.h>
|
|
||||||
#include <drogon/utils/monitoring/Sample.h>
|
|
@ -1,132 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* Collector.h
|
|
||||||
* An Tao
|
|
||||||
*
|
|
||||||
* Copyright 2018, An Tao. All rights reserved.
|
|
||||||
* https://github.com/an-tao/drogon
|
|
||||||
* Use of this source code is governed by a MIT license
|
|
||||||
* that can be found in the License file.
|
|
||||||
*
|
|
||||||
* Drogon
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <trantor/utils/Date.h>
|
|
||||||
#include <drogon/utils/monitoring/Sample.h>
|
|
||||||
#include <drogon/utils/monitoring/Metric.h>
|
|
||||||
#include <drogon/utils/monitoring/Registry.h>
|
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
|
||||||
#include <vector>
|
|
||||||
#include <mutex>
|
|
||||||
#include <map>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace drogon
|
|
||||||
{
|
|
||||||
namespace monitoring
|
|
||||||
{
|
|
||||||
struct SamplesGroup
|
|
||||||
{
|
|
||||||
std::shared_ptr<Metric> metric;
|
|
||||||
std::vector<Sample> samples;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CollectorBase : public std::enable_shared_from_this<CollectorBase>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~CollectorBase() = default;
|
|
||||||
virtual std::vector<SamplesGroup> collect() const = 0;
|
|
||||||
virtual const std::string &name() const = 0;
|
|
||||||
virtual const std::string &help() const = 0;
|
|
||||||
virtual const std::string_view type() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The Collector class template is used to collect samples from a group
|
|
||||||
* of metric.
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
class Collector : public CollectorBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Collector(const std::string &name,
|
|
||||||
const std::string &help,
|
|
||||||
const std::vector<std::string> &labelNames)
|
|
||||||
: name_(name), help_(help), labelsNames_(labelNames)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::shared_ptr<T> &metric(
|
|
||||||
const std::vector<std::string> &labelValues) noexcept(false)
|
|
||||||
{
|
|
||||||
if (labelValues.size() != labelsNames_.size())
|
|
||||||
{
|
|
||||||
throw std::runtime_error(
|
|
||||||
"The number of label values is not equal to the number of "
|
|
||||||
"label names!");
|
|
||||||
}
|
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
|
||||||
auto iter = metrics_.find(labelValues);
|
|
||||||
if (iter != metrics_.end())
|
|
||||||
{
|
|
||||||
return iter->second;
|
|
||||||
}
|
|
||||||
auto metric = std::make_shared<T>(name_, labelsNames_, labelValues);
|
|
||||||
metrics_[labelValues] = metric;
|
|
||||||
return metrics_[labelValues];
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<SamplesGroup> collect() const override
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
|
||||||
std::vector<SamplesGroup> samples;
|
|
||||||
for (auto &pair : metrics_)
|
|
||||||
{
|
|
||||||
SamplesGroup samplesGroup;
|
|
||||||
auto &metric = pair.second;
|
|
||||||
samplesGroup.metric = metric;
|
|
||||||
auto metricSamples = metric->collect();
|
|
||||||
samplesGroup.samples = std::move(metricSamples);
|
|
||||||
samples.emplace_back(std::move(samplesGroup));
|
|
||||||
}
|
|
||||||
return samples;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string &name() const override
|
|
||||||
{
|
|
||||||
return name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string &help() const override
|
|
||||||
{
|
|
||||||
return help_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string_view type() const override
|
|
||||||
{
|
|
||||||
return T::type();
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerTo(Registry ®istry)
|
|
||||||
{
|
|
||||||
registry.registerCollector(shared_from_this());
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<std::string> &labelsNames() const
|
|
||||||
{
|
|
||||||
return labelsNames_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const std::string name_;
|
|
||||||
const std::string help_;
|
|
||||||
const std::vector<std::string> labelsNames_;
|
|
||||||
std::map<std::vector<std::string>, std::shared_ptr<T>> metrics_;
|
|
||||||
mutable std::mutex mutex_;
|
|
||||||
};
|
|
||||||
} // namespace monitoring
|
|
||||||
} // namespace drogon
|
|
@ -1,82 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* Counter.h
|
|
||||||
* An Tao
|
|
||||||
*
|
|
||||||
* Copyright 2018, An Tao. All rights reserved.
|
|
||||||
* https://github.com/an-tao/drogon
|
|
||||||
* Use of this source code is governed by a MIT license
|
|
||||||
* that can be found in the License file.
|
|
||||||
*
|
|
||||||
* Drogon
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <drogon/utils/monitoring/Metric.h>
|
|
||||||
#include <string_view>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
namespace drogon
|
|
||||||
{
|
|
||||||
namespace monitoring
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* This class is used to collect samples for a counter metric.
|
|
||||||
* */
|
|
||||||
class Counter : public Metric
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Counter(const std::string &name,
|
|
||||||
const std::vector<std::string> &labelNames,
|
|
||||||
const std::vector<std::string> &labelValues) noexcept(false)
|
|
||||||
: Metric(name, labelNames, labelValues)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Sample> collect() const override
|
|
||||||
{
|
|
||||||
Sample s;
|
|
||||||
s.name = name_;
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
|
||||||
s.value = value_;
|
|
||||||
}
|
|
||||||
return {s};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increment the counter by 1.
|
|
||||||
* */
|
|
||||||
void increment()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
|
||||||
value_++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increment the counter by the given value.
|
|
||||||
* */
|
|
||||||
void increment(double value)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
|
||||||
value_ += value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
|
||||||
value_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string_view type()
|
|
||||||
{
|
|
||||||
return "counter";
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
mutable std::mutex mutex_;
|
|
||||||
double value_{0};
|
|
||||||
};
|
|
||||||
} // namespace monitoring
|
|
||||||
} // namespace drogon
|
|
@ -1,109 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* Gauge.h
|
|
||||||
* An Tao
|
|
||||||
*
|
|
||||||
* Copyright 2018, An Tao. All rights reserved.
|
|
||||||
* https://github.com/an-tao/drogon
|
|
||||||
* Use of this source code is governed by a MIT license
|
|
||||||
* that can be found in the License file.
|
|
||||||
*
|
|
||||||
* Drogon
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <drogon/utils/monitoring/Metric.h>
|
|
||||||
#include <string_view>
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
namespace drogon
|
|
||||||
{
|
|
||||||
namespace monitoring
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* This class is used to collect samples for a gauge metric.
|
|
||||||
* */
|
|
||||||
class Gauge : public Metric
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Construct a gauge metric with a name and a help string.
|
|
||||||
* */
|
|
||||||
Gauge(const std::string &name,
|
|
||||||
const std::vector<std::string> &labelNames,
|
|
||||||
const std::vector<std::string> &labelValues) noexcept(false)
|
|
||||||
: Metric(name, labelNames, labelValues)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Sample> collect() const override
|
|
||||||
{
|
|
||||||
Sample s;
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
|
||||||
s.name = name_;
|
|
||||||
s.value = value_;
|
|
||||||
s.timestamp = timestamp_;
|
|
||||||
return {s};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increment the counter by 1.
|
|
||||||
* */
|
|
||||||
void increment()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
|
||||||
value_ += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void decrement()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
|
||||||
value_ -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void decrement(double value)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
|
||||||
value_ -= value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increment the counter by the given value.
|
|
||||||
* */
|
|
||||||
void increment(double value)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
|
||||||
value_ += value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
|
||||||
value_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(double value)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
|
||||||
value_ = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string_view type()
|
|
||||||
{
|
|
||||||
return "counter";
|
|
||||||
}
|
|
||||||
|
|
||||||
void setToCurrentTime()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
|
||||||
timestamp_ = trantor::Date::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
mutable std::mutex mutex_;
|
|
||||||
double value_{0};
|
|
||||||
trantor::Date timestamp_{0};
|
|
||||||
};
|
|
||||||
} // namespace monitoring
|
|
||||||
} // namespace drogon
|
|
@ -1,122 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* Histogram.h
|
|
||||||
* An Tao
|
|
||||||
*
|
|
||||||
* Copyright 2018, An Tao. All rights reserved.
|
|
||||||
* https://github.com/an-tao/drogon
|
|
||||||
* Use of this source code is governed by a MIT license
|
|
||||||
* that can be found in the License file.
|
|
||||||
*
|
|
||||||
* Drogon
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <drogon/exports.h>
|
|
||||||
#include <drogon/utils/monitoring/Metric.h>
|
|
||||||
#include <trantor/net/EventLoopThread.h>
|
|
||||||
#include <string_view>
|
|
||||||
#include <atomic>
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
namespace drogon
|
|
||||||
{
|
|
||||||
namespace monitoring
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* This class is used to collect samples for a counter metric.
|
|
||||||
* */
|
|
||||||
class DROGON_EXPORT Histogram : public Metric
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct TimeBucket
|
|
||||||
{
|
|
||||||
std::vector<uint64_t> buckets;
|
|
||||||
uint64_t count{0};
|
|
||||||
double sum{0};
|
|
||||||
};
|
|
||||||
|
|
||||||
Histogram(const std::string &name,
|
|
||||||
const std::vector<std::string> &labelNames,
|
|
||||||
const std::vector<std::string> &labelValues,
|
|
||||||
const std::vector<double> &bucketBoundaries,
|
|
||||||
const std::chrono::duration<double> &maxAge,
|
|
||||||
uint64_t timeBucketsCount,
|
|
||||||
trantor::EventLoop *loop = nullptr) noexcept(false)
|
|
||||||
: Metric(name, labelNames, labelValues),
|
|
||||||
maxAge_(maxAge),
|
|
||||||
timeBucketCount_(timeBucketsCount),
|
|
||||||
bucketBoundaries_(bucketBoundaries)
|
|
||||||
{
|
|
||||||
if (loop == nullptr)
|
|
||||||
{
|
|
||||||
loopThreadPtr_ = std::make_unique<trantor::EventLoopThread>();
|
|
||||||
loopPtr_ = loopThreadPtr_->getLoop();
|
|
||||||
loopThreadPtr_->run();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
loopPtr_ = loop;
|
|
||||||
}
|
|
||||||
if (maxAge > std::chrono::seconds(0))
|
|
||||||
{
|
|
||||||
if (timeBucketsCount == 0)
|
|
||||||
{
|
|
||||||
throw std::runtime_error(
|
|
||||||
"timeBucketsCount must be greater than 0");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
timeBuckets_.emplace_back();
|
|
||||||
// check the bucket boundaries are sorted
|
|
||||||
for (size_t i = 1; i < bucketBoundaries.size(); i++)
|
|
||||||
{
|
|
||||||
if (bucketBoundaries[i] <= bucketBoundaries[i - 1])
|
|
||||||
{
|
|
||||||
throw std::runtime_error(
|
|
||||||
"The bucket boundaries must be sorted");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void observe(double value);
|
|
||||||
std::vector<Sample> collect() const override;
|
|
||||||
|
|
||||||
~Histogram() override
|
|
||||||
{
|
|
||||||
if (timerId_ != trantor::InvalidTimerId)
|
|
||||||
{
|
|
||||||
loopPtr_->invalidateTimer(timerId_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string_view type()
|
|
||||||
{
|
|
||||||
return "histogram";
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::deque<TimeBucket> timeBuckets_;
|
|
||||||
std::unique_ptr<trantor::EventLoopThread> loopThreadPtr_;
|
|
||||||
trantor::EventLoop *loopPtr_{nullptr};
|
|
||||||
mutable std::mutex mutex_;
|
|
||||||
std::chrono::duration<double> maxAge_;
|
|
||||||
trantor::TimerId timerId_{trantor::InvalidTimerId};
|
|
||||||
size_t timeBucketCount_{0};
|
|
||||||
const std::vector<double> bucketBoundaries_;
|
|
||||||
|
|
||||||
void rotateTimeBuckets()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
|
||||||
TimeBucket bucket;
|
|
||||||
bucket.buckets.resize(bucketBoundaries_.size() + 1);
|
|
||||||
timeBuckets_.emplace_back(std::move(bucket));
|
|
||||||
if (timeBuckets_.size() > timeBucketCount_)
|
|
||||||
{
|
|
||||||
auto expiredTimeBucket = timeBuckets_.front();
|
|
||||||
timeBuckets_.erase(timeBuckets_.begin());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace monitoring
|
|
||||||
} // namespace drogon
|
|
@ -1,77 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* Metric.h
|
|
||||||
* An Tao
|
|
||||||
*
|
|
||||||
* Copyright 2018, An Tao. All rights reserved.
|
|
||||||
* https://github.com/an-tao/drogon
|
|
||||||
* Use of this source code is governed by a MIT license
|
|
||||||
* that can be found in the License file.
|
|
||||||
*
|
|
||||||
* Drogon
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <drogon/utils/monitoring/Sample.h>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
namespace drogon
|
|
||||||
{
|
|
||||||
namespace monitoring
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* This class is used to collect samples for a metric.
|
|
||||||
* */
|
|
||||||
class Metric : public std::enable_shared_from_this<Metric>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Construct a metric with a name and a help string.
|
|
||||||
* */
|
|
||||||
|
|
||||||
Metric(const std::string &name,
|
|
||||||
const std::vector<std::string> &labelNames,
|
|
||||||
const std::vector<std::string> &labelValues) noexcept(false)
|
|
||||||
: name_(name)
|
|
||||||
{
|
|
||||||
if (labelNames.size() != labelValues.size())
|
|
||||||
{
|
|
||||||
throw std::runtime_error(
|
|
||||||
"The number of label names is not equal to the number of label "
|
|
||||||
"values!");
|
|
||||||
}
|
|
||||||
labels_.resize(labelNames.size());
|
|
||||||
for (size_t i = 0; i < labelNames.size(); i++)
|
|
||||||
{
|
|
||||||
labels_[i].first = labelNames[i];
|
|
||||||
labels_[i].second = labelValues[i];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const std::string &name() const
|
|
||||||
{
|
|
||||||
return name_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<std::pair<std::string, std::string>> &labels() const
|
|
||||||
{
|
|
||||||
return labels_;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~Metric() = default;
|
|
||||||
virtual std::vector<Sample> collect() const = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const std::string name_;
|
|
||||||
std::vector<std::pair<std::string, std::string>> labels_;
|
|
||||||
};
|
|
||||||
|
|
||||||
using MetricPtr = std::shared_ptr<Metric>;
|
|
||||||
|
|
||||||
} // namespace monitoring
|
|
||||||
} // namespace drogon
|
|
@ -1,35 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* Registry.h
|
|
||||||
* An Tao
|
|
||||||
*
|
|
||||||
* Copyright 2018, An Tao. All rights reserved.
|
|
||||||
* https://github.com/an-tao/drogon
|
|
||||||
* Use of this source code is governed by a MIT license
|
|
||||||
* that can be found in the License file.
|
|
||||||
*
|
|
||||||
* Drogon
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace drogon
|
|
||||||
{
|
|
||||||
namespace monitoring
|
|
||||||
{
|
|
||||||
class CollectorBase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is used to register metrics.
|
|
||||||
* */
|
|
||||||
class Registry
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~Registry() = default;
|
|
||||||
virtual void registerCollector(
|
|
||||||
const std::shared_ptr<CollectorBase> &collector) = 0;
|
|
||||||
};
|
|
||||||
} // namespace monitoring
|
|
||||||
} // namespace drogon
|
|
@ -1,35 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* Sample.h
|
|
||||||
* An Tao
|
|
||||||
*
|
|
||||||
* Copyright 2018, An Tao. All rights reserved.
|
|
||||||
* https://github.com/an-tao/drogon
|
|
||||||
* Use of this source code is governed by a MIT license
|
|
||||||
* that can be found in the License file.
|
|
||||||
*
|
|
||||||
* Drogon
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <trantor/utils/Date.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace drogon
|
|
||||||
{
|
|
||||||
namespace monitoring
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* This class is used to collect samples for a metric.
|
|
||||||
* */
|
|
||||||
struct Sample
|
|
||||||
{
|
|
||||||
double value{0};
|
|
||||||
trantor::Date timestamp{0};
|
|
||||||
std::string name;
|
|
||||||
std::vector<std::pair<std::string, std::string>> exLabels;
|
|
||||||
};
|
|
||||||
} // namespace monitoring
|
|
||||||
} // namespace drogon
|
|
@ -1,75 +0,0 @@
|
|||||||
/**
|
|
||||||
*
|
|
||||||
* StopWatch.h
|
|
||||||
* An Tao
|
|
||||||
*
|
|
||||||
* Copyright 2018, An Tao. All rights reserved.
|
|
||||||
* https://github.com/an-tao/drogon
|
|
||||||
* Use of this source code is governed by a MIT license
|
|
||||||
* that can be found in the License file.
|
|
||||||
*
|
|
||||||
* Drogon
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <functional>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
namespace drogon
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @brief This class is used to measure the elapsed time.
|
|
||||||
*/
|
|
||||||
class StopWatch
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
StopWatch() : start_(std::chrono::steady_clock::now())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~StopWatch()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Reset the start time.
|
|
||||||
*/
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
start_ = std::chrono::steady_clock::now();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the elapsed time in seconds.
|
|
||||||
*/
|
|
||||||
double elapsed() const
|
|
||||||
{
|
|
||||||
return std::chrono::duration_cast<std::chrono::duration<double>>(
|
|
||||||
std::chrono::steady_clock::now() - start_)
|
|
||||||
.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::chrono::steady_clock::time_point start_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class LifeTimeWatch
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LifeTimeWatch(std::function<void(double)> callback)
|
|
||||||
: stopWatch_(), callback_(std::move(callback))
|
|
||||||
{
|
|
||||||
assert(callback_);
|
|
||||||
}
|
|
||||||
|
|
||||||
~LifeTimeWatch()
|
|
||||||
{
|
|
||||||
callback_(stopWatch_.elapsed());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
StopWatch stopWatch_;
|
|
||||||
std::function<void(double)> callback_;
|
|
||||||
};
|
|
||||||
} // namespace drogon
|
|
@ -1,80 +0,0 @@
|
|||||||
#include <drogon/utils/monitoring/Histogram.h>
|
|
||||||
using namespace drogon;
|
|
||||||
using namespace drogon::monitoring;
|
|
||||||
|
|
||||||
void Histogram::observe(double value)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
|
||||||
if (maxAge_ > std::chrono::seconds(0) &&
|
|
||||||
timerId_ == trantor::InvalidTimerId)
|
|
||||||
{
|
|
||||||
std::weak_ptr<Histogram> weakPtr =
|
|
||||||
std::dynamic_pointer_cast<Histogram>(shared_from_this());
|
|
||||||
timerId_ = loopPtr_->runEvery(maxAge_ / timeBucketCount_, [weakPtr]() {
|
|
||||||
auto thisPtr = weakPtr.lock();
|
|
||||||
if (!thisPtr)
|
|
||||||
return;
|
|
||||||
thisPtr->rotateTimeBuckets();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
auto ¤tBucket = timeBuckets_.back();
|
|
||||||
currentBucket.sum += value;
|
|
||||||
currentBucket.count += 1;
|
|
||||||
for (size_t i = 0; i < bucketBoundaries_.size(); i++)
|
|
||||||
{
|
|
||||||
if (value <= bucketBoundaries_[i])
|
|
||||||
{
|
|
||||||
currentBucket.buckets[i] += 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (value > bucketBoundaries_.back())
|
|
||||||
{
|
|
||||||
currentBucket.buckets.back() += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Sample> Histogram::collect() const
|
|
||||||
{
|
|
||||||
std::vector<Sample> samples;
|
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
|
||||||
size_t count{0};
|
|
||||||
for (size_t i = 0; i < bucketBoundaries_.size(); i++)
|
|
||||||
{
|
|
||||||
Sample sample;
|
|
||||||
for (auto &bucket : timeBuckets_)
|
|
||||||
{
|
|
||||||
count += bucket.buckets[i];
|
|
||||||
}
|
|
||||||
sample.name = name_ + "_bucket";
|
|
||||||
sample.exLabels.emplace_back("le",
|
|
||||||
std::to_string(bucketBoundaries_[i]));
|
|
||||||
sample.value = count;
|
|
||||||
samples.emplace_back(std::move(sample));
|
|
||||||
}
|
|
||||||
Sample sample;
|
|
||||||
for (auto &bucket : timeBuckets_)
|
|
||||||
{
|
|
||||||
count += bucket.buckets.back();
|
|
||||||
}
|
|
||||||
sample.name = name_ + "_bucket";
|
|
||||||
sample.exLabels.emplace_back("le", "+Inf");
|
|
||||||
sample.value = count;
|
|
||||||
samples.emplace_back(std::move(sample));
|
|
||||||
double sum{0};
|
|
||||||
uint64_t totalCount{0};
|
|
||||||
for (auto &bucket : timeBuckets_)
|
|
||||||
{
|
|
||||||
sum += bucket.sum;
|
|
||||||
totalCount += bucket.count;
|
|
||||||
}
|
|
||||||
Sample sumSample;
|
|
||||||
sumSample.name = name_ + "_sum";
|
|
||||||
sumSample.value = sum;
|
|
||||||
samples.emplace_back(std::move(sumSample));
|
|
||||||
Sample countSample;
|
|
||||||
countSample.name = name_ + "_count";
|
|
||||||
countSample.value = totalCount;
|
|
||||||
samples.emplace_back(std::move(countSample));
|
|
||||||
return samples;
|
|
||||||
}
|
|
@ -524,42 +524,6 @@ void HttpControllersRouter::route(
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::vector<std::string> params;
|
|
||||||
for (size_t j = 1; j < result.size(); ++j)
|
|
||||||
{
|
|
||||||
if (!result[j].matched)
|
|
||||||
continue;
|
|
||||||
size_t place = j;
|
|
||||||
if (j <= binder->parameterPlaces_.size())
|
|
||||||
{
|
|
||||||
place = binder->parameterPlaces_[j - 1];
|
|
||||||
}
|
|
||||||
if (place > params.size())
|
|
||||||
params.resize(place);
|
|
||||||
params[place - 1] = result[j].str();
|
|
||||||
LOG_TRACE << "place=" << place << " para:" << params[place - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!binder->queryParametersPlaces_.empty())
|
|
||||||
{
|
|
||||||
auto &queryPara = req->getParameters();
|
|
||||||
for (auto const ¶Place : binder->queryParametersPlaces_)
|
|
||||||
{
|
|
||||||
auto place = paraPlace.second;
|
|
||||||
if (place > params.size())
|
|
||||||
params.resize(place);
|
|
||||||
auto iter = queryPara.find(paraPlace.first);
|
|
||||||
if (iter != queryPara.end())
|
|
||||||
{
|
|
||||||
params[place - 1] = iter->second;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
params[place - 1] = std::string{};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
req->setRoutingParameters(std::move(params));
|
|
||||||
if (!postRoutingObservers_.empty())
|
if (!postRoutingObservers_.empty())
|
||||||
{
|
{
|
||||||
for (auto &observer : postRoutingObservers_)
|
for (auto &observer : postRoutingObservers_)
|
||||||
@ -675,11 +639,41 @@ void HttpControllersRouter::doControllerHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ¶msVector = req->getRoutingParameters();
|
std::deque<std::string> params(ctrlBinderPtr->parameterPlaces_.size());
|
||||||
std::deque<std::string> params(paramsVector.size());
|
|
||||||
for (int i = 0; i < paramsVector.size(); i++)
|
for (size_t j = 1; j < matchResult.size(); ++j)
|
||||||
{
|
{
|
||||||
params[i] = paramsVector[i];
|
if (!matchResult[j].matched)
|
||||||
|
continue;
|
||||||
|
size_t place = j;
|
||||||
|
if (j <= ctrlBinderPtr->parameterPlaces_.size())
|
||||||
|
{
|
||||||
|
place = ctrlBinderPtr->parameterPlaces_[j - 1];
|
||||||
|
}
|
||||||
|
if (place > params.size())
|
||||||
|
params.resize(place);
|
||||||
|
params[place - 1] = matchResult[j].str();
|
||||||
|
LOG_TRACE << "place=" << place << " para:" << params[place - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctrlBinderPtr->queryParametersPlaces_.empty())
|
||||||
|
{
|
||||||
|
auto &queryPara = req->getParameters();
|
||||||
|
for (auto const ¶Place : ctrlBinderPtr->queryParametersPlaces_)
|
||||||
|
{
|
||||||
|
auto place = paraPlace.second;
|
||||||
|
if (place > params.size())
|
||||||
|
params.resize(place);
|
||||||
|
auto iter = queryPara.find(paraPlace.first);
|
||||||
|
if (iter != queryPara.end())
|
||||||
|
{
|
||||||
|
params[place - 1] = iter->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
params[place - 1] = std::string{};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctrlBinderPtr->binderPtr_->handleHttpRequest(
|
ctrlBinderPtr->binderPtr_->handleHttpRequest(
|
||||||
params,
|
params,
|
||||||
|
@ -583,7 +583,6 @@ void HttpRequestImpl::swap(HttpRequestImpl &that) noexcept
|
|||||||
swap(loop_, that.loop_);
|
swap(loop_, that.loop_);
|
||||||
swap(flagForParsingContentType_, that.flagForParsingContentType_);
|
swap(flagForParsingContentType_, that.flagForParsingContentType_);
|
||||||
swap(jsonParsingErrorPtr_, that.jsonParsingErrorPtr_);
|
swap(jsonParsingErrorPtr_, that.jsonParsingErrorPtr_);
|
||||||
swap(routingParams_, that.routingParams_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *HttpRequestImpl::versionString() const
|
const char *HttpRequestImpl::versionString() const
|
||||||
|
@ -79,7 +79,6 @@ class HttpRequestImpl : public HttpRequest
|
|||||||
keepAlive_ = true;
|
keepAlive_ = true;
|
||||||
jsonParsingErrorPtr_.reset();
|
jsonParsingErrorPtr_.reset();
|
||||||
peerCertificate_.reset();
|
peerCertificate_.reset();
|
||||||
routingParams_.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
trantor::EventLoop *getLoop()
|
trantor::EventLoop *getLoop()
|
||||||
@ -144,16 +143,6 @@ class HttpRequestImpl : public HttpRequest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string> &getRoutingParameters() const override
|
|
||||||
{
|
|
||||||
return routingParams_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRoutingParameters(std::vector<std::string> &¶ms)
|
|
||||||
{
|
|
||||||
routingParams_ = std::move(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPath(const std::string &path) override
|
void setPath(const std::string &path) override
|
||||||
{
|
{
|
||||||
path_ = path;
|
path_ = path;
|
||||||
@ -625,7 +614,6 @@ class HttpRequestImpl : public HttpRequest
|
|||||||
bool keepAlive_{true};
|
bool keepAlive_{true};
|
||||||
bool isOnSecureConnection_{false};
|
bool isOnSecureConnection_{false};
|
||||||
bool passThrough_{false};
|
bool passThrough_{false};
|
||||||
std::vector<std::string> routingParams_;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string content_;
|
std::string content_;
|
||||||
|
@ -1,207 +0,0 @@
|
|||||||
#include <drogon/plugins/PromExporter.h>
|
|
||||||
#include <drogon/HttpAppFramework.h>
|
|
||||||
#include <drogon/utils/monitoring/Counter.h>
|
|
||||||
#include <drogon/utils/monitoring/Gauge.h>
|
|
||||||
#include <drogon/utils/monitoring/Histogram.h>
|
|
||||||
#include <drogon/utils/monitoring/Collector.h>
|
|
||||||
|
|
||||||
using namespace drogon;
|
|
||||||
using namespace drogon::monitoring;
|
|
||||||
using namespace drogon::plugin;
|
|
||||||
|
|
||||||
void PromExporter::initAndStart(const Json::Value &config)
|
|
||||||
{
|
|
||||||
path_ = config.get("path", path_).asString();
|
|
||||||
LOG_ERROR << path_;
|
|
||||||
auto &app = drogon::app();
|
|
||||||
std::weak_ptr<PromExporter> weakPtr = shared_from_this();
|
|
||||||
app.registerHandler(
|
|
||||||
path_,
|
|
||||||
[weakPtr](const HttpRequestPtr &req,
|
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback) {
|
|
||||||
auto thisPtr = weakPtr.lock();
|
|
||||||
if (!thisPtr)
|
|
||||||
{
|
|
||||||
auto resp = HttpResponse::newNotFoundResponse();
|
|
||||||
callback(resp);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto resp = HttpResponse::newHttpResponse();
|
|
||||||
resp->setBody(thisPtr->exportMetrics());
|
|
||||||
resp->setExpiredTime(5);
|
|
||||||
callback(resp);
|
|
||||||
},
|
|
||||||
{Get, Options},
|
|
||||||
"PromExporter");
|
|
||||||
if (config.isMember("collectors"))
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
|
||||||
auto &collectors = config["collectors"];
|
|
||||||
if (collectors.isArray())
|
|
||||||
{
|
|
||||||
for (auto const &collector : collectors)
|
|
||||||
{
|
|
||||||
if (collector.isObject())
|
|
||||||
{
|
|
||||||
auto name = collector["name"].asString();
|
|
||||||
auto type = collector["type"].asString();
|
|
||||||
auto help = collector["help"].asString();
|
|
||||||
auto labels = collector["labels"];
|
|
||||||
if (labels.isArray())
|
|
||||||
{
|
|
||||||
std::vector<std::string> labelNames;
|
|
||||||
for (auto const &label : labels)
|
|
||||||
{
|
|
||||||
if (label.isString())
|
|
||||||
{
|
|
||||||
labelNames.push_back(label.asString());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_ERROR << "label name must be a string!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (type == "counter")
|
|
||||||
{
|
|
||||||
auto counterCollector =
|
|
||||||
std::make_shared<Collector<Counter>>(
|
|
||||||
name, help, labelNames);
|
|
||||||
collectors_.insert(
|
|
||||||
std::make_pair(name, counterCollector));
|
|
||||||
}
|
|
||||||
else if (type == "gauge")
|
|
||||||
{
|
|
||||||
auto gaugeCollector =
|
|
||||||
std::make_shared<Collector<Gauge>>(name,
|
|
||||||
help,
|
|
||||||
labelNames);
|
|
||||||
collectors_.insert(
|
|
||||||
std::make_pair(name, gaugeCollector));
|
|
||||||
}
|
|
||||||
else if (type == "histogram")
|
|
||||||
{
|
|
||||||
auto histogramCollector =
|
|
||||||
std::make_shared<Collector<Histogram>>(
|
|
||||||
name, help, labelNames);
|
|
||||||
collectors_.insert(
|
|
||||||
std::make_pair(name, histogramCollector));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_ERROR << "Unknown collector type: " << type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_ERROR << "labels must be an array!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_ERROR << "collector must be an object!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_ERROR << "collectors must be an array!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string exportCollector(
|
|
||||||
const std::shared_ptr<CollectorBase> &collector)
|
|
||||||
{
|
|
||||||
auto sampleGroups = collector->collect();
|
|
||||||
std::string res;
|
|
||||||
res.append("# HELP ")
|
|
||||||
.append(collector->name())
|
|
||||||
.append(" ")
|
|
||||||
.append(collector->help())
|
|
||||||
.append("\r\n");
|
|
||||||
res.append("# TYPE ")
|
|
||||||
.append(collector->name())
|
|
||||||
.append(" ")
|
|
||||||
.append(collector->type())
|
|
||||||
.append("\r\n");
|
|
||||||
for (auto const &sampleGroup : sampleGroups)
|
|
||||||
{
|
|
||||||
auto const &metricPtr = sampleGroup.metric;
|
|
||||||
auto const &samples = sampleGroup.samples;
|
|
||||||
for (auto &sample : samples)
|
|
||||||
{
|
|
||||||
res.append(metricPtr->name());
|
|
||||||
if (!sample.exLabels.empty() || !metricPtr->labels().empty())
|
|
||||||
{
|
|
||||||
res.append("{");
|
|
||||||
for (auto const &label : metricPtr->labels())
|
|
||||||
{
|
|
||||||
res.append(label.first)
|
|
||||||
.append("=\"")
|
|
||||||
.append(label.second)
|
|
||||||
.append("\",");
|
|
||||||
}
|
|
||||||
for (auto const &label : sample.exLabels)
|
|
||||||
{
|
|
||||||
res.append(label.first)
|
|
||||||
.append("=\"")
|
|
||||||
.append(label.second)
|
|
||||||
.append("\",");
|
|
||||||
}
|
|
||||||
res.pop_back();
|
|
||||||
res.append("}");
|
|
||||||
}
|
|
||||||
res.append(" ").append(std::to_string(sample.value));
|
|
||||||
if (sample.timestamp.microSecondsSinceEpoch() > 0)
|
|
||||||
{
|
|
||||||
res.append(" ")
|
|
||||||
.append(std::to_string(
|
|
||||||
sample.timestamp.microSecondsSinceEpoch() / 1000))
|
|
||||||
.append("\r\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
res.append("\r\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string PromExporter::exportMetrics()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
|
||||||
std::string result;
|
|
||||||
for (auto const &collector : collectors_)
|
|
||||||
{
|
|
||||||
result.append(exportCollector(collector.second));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PromExporter::registerCollector(
|
|
||||||
const std::shared_ptr<drogon::monitoring::CollectorBase> &collector)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
|
||||||
if (collectors_.find(collector->name()) != collectors_.end())
|
|
||||||
{
|
|
||||||
throw std::runtime_error("The collector named " + collector->name() +
|
|
||||||
" has been registered!");
|
|
||||||
}
|
|
||||||
collectors_.insert(std::make_pair(collector->name(), collector));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<drogon::monitoring::CollectorBase> PromExporter::getCollector(
|
|
||||||
const std::string &name) const noexcept(false)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> guard(mutex_);
|
|
||||||
auto iter = collectors_.find(name);
|
|
||||||
if (iter != collectors_.end())
|
|
||||||
{
|
|
||||||
return iter->second;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Can't find the collector named " + name);
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,7 +6,6 @@ void TestController::asyncHandleHttpRequest(
|
|||||||
std::function<void(const HttpResponsePtr &)> &&callback)
|
std::function<void(const HttpResponsePtr &)> &&callback)
|
||||||
{
|
{
|
||||||
// write your application logic here
|
// write your application logic here
|
||||||
counter_->increment();
|
|
||||||
LOG_WARN << req->matchedPathPatternData();
|
LOG_WARN << req->matchedPathPatternData();
|
||||||
LOG_DEBUG << "index=" << threadIndex_.getThreadData();
|
LOG_DEBUG << "index=" << threadIndex_.getThreadData();
|
||||||
++(threadIndex_.getThreadData());
|
++(threadIndex_.getThreadData());
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <drogon/HttpSimpleController.h>
|
#include <drogon/HttpSimpleController.h>
|
||||||
#include <drogon/IOThreadStorage.h>
|
#include <drogon/IOThreadStorage.h>
|
||||||
#include <drogon/utils/monitoring/Counter.h>
|
|
||||||
#include <drogon/utils/monitoring/Collector.h>
|
|
||||||
#include <drogon/plugins/PromExporter.h>
|
|
||||||
using namespace drogon;
|
using namespace drogon;
|
||||||
|
|
||||||
namespace example
|
namespace example
|
||||||
@ -26,18 +23,9 @@ class TestController : public drogon::HttpSimpleController<TestController>
|
|||||||
TestController()
|
TestController()
|
||||||
{
|
{
|
||||||
LOG_DEBUG << "TestController constructor";
|
LOG_DEBUG << "TestController constructor";
|
||||||
auto collector = std::make_shared<
|
|
||||||
drogon::monitoring::Collector<drogon::monitoring::Counter>>(
|
|
||||||
"test_counter",
|
|
||||||
"The counter for requests to the root url",
|
|
||||||
std::vector<std::string>());
|
|
||||||
counter_ = collector->metric(std::vector<std::string>());
|
|
||||||
collector->registerTo(
|
|
||||||
*app().getSharedPlugin<drogon::plugin::PromExporter>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
drogon::IOThreadStorage<int> threadIndex_;
|
drogon::IOThreadStorage<int> threadIndex_;
|
||||||
std::shared_ptr<drogon::monitoring::Counter> counter_;
|
|
||||||
};
|
};
|
||||||
} // namespace example
|
} // namespace example
|
||||||
|
Loading…
x
Reference in New Issue
Block a user