Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【腾讯犀牛鸟开源课题实战】prometheus插件专项建设(PUSH模式支持等) #175

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
809dfe0
Update prometheus documentation and running scripts
Heaven2024 Aug 26, 2024
ccfc856
Update prometheus documentation and running scripts
Heaven2024 Aug 26, 2024
8a1de0e
Fixed prometheus documentation and running scripts
Heaven2024 Aug 26, 2024
c879973
Fixed prometheus documentation and running scripts
Heaven2024 Aug 26, 2024
e1916f8
v1
Heaven2024 Sep 29, 2024
b980723
Feature: Add Prometheus pull mode authentication.
leolin49 Jul 19, 2024
7f42fbd
Merge branch 'prometheus' into branch_prometheus_basic
leolin49 Oct 5, 2024
cd24612
Merge pull request #1 from leolin49/branch_prometheus_basic
Heaven2024 Oct 7, 2024
816bc28
fixed
Heaven2024 Oct 8, 2024
3d907d6
Fixed: Prometheus pull mode authentication.
leolin49 Oct 12, 2024
2309769
Fixed: Prometheus pull mode authentication.
leolin49 Oct 16, 2024
1a5bb30
Fixed: Prometheus pull mode authentication.
leolin49 Oct 16, 2024
8cb45d4
Fixed: Prometheus pull mode authentication.
leolin49 Oct 26, 2024
a931cfc
Fixed: Prometheus pull mode authentication.
leolin49 Nov 26, 2024
3a9fe81
Fixed: Prometheus push mode authentication.
leolin49 Nov 26, 2024
35ef136
Fixed: Prometheus authentication clang-format.
leolin49 Nov 26, 2024
f87a954
Fixed: Prometheus pull mode authentication empty auth config.
leolin49 Nov 27, 2024
973bf4b
Update prometheus_metrics.md
leolin49 Nov 27, 2024
18dc6d7
Update prometheus_metrics.md
leolin49 Nov 27, 2024
919b8b3
Update prometheus_metrics.md
leolin49 Nov 27, 2024
c986e4f
Prometheus authentication format.
leolin49 Nov 28, 2024
12afca9
Merge branch 'prometheus' of https://github.com/Heaven2024/trpc-cpp i…
leolin49 Nov 28, 2024
16b5b8c
Update LICENSE: Add 'jwt-cpp' LICENSE
leolin49 Dec 4, 2024
078f31d
Update prometheus_metrics.md
leolin49 Dec 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ build --copt=-O2
#build --copt=-g --strip=never
build --jobs 16
#test --cache_test_results=no --test_output=errors

build --define trpc_include_prometheus=true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

默认关闭prometheus,这行可以删掉

13 changes: 13 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,19 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI

As an exception, if, as a result of your compiling your source code, portions of this Software are embedded into a machine-executable object form of such source code, you may redistribute such embedded portions in such object form without including the above copyright and permission notices.

Open Source Software Licensed under the MIT with exceptions:
--------------------------------------------------------------------
1. jwt-cpp
Copyright (c) 2018 Dominik Thalhammer

Terms of the MIT with exceptions:
--------------------------------------------------------------------
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


Open Source Software Licensed under the OpenSSL License and the original SSLeay License:
--------------------------------------------------------------------
Expand Down
82 changes: 79 additions & 3 deletions docs/zh/prometheus_metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ client:
| aApp | 主调app名 |
| aServer | 主调server名 |
| aService | 主调service名 |
| aIp | 主调ip地址 |
| pApp | 被调app名 |
| pServer | 被调server名 |
| pService | 被调service名 |
Expand All @@ -109,6 +110,7 @@ client:
| frame_ret_code | 调用的框架错误码 |
| interface_ret_code | 调用的接口错误码 |


### 被调监控上报

只需在框架配置文件的 `server` 中加上 `prometheus` 拦截器,即可开启被调监控:
Expand All @@ -124,7 +126,6 @@ server:

统计数据:

```mermaid
| 监控名 | 监控类型 | 说明 |
| ------ | ------ | ------ |
| rpc_server_counter_metric | Counter | 服务端收到的请求总次数 |
Expand All @@ -149,7 +150,7 @@ server:
| pConSetId | 被调所属set |
| frame_ret_code | 调用的框架错误码 |
| interface_ret_code | 调用的接口错误码 |
```


## 属性监控上报

Expand Down Expand Up @@ -314,7 +315,7 @@ single_metrics_info.single_attr_info.value = 1;

#### 通用多维属性上报

Prometheus 监控插件支持框架通用的多维属性上报方式,即通过构造 `::trpc::TrpcMultiAttrMetricsInfo` 然后使用`::trpc::metrics::MultiAttrReport`接口来上报。**Prometheus 的单维属性上报是指上报统计标签包含多个键值对的数据。**。
Prometheus 监控插件支持框架通用的多维属性上报方式,即通过构造 `::trpc::TrpcMultiAttrMetricsInfo` 然后使用`::trpc::metrics::MultiAttrReport`接口来上报。**Prometheus 的多维属性上报是指上报统计标签包含多个键值对的数据。**。

设置 `::trpc::TrpcMultiAttrMetricsInfo` 值需要注意:

Expand Down Expand Up @@ -398,3 +399,78 @@ std::vector<::prometheus::MetricFamily> Collect();
## 通过 admin 获取

如果服务开启了 [admin 功能](./admin_service.md),则可以通过访问 `http://admin_ip:admin_port/metrics` 获取序列化为字符串后的 Prometheus 数据。

# 鉴权

Prometheus插件鉴权分为两种模式:pull模式 和 push模式,不同模式下的配置方式有所区别。

## pull模式

在pull模式下,使用Json Web Token(JWT)方式来鉴权。需要同时配置**trpc的Prometheus插件**和**Prometheus服务器**。

### 插件配置

插件配置样例如下:

```yaml
plugins:
metrics:
prometheus:
auth_cfg:
iss: admin # issuer 签发人
sub: prometheus-pull # subject 主题
aud: trpc-server # audience 受众
secret: test # 密钥
```

### Prometheus服务器配置

```yaml
global:
scrape_interval: 15s
evaluation_interval: 15s

scrape_configs:
- job_name: trpc-cpp
static_configs:
- targets: ['127.0.0.1:8889']
labels:
instance: trpc-cpp
bearer_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJwcm9tZXRoZXVzLXB1bGwiLCJhdWQiOiJ0cnBjLXNlcnZlciIsImlzcyI6ImFkbWluIiwiaWF0IjoxNTE2MjM5MDIyfQ.WWYY3jgxelzAXzX0IJSmZUeQeqb5YLV4oBAO7FTUI5o
```

需要配置**bearer_token**字段,该token可以通过[JWT官方工具](https://jwt.io/)生成。在payload中填写相应的iss,sub和aud字段,verify signature中填写secret字段,加密算法使用默认的 HS256。

## push模式

在push模式下,为了和pushgateway兼容,鉴权使用**username**和**password**的形式。

### 插件配置

插件配置样例如下:

```yaml
plugins:
metrics:
prometheus:
auth_cfg:
username: admin
password: test
```

### Pushgateway服务器配置

需要在Pushgateway服务器启动时,通过带有通过**bcrypt**加密的密文的配置文件启动。Pushgateway启动的配置文件如下:

```yaml
basic_auth_users:
admin: $2y$05$5uq4H5p8JyfQm.e16o3xduW6tkI2bTRpArTK4MF4dEuvncpz/bqy.
```

密码的密文可以通过htpasswd工具生成:
```shell
> htpasswd -nbB admin test
admin:$2y$05$5uq4H5p8JyfQm.e16o3xduW6tkI2bTRpArTK4MF4dEuvncpz/bqy.
```


10 changes: 10 additions & 0 deletions examples/features/prometheus/proxy/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,13 @@ cc_library(
"@trpc_cpp//trpc/metrics/prometheus:prometheus_metrics_api",
],
)

cc_binary(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不需要push这个文件,去掉与之相关的编译引入

name = "push",
srcs = ["push.cc"],
deps = [
"@trpc_cpp//trpc/metrics/prometheus:prometheus_metrics_api",
"@trpc_cpp//trpc/log:trpc_log",

],
)
6 changes: 6 additions & 0 deletions examples/features/prometheus/proxy/forward_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ ::trpc::Status ForwardServiceImpl::Route(::trpc::ServerContextPtr context,
"counter_name", "counter_desc", {{"const_counter_key", "const_counter_value"}});
::prometheus::Counter& counter = counter_family->Add({{"counter_key", "counter_value"}});
counter.Increment(random_num);

if (::trpc::prometheus::PushMetricsInfo()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为啥这里还需要手动调用呢?不能配置一下yaml文件就生效吗?

TRPC_FMT_INFO("Successfully pushed metrics to Pushgateway");
} else {
TRPC_FMT_ERROR("Failed to push metrics to Pushgateway");
}
#endif

auto client_context = ::trpc::MakeClientContext(context, greeter_proxy_);
Expand Down
22 changes: 22 additions & 0 deletions examples/features/prometheus/proxy/push.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include <chrono>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个文件和框架无关,没必要增加,用法放在文档就好了

#include <thread>
#include "trpc/metrics/prometheus/prometheus_metrics_api.h"
#include "trpc/log/trpc_log.h"



int main(int argc, char** argv) {

while (true) {
if (::trpc::prometheus::PushMetricsInfo())
{
std::cout << "Successfully pushed metrics to Pushgateway" << std::endl;
} else {
std::cerr << "Failed to push metrics to Pushgateway" << std::endl;
}

std::this_thread::sleep_for(std::chrono::seconds(5)); // 每60秒推送一次
}

return 0;
}
10 changes: 10 additions & 0 deletions examples/features/prometheus/proxy/trpc_cpp_fiber.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ plugins:
const_labels:
const_key1: const_value1
const_key2: const_value2
push_mode:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

例子需要演示pull模式和push模式,应该给出2个文件配置

enabled: true
gateway_url: "http://pushgateway:9091"
job_name: "test_job"
push_interval_seconds: 2
auth_cfg:
iss: admin
sub: prometheus-pull
aud: trpc-server
secret: test
log:
default:
- name: default
Expand Down
2 changes: 1 addition & 1 deletion examples/features/prometheus/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ echo "begin"
sleep 1
./bazel-bin/examples/features/prometheus/proxy/forward_server --config=examples/features/prometheus/proxy/trpc_cpp_fiber.yaml &
sleep 1
./bazel-bin/examples/features/prometheus/client/client_config --config=examples/features/prometheus/client/trpc_cpp_fiber.yaml
./bazel-bin/examples/features/prometheus/client/client --client_config=examples/features/prometheus/client/trpc_cpp_fiber.yaml

killall helloworld_svr
if [ $? -ne 0 ]; then
Expand Down
Empty file.
12 changes: 12 additions & 0 deletions third_party/com_github_thalhammer_jwt_cpp/jwt_cpp.BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package(
default_visibility = ["//visibility:public"],
)

cc_library(
name = "jwt-cpp",
hdrs = glob(["**/*.h"]),
deps = [
"@com_github_openssl_openssl//:libcrypto",
"@com_github_openssl_openssl//:libssl",
],
)
7 changes: 7 additions & 0 deletions trpc/admin/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -354,13 +354,20 @@ cc_library(
":admin_handler",
":base_funcs",
"//trpc/util:prometheus",
"//trpc/common/config:trpc_config",
"//trpc/log:trpc_log",
"//trpc/util/http:base64",
"//trpc/util/string:string_helper",
"//trpc/util:jwt",
] + select({
"//conditions:default": [],
"//trpc:trpc_include_prometheus": [
"@com_github_jupp0r_prometheus_cpp//pull",
"//trpc/metrics/prometheus:prometheus_metrics",
],
"//trpc:include_metrics_prometheus": [
"@com_github_jupp0r_prometheus_cpp//pull",
"//trpc/metrics/prometheus:prometheus_metrics",
],
}),
)
Expand Down
4 changes: 3 additions & 1 deletion trpc/admin/admin_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@ AdminService::AdminService() {

#ifdef TRPC_BUILD_INCLUDE_PROMETHEUS
// Prometheus metrics.
RegisterCmd(http::OperationType::GET, "/metrics", std::make_shared<admin::PrometheusHandler>());
auto prometheus_handle_ptr = std::make_shared<admin::PrometheusHandler>();
prometheus_handle_ptr->Init();
RegisterCmd(http::OperationType::GET, "/metrics", prometheus_handle_ptr);
#endif

RegisterCmd(http::OperationType::POST, "/client_detach", std::make_shared<admin::ClientDetachHandler>());
Expand Down
77 changes: 77 additions & 0 deletions trpc/admin/prometheus_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,87 @@ namespace trpc::admin {

PrometheusHandler::PrometheusHandler() { description_ = "[GET /metrics] get prometheus metrics"; }

void PrometheusHandler::Init() {
PrometheusConfig prometheus_conf;
bool ret = TrpcConfig::GetInstance()->GetPluginConfig<PrometheusConfig>(
"metrics", trpc::prometheus::kPrometheusMetricsName, prometheus_conf);
if (!ret) {
TRPC_LOG_WARN(
"Failed to obtain Prometheus plugin configuration from the framework configuration file. Default configuration "
"will be used.");
}
auth_cfg_ = prometheus_conf.auth_cfg;
}

bool PrometheusHandler::CheckTokenAuth(std::string bearer_token) {
auto splited = Split(bearer_token, ' ');
if (splited.size() != 2) {
TRPC_FMT_ERROR("error token: {}", bearer_token);
return false;
}
auto method = splited[0];
if (method != "Bearer") {
TRPC_FMT_ERROR("error auth method: {}", method);
return false;
}
std::string token = std::string(splited[1]);
if (!Jwt::isValid(token, auth_cfg_)) {
TRPC_FMT_ERROR("error token: {}", token);
return false;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

构造函数做了太复杂的事情,可以定义一个Init函数,把这部分逻辑放在Init函数里

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已修改。

return true;
}

bool PrometheusHandler::CheckBasicAuth(std::string token) {
auto splited = Split(token, ' ');
if (splited.size() != 2) {
TRPC_FMT_ERROR("error token: {}", token);
return false;
}
if (splited[0] != "Basic") {
TRPC_FMT_ERROR("error token: {}", token);
return false;
}

std::string username_pwd = http::Base64Decode(std::begin(splited[1]), std::end(splited[1]));
auto sp = Split(username_pwd, ':');
if (sp.size() != 2) {
TRPC_FMT_ERROR("error token: {}", token);
return false;
}

auto username = sp[0], pwd = sp[1];
if (username != auth_cfg_["username"] || pwd != auth_cfg_["password"]) {
TRPC_FMT_ERROR("error username or password: username: {}, password: {}", username, pwd);
return false;
}
return true;
}

void PrometheusHandler::CommandHandle(http::HttpRequestPtr req, rapidjson::Value& result,
rapidjson::Document::AllocatorType& alloc) {
static std::unique_ptr<::prometheus::Serializer> serializer = std::make_unique<::prometheus::TextSerializer>();

std::string token = req->GetHeader("authorization");

if (!auth_cfg_.empty()) {
if (auth_cfg_.count("username") && auth_cfg_.count("password")) {
// push mode
// use the basic auth if already config the username and password.
if (!CheckBasicAuth(token)) {
result.AddMember("message", "wrong request without right username or password", alloc);
return;
}
} else {
// pull mode
// use the json web token auth.
if (!CheckTokenAuth(token)) {
result.AddMember("message", "wrong request without right token", alloc);
return;
}
}
}

std::string prometheus_str = serializer->Serialize(trpc::prometheus::Collect());
result.AddMember(rapidjson::StringRef("trpc-html"), rapidjson::Value(prometheus_str, alloc).Move(), alloc);
}
Expand Down
16 changes: 16 additions & 0 deletions trpc/admin/prometheus_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@
#pragma once

#include "trpc/admin/admin_handler.h"
#include "trpc/common/config/trpc_config.h"
#include "trpc/log/trpc_log.h"
#include "trpc/metrics/prometheus/prometheus_metrics.h"
#include "trpc/util/http/base64.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

用clang-format格式化一下,头文件顺序需要按照字母序顺序排列

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已修改。

#include "trpc/util/jwt.h"
#include "trpc/util/prometheus.h"
#include "trpc/util/string/string_helper.h"
#include "trpc/util/time.h"

namespace trpc::admin {

Expand All @@ -24,8 +31,17 @@ class PrometheusHandler : public AdminHandlerBase {
public:
PrometheusHandler();

void Init();

void CommandHandle(http::HttpRequestPtr req, rapidjson::Value& result,
rapidjson::Document::AllocatorType& alloc) override;

private:
bool CheckTokenAuth(std::string token);

bool CheckBasicAuth(std::string token);

std::map<std::string, std::string> auth_cfg_;
};

} // namespace trpc::admin
Expand Down
2 changes: 1 addition & 1 deletion trpc/common/plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class Plugin : public RefCounted<Plugin> {

/// @brief Stop the runtime environment of the plugin
virtual void Stop() noexcept {}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

记得用clang-format把所有代码文件都格式化一遍(使用项目根目录的.clang-format配置的格式化规范)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里出现了不必要的空格

/// @brief destroy plugin internal resources
virtual void Destroy() noexcept {}

Expand Down
Loading
Loading