c++ 一个不是用Go语言编写的Grafana后端插件是如何传递连接设置的呢?

wbrvyc0a  于 2023-01-15  发布在  Go
关注(0)|答案(1)|浏览(158)

我正在尝试用C编写一个Grafana后端插件。我这样做是为了与一个具有C API的自定义工具(称为“灯塔”)集成。我创建了一个C++ gRPC应用程序,该应用程序按照本文档的建议实现了Grafana plugin protocol
我的问题是:连接设置,例如gRPC服务器端口,如何在主Grafana进程和后端插件之间通信。我希望能够在plugin.json配置文件中指定连接字符串或端口号,但似乎没有any such field
我安装了我的插件并试图加载它。当然,它没有工作,但给了我这个日志输出:

logger=plugin.loader t=2023-01-11T11:58:25.984652862Z level=debug msg="Loading plugin" path=/var/lib/grafana/plugins/lighthouse-datasource/plugin.json
logger=plugin.loader t=2023-01-11T11:58:25.984878566Z level=debug msg="Plugin is unsigned" id=lighthouse-datasource
logger=plugin.signature.validator t=2023-01-11T11:58:25.984904895Z level=warn msg="Permitting unsigned plugin. This is not recommended" pluginID=lighthouse-datasource pluginDir=/var/lib/grafana/plugins/lighthouse-datasource
logger=plugin.loader t=2023-01-11T11:58:25.984925224Z level=info msg="Plugin registered" pluginID=lighthouse-datasource
logger=plugin.lighthouse-datasource t=2023-01-11T11:58:25.984963175Z level=debug msg="starting plugin" path=/var/lib/grafana/plugins/lighthouse-datasource/lighthouse_backend_linux_amd64 args=[/var/lib/grafana/plugins/lighthouse-datasource/lighthouse_backend_linux_amd64]
logger=plugin.lighthouse-datasource t=2023-01-11T11:58:25.985195211Z level=debug msg="plugin started" path=/var/lib/grafana/plugins/lighthouse-datasource/lighthouse_backend_linux_amd64 pid=7065
logger=plugin.lighthouse-datasource t=2023-01-11T11:58:25.98523206Z level=debug msg="waiting for RPC address" path=/var/lib/grafana/plugins/lighthouse-datasource/lighthouse_backend_linux_amd64
logger=plugin.loader t=2023-01-11T11:59:31.176451438Z level=error msg="Could not start plugin" pluginId=lighthouse-datasource err="timeout while waiting for plugin to start"
logger=plugin.lighthouse-datasource t=2023-01-11T11:59:31.177010088Z level=debug msg="plugin process exited" path=/var/lib/grafana/plugins/lighthouse-datasource/lighthouse_backend_linux_amd64 pid=7065 error="signal: killed"

消息msg="waiting for RPC address"表明Grafana进程正在等待某个东西(可能是插件本身)来提供gRPC地址。如果这种解释是正确的,那么插件应该如何提供这个信息呢?

osh3o9ms

osh3o9ms1#

通过查找"waiting for RPC address"消息的来源,我最终找到了这一点,结果发现该消息来自HashiCorp go-plugin中的代码,正如那里所描述的,插件实现了服务器部分,而插件用户(在本例中为Grafana)实现了客户端部分。
在浏览了代码之后,我能够拼凑出事情是如何组合在一起的。Grafana将插件可执行文件作为子进程生成,然后附加管道来捕获它的stdout和stderr。Grafana期望一个特殊的管道分隔值输出到stdout,其中包括连接信息。对于我的简单情况,值输出如下所示:

1|2|unix|/tmp/some_path_for_uds|grpc

Grafana记录插件的stderr输出,这对调试很有用。
我在上面犯了一个错误,如果你运行Unix/Linux,那么插件架构期望gRPC使用Unix域套接字。这是有道理的,但我之前没有想到。所以在我的例子中,我期望的地址+端口只是UDS文件系统路径,如上所示。
下面是我的C++插件入口点的最后一个粗略版本:

#include <cstdint>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>

#include <grpcpp/grpcpp.h>

#include "DiagnosticsServiceImpl.h"
#include "Logger/Logger.h"

void RunServer(const std::string& udsAddress)
{
    const std::string addressURI("unix://" + udsAddress);
    ::unlink(udsAddress.c_str());
    
    DiagnosticsServiceImpl service;

    grpc::EnableDefaultHealthCheckService(true);
    grpc::reflection::InitProtoReflectionServerBuilderPlugin();
    grpc::ServerBuilder builder;
    
    // Listen on the given address without any authentication mechanism.
    builder.AddListeningPort(addressURI, grpc::InsecureServerCredentials());
    
    // Register "service" as the instance through which we'll communicate with
    // clients. In this case it corresponds to an *synchronous* service.
    builder.RegisterService(&service);
    
    // Finally assemble the server.
    std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
    std::cerr << "Server listening on " << udsAddress;
    
    // Build start handshake output
    std::ostringstream strm;
    strm << "1|2|unix|" << udsAddress << "|grpc\n";
    const std::string startOutput(strm.str());
    
    // Now output it
    std::cout << startOutput << std::endl;

    // Wait for the server to shutdown. Note that some other thread must be
    // responsible for shutting down the server for this call to ever return.
    server->Wait();
}

int main(int argc, char** argv)
{
    const std::string udsAddress("/tmp/lighthouse_backend_plugin_uds");
    
    std::cerr << "Grafana Lighthouse Backend Plugin starting...";
    
    RunServer(udsAddress);
    
    std::cerr << "Grafana Lighthouse Backend Plugin terminating...";
    
    return 0;
}

这花了我几天的时间才弄清楚,所以希望它能在未来为某人节省一些时间。

相关问题