Corsair Grafana 插件接入指南:用 API Key 打通 Grafana 观测数据、Loki 日志与 Mimir 集群状态
2026/9/16 15:32:56 网站建设 项目流程

Corsair Grafana 插件接入指南:用 API Key 打通 Grafana 观测数据、Loki 日志与 Mimir 集群状态

【免费下载链接】corsairConnect your users to their apps项目地址: https://gitcode.com/GitHub_Trending/corsa/corsair

本指南以 packages/grafana/README.md 为骨架,完整讲解@corsair-dev/grafana这一 Corsair 官方 Grafana 插件的安装、认证、11 个内置端点、权限配置、错误重试与数据持久化机制,并深入源码验证每个端点对应的真实 Grafana API 路径。读完你将能在自己的 Corsair 应用中一键接入 Grafana,让 AI Agent 安全地查询公共仪表盘、写入 Loki 日志、检查 Mimir 哈希环状态与 Enterprise 许可证状态。

安装与依赖

@corsair-dev/grafana是 Corsair 生态中的 Grafana 连接插件,通过 pnpm 安装:

pnpm add @corsair-dev/grafana

从 packages/grafana/package.json 可以看到,它声明了两个 peerDependencies:

  • corsair >= 0.1.0:Corsair 核心运行时,提供插件上下文、认证、请求、日志等基础设施;
  • zod ^4.1.13:用于端点输入/输出 schema 的运行时校验。

插件使用 TypeScript 编写并以 ESM 形式发布("type": "module"),包入口为dist/index.js,同时通过exports["."]["dev-source"]暴露源码路径方便开发调试。安装完成后,用corsair核心包中注册插件的方式将其挂载到你的 Corsair 应用中即可。

快速接入:注册 Grafana 插件

在 packages/grafana/index.ts 中,插件以工厂函数grafana(options)的形式导出。最小接入方式如下:

import { grafana } from '@corsair-dev/grafana'; export const grafanaPlugin = grafana({ authType: 'api_key', key: process.env.GRAFANA_SERVICE_ACCOUNT_TOKEN, grafanaUrl: 'https://example.grafana.net', });

GrafanaPluginOptions支持的完整配置项如下(类型定义见 packages/grafana/index.ts):

配置项类型说明
authType'api_key'认证方式,当前固定为api_key,未传时默认为api_key
keystringGrafana Service Account Token,作为 Bearer Token 使用;也可不传,改由运行时通过corsair auth动态获取
grafanaUrlstringGrafana 实例基础 URL,例如https://example.grafana.net
hooks插件钩子透传给 Corsair 的插件生命周期钩子
webhookHooks插件钩子Grafana 插件未定义 webhook,保留字段
errorHandlersCorsairErrorHandler自定义错误处理器,会与插件内置错误处理器合并
permissions权限配置控制 AI Agent 可调用的端点,使用端点树的点分路径,路径非法会触发类型错误

在插件内部,grafana()工厂把端点组织为嵌套结构(logshealthstatusringstoreGatewaysamldashboardsjwks),并一次性注册了 endpointMeta(风险等级与描述)、endpointSchemas(zod 输入输出校验)与错误处理器。

插件 ID 与认证配置

插件 ID 固定为'grafana'。值得注意的是一段自定义认证配置(packages/grafana/index.ts):

export const grafanaAuthConfig = { api_key: { account: ['grafana_url', 'org_id'] as const, }, } as const satisfies PluginAuthConfig;

这意味着通过corsair auth为租户录入凭证时,除了 API Key 本身,还可以附带grafana_urlorg_id两个账户级字段。grafana_url会在每个端点的实现中被读取(ctx.keys.get_grafana_url()),从而让实例 URL 随租户凭证存储,而不是硬编码在插件配置里——这是多租户场景下避免写死 URL 的关键设计。org_id同样被预留为账户字段,便于区分不同 Grafana 组织。

认证机制:API Key 与 Service Account Token

README 明确指出本插件认证方式为API key,并说明"Corsair prompts your tenant for credentials on first use",即租户首次使用时 Corsair 会提示录入凭证。

从源码keyBuilder(packages/grafana/index.ts)可以看到凭证解析的完整逻辑:

  1. 若请求来源为webhook,直接返回空字符串(Grafana 插件没有 webhook);
  2. 若请求来源为endpoint且插件配置了options.key,优先使用配置中的 Service Account Token;
  3. 否则从ctx.keys.get_api_key()读取租户在corsair auth中录入的 API Key;
  4. 读取失败时抛出AuthMissingError('grafana', 'api_key'),提示用户补充凭证。

传输安全:强制 HTTPS

底层客户端 packages/grafana/client.ts 在发起任何请求前都会执行assertHttpsGrafanaBaseUrl:剥离 URL 尾部的斜杠、校验 URL 合法性,并且只允许https:协议,否则直接抛出GrafanaAPIError,拒绝将 Bearer Token 发送到非 HTTPS 地址。这是针对令牌泄露风险的一道硬性防线。

两种请求通道

客户端提供两个底层函数:

  • makeGrafanaRequest:发送 JSON 请求(GET/POST/PUT/DELETE/PATCH),自动附加Authorization: Bearer <token>Content-Type: application/json,用于 health、status 等标准 REST 接口;
  • makeGrafanaRawRequest:发送原始请求并返回{ content, content_type, status_code },用于返回 HTML 页面或表单编码体的端点(如 Mimir ring 状态页、SAML ACS、Loki OTLP 写入),POST 时支持自定义contentType

此外,GRAFANA_RATE_LIMIT_CONFIG(packages/grafana/client.ts)内置了速率限制处理:启用重试、最多 3 次、初始退避 1s、指数退避倍数 2,并读取Retry-After响应头。

端点总览

插件共暴露11 个端点,覆盖 Grafana 的观测、鉴权与 Mimir 集群运维能力。以下是 README 中的端点速查表:

操作Operation ID风险描述
dashboards.queryPublicgrafana.api.dashboards.queryPublicread查询公共 Grafana 仪表盘上的面板
health.getgrafana.api.health.getread检查 Grafana 服务器健康状态与数据库连通性
jwks.retrievegrafana.api.jwks.retrieveread获取用于令牌验证的 JWKS 公钥
logs.createOtlpgrafana.api.logs.createOtlpwrite通过 OTLP v1 向 Grafana Loki 发送日志
ring.getDistributorHaTrackergrafana.api.ring.getDistributorHaTrackerread获取 distributor HA tracker ring 状态
ring.getIndexGatewaygrafana.api.ring.getIndexGatewayread获取 index gateway 哈希环状态
ring.getOverridesExportergrafana.api.ring.getOverridesExporterread获取 overrides-exporter 哈希环状态
ring.getRulergrafana.api.ring.getRulerread获取 Grafana Mimir 的 ruler ring 状态
saml.postAcsgrafana.api.saml.postAcswrite处理 SAML Assertion Consumer Service 认证响应
status.getgrafana.api.status.getread检查 Grafana Enterprise 许可证可用性
storeGateway.getTenantsgrafana.api.storeGateway.getTenantsread列出 store-gateway 存储中拥有块的租户

其中read风险端点 9 个、write风险端点 2 个(logs.createOtlpsaml.postAcs)。风险等级在grafanaEndpointMeta中集中声明(packages/grafana/index.ts),Corsair 权限系统会据此约束 Agent 行为。所有端点的输入/输出 schema 定义在 packages/grafana/endpoints/types.ts,并在 packages/grafana/endpoints/index.ts 中聚合导出。

下面按功能域深入每个端点的实现细节与真实 API 路径。

dashboards.queryPublic:查询公共仪表盘面板

对应 Grafana 公共仪表盘 API,实现位于 packages/grafana/endpoints/dashboards.ts。

输入参数(来自DashboardsQueryPublicInputSchema):

参数类型必填说明
access_tokenstring公共仪表盘的访问令牌
panel_idnumber要查询的面板 ID
from/tostring时间范围
intervalMsnumber采样间隔(毫秒)
maxDataPointsnumber最大数据点数
base_url_overridestring覆盖默认 Grafana 实例 URL

实现通过makeGrafanaRawRequest以 POST 方式请求/api/public/dashboards/{access_token}/panels/{panel_id}/query(packages/grafana/endpoints/dashboards.ts),并尝试将响应解析为 JSON,取results字段;若返回的是 HTML 错误页则回退为把原始内容放入message字段。查询成功后,结果会以${access_token}-${panel_id}为唯一键 upsert 到数据库的dashboardQueries表,并记录grafana.dashboards.queryPublic事件日志。

health.get 与 status.get:健康与许可证检查

两个端点都调用 JSON 通道,实现在 packages/grafana/endpoints/health.ts:

  • health.get请求/api/health,返回{ version, commit, database, enterpriseCommit }等字段,用于判断 Grafana 服务器与底层数据库是否健康;
  • status.get请求/api/licensing/check,通过raw.hasLicense === truelicenseExpiry > Date.now() / 1000计算license_available布尔值,用于判断 Enterprise 许可证是否有效。

两者的结果都会写入healthStatus表(status.get在已有记录上合并licenseAvailable字段),便于后续审计与状态追溯。

logs.createOtlp:向 Loki 写入 OTLP 日志

这是本插件唯一的日志写入端点,实现于 packages/grafana/endpoints/logs.ts。它通过原始请求通道 POST/otlp/v1/logs,请求体为 OTLP 的resourceLogs结构(ResourceLog → ScopeLog → LogRecord,每层 schema 见 packages/grafana/endpoints/types.ts)。

成功(2xx)后,插件会将日志记录扁平化持久化:把 resource attributes 展平为字符串键值对、提取scope.namescope.version、以body.stringValue优先存储日志正文(否则 JSON 序列化整个 body),并用crypto.randomUUID()生成唯一 ID 写入logs表。

ring.* 与 storeGateway.getTenants:Mimir 集群状态

四个ring.*端点与storeGateway.getTenants面向 Grafana Mimir 的哈希环运维场景,实现见 packages/grafana/endpoints/ring.ts,全部通过原始请求通道返回 HTML 页面:

端点请求路径数据落库 key
ring.getDistributorHaTracker/distributor/ha-trackerdistributor-ha-tracker
ring.getIndexGateway/index-gateway/ringindex-gateway
ring.getOverridesExporter/overrides-exporter/ringoverrides-exporter
ring.getRuler/ruler/ringruler
storeGateway.getTenants/store-gateway/tenantsstore-gateway-tenants

响应中html_contentcontent连同content_typestatus_code一起写入ringStatus表。这类端点让 Agent 能快速巡检 Mimir 各组件哈希环的健康状态、租户块分布等信息,是监控告警类 Agent 的高价值能力。

saml.postAcs:处理 SAML 认证响应

write风险端点,实现于 packages/grafana/endpoints/auth.ts。输入为saml_response(必填)与relay_state(可选)。实现将参数编码为application/x-www-form-urlencoded表单,POST 到/login/saml/acs(packages/grafana/endpoints/auth.ts)。

返回结果会判断是否 302 重定向,并尝试从返回内容中正则提取<meta ... url=...>形式的跳转地址作为location。每次处理都会以saml-${saml_response 前 16 位}为稳定 session ID 写入samlSessions表。

jwks.retrieve:获取令牌验证公钥

同样实现于 packages/grafana/endpoints/auth.ts,该端点按顺序探测三个已知 JWKS 路径,直到拿到 200 响应为止:

  1. /api/signing-keys/jwks
  2. /.well-known/jwks.json
  3. /api/jwks

拿到 JSON 后解析出keys数组;JWKS 中每个 key 的Key(密钥材料)、UseAlgorithmCertificates等字段会展开存入jwksKeys表。这为验证 Grafana 签发的令牌提供了公钥获取通道。

权限配置:限制 Agent 可调用的端点

插件通过permissions选项控制 AI Agent 的调用边界,类型定义明确指出"Overrides use dot-notation paths from the Grafana endpoint tree — invalid paths are type errors"。由于权限路径是类型化的,写错端点路径会在编译期直接报错,而不是留到运行时。示例:

grafana({ key: process.env.GRAFANA_SERVICE_ACCOUNT_TOKEN, permissions: { // 只允许读取健康状态,禁止写入 'health.get': true, 'logs.createOtlp': false, }, });

结合 endpointMeta 中的风险等级(packages/grafana/index.ts),可以实现"默认只读、按需开放写操作"的精细化授权策略,降低 Agent 误操作风险。

错误处理与重试策略

插件内置了一套完整的错误处理器,定义在 packages/grafana/error-handlers.ts,覆盖六类场景:

错误类型匹配条件处理策略
RATE_LIMIT_ERRORHTTP 429 或消息含 rate_limited/ratelimited/429最多重试 5 次,优先采用Retry-After
AUTH_ERRORHTTP 401 或 unauthorized/invalid token/token expired 等不重试,提示检查 Service Account Token
PERMISSION_ERRORHTTP 403 或 forbidden/permission denied 等不重试
NOT_FOUND_ERRORHTTP 404 或 not found不重试
NETWORK_ERROR消息含 network/connection/ECONNREFUSED/ETIMEDOUT 等最多重试 3 次
DEFAULT兜底匹配一切不重试,记录 unhandled error

开发者可以通过grafana({ errorHandlers })传入自定义处理器,插件会在构造时用{ ...errorHandlers, ...options.errorHandlers }合并(packages/grafana/index.ts),自定义项覆盖同名内置项。

数据持久化:插件内置的数据库表

插件的 schema 定义在 packages/grafana/schema/database.ts,包含 6 张表对应的 zod schema:

用途主要字段
healthStatus健康与许可证状态versioncommitdatabaselicenseAvailablecheckedAt
logsLoki 摄入的日志记录timeUnixNanoseverityTextbodytraceIdspanIdresourcescope
dashboardQueries公共仪表盘查询历史accessTokenpanelIdfromtoresultsqueriedAt
ringStatusMimir 哈希环状态快照contentcontentTypestatusCodefetchedAt
jwksKeysJWKS 公钥记录usealgorithmcertificateskeyMaterial
samlSessionsSAML ACS 处理记录statusCodelocationmessagesuccessful

所有表均以.loose()声明,允许保存 Grafana 返回的未知扩展字段。端点在成功时通过ctx.db.xxx.upsertByEntityId写入,失败时仅返回错误而不会污染历史数据——这种"成功才落库"的约定保证了数据库里只保留有效观测记录。

测试与验证

插件提供了基于 Jest 的测试,见 packages/grafana/api.test.ts 与 packages/grafana/client.test.ts。api.test.ts是针对真实 Grafana 实例的集成测试,依赖以下环境变量:

  • GRAFANA_BEARER_TOKEN:Service Account Token;
  • GRAFANA_URL:Grafana 实例地址;
  • GRAFANA_PUBLIC_DASHBOARD_ACCESS_TOKEN/GRAFANA_PUBLIC_DASHBOARD_PANEL_ID:公共仪表盘测试令牌与面板 ID(可选)。

测试逐一调用 11 个端点并用GrafanaEndpointOutputSchemas.*校验返回结构与声明类型一致,client.test.ts则覆盖客户端请求构造与 HTTPS 校验逻辑。本地可通过pnpm test运行(见 packages/grafana/package.json)。

Webhooks 与许可证

README 明确说明 Grafana 插件无 webhook 触发("No webhooks")。源码中grafanaWebhooksNested为空对象、pluginWebhookMatcher恒返回false(packages/grafana/index.ts),keyBuilder对 webhook 来源直接返回空字符串。因此本插件仅需处理出站 API 调用,无需配置入站 webhook 接收地址。

插件遵循Apache-2.0开源许可发布,配置元数据(displayName、description)见 packages/grafana/plugin-docs.yaml,可用于在 Corsair Hub 中展示。

总结

@corsair-dev/grafana以极简的接入方式(一条pnpm add+ 一个grafana()工厂调用)为 Corsair 应用补全了 Grafana 观测能力:读取健康与许可证状态、查询公共仪表盘、向 Loki 写入 OTLP 日志、巡检 Mimir 哈希环、处理 SAML 与 JWKS 令牌流程。其强制的 HTTPS 传输、类型化权限路径、内置错误重试与"成功才落库"的持久化约定,使它适合作为多租户 AI Agent 的 Grafana 数据网关,相关实现均可继续在 packages/grafana 目录下深入阅读。

【免费下载链接】corsairConnect your users to their apps项目地址: https://gitcode.com/GitHub_Trending/corsa/corsair

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询