OpenTelemetry Google Cloud Monitoring Exporter 接入指南:将 Go 指标写入 Google Cloud Monitoring
2026/9/23 15:35:29 网站建设 项目流程
  • 人工智能
  • AI Agent
  • Agent 沙箱
  • 云原生
  • 容器运行时
  • 零信任

【免费下载链接】substrate

Agent Substrate: the core system

项目地址:https://gitcode.com/GitHub_Trending/substrate7/substrate
点击查看免费下载

导读

本文以 substrate 仓库中随 vendored 依赖引入的 opentelemetry-operations-go/exporter/metric 文档为主体,讲解如何在 Go 应用中把 OpenTelemetry 采集的指标(Metrics)导出到 Google Cloud Monitoring(GCM)。读完本文你将掌握:Google Cloud Monitoring 的前置 Workspace 设置、基于应用默认凭据(ADC)的认证机制、WithProjectID等核心配置项的用法,以及该 exporter 在底层如何完成 MetricDescriptor 创建、TimeSeries 批量上传与指标类型映射。文末还会结合仓库源码给出全部可用的Option配置项说明与真实调用链。


一、Exporter 是什么:把 OTel 指标送达 Google Cloud Monitoring

本小节内容基于 exporter/metric/README.md 的开篇描述。

OpenTelemetry Google Cloud Monitoring Exporter是一个标准的 OpenTelemetry Metric Exporter,它允许用户把程序内采集并聚合好的指标数据发送到 Google Cloud(即 Google Cloud Monitoring 服务)。在 substrate 仓库中,该模块以 vendored 形式存在于 vendor/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric/ 目录下,包含以下源文件:

  • cloudmonitoring.go:导出器入口构造函数New(),负责默认凭据探测与metricExporter初始化;
  • option.go:定义Option函数类型与全部可配置项;
  • metric.go:核心实现,完成指标描述符创建、时间序列转换与批量上传;
  • constants.go:历史遗留的资源标签键与受监控资源类型常量(多数已标记 Deprecated);
  • error.go:导出器相关错误定义;
  • version.go:当前版本号0.55.0

在 Go 模块层面,该包以间接依赖的形式被仓库引用,见 go.mod:

github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.33.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.55.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.55.0 // indirect

其中internal/resourcemapping被 metric.go 用来完成 OTel Resource 到 Cloud Monitoring MonitoredResource 的自动映射,这将在后文详述。

Google Cloud Monitoring 本身是一个托管服务,它收集来自 Google Cloud、AWS、托管可用性探测、应用埋点以及 Cassandra、Nginx、Apache、Elasticsearch 等常见中间件的指标、事件和元数据,并通过仪表盘、图表和告警(可对接 Slack、PagerDuty 等)把数据转化为可操作的洞察。


二、前置准备:先创建 Monitoring Workspace

对应 README 的 Setup 一节。

Google Cloud Monitoring 是 GCP 提供的托管服务,使用前必须预先创建 Workspace。Workspace 是 Cloud Monitoring 中的数据组织单元,指标、仪表盘与告警策略都归属于某个 Workspace。官方要求在使用该 exporter 前完成 Workspace 的创建,创建入口位于 Google Cloud 控制台的 Monitoring 页面("Create Workspace" 流程)。

提示:本文档仅确认"必须预先创建 Workspace"这一事实。创建 Workspace 的具体操作步骤属于 GCP 控制台交互流程,需以 Google Cloud 官方文档为准,本仓库并未包含该流程的实现代码。


三、认证机制:应用默认凭据(ADC)的自动探测

对应 README 的 Authentication 一节。

该 exporter 的认证完全依赖 Go 生态的google.FindDefaultCredentialsgolang.org/x/oauth2/google包)。也就是说:默认情况下,服务账号会自动被探测到,无需手工传凭据。README 引用其官方说明,ADC 的探测顺序如下:

  1. 读取环境变量GOOGLE_APPLICATION_CREDENTIALS指定的 JSON 文件路径(即通常所说的service_account_key.json服务账号密钥文件);
  2. 读取 gcloud 命令行工具已知位置的 JSON 文件:
    • Windows:%APPDATA%/gcloud/application_default_credentials.json
    • 其他系统:$HOME/.config/gcloud/application_default_credentials.json

源码层面,这一探测逻辑体现在 cloudmonitoring.go 的New()中:

func New(opts ...Option) (sdkmetric.Exporter, error) { o := options{ context: context.Background(), resourceAttributeFilter: DefaultResourceAttributesFilter, } for _, opt := range opts { opt(&o) } if o.projectID == "" { creds, err := google.FindDefaultCredentials(o.context, monitoring.DefaultAuthScopes()...) if err != nil { return nil, fmt.Errorf("failed to find Google Cloud credentials: %v", err) } if creds.ProjectID == "" { return nil, errors.New("google cloud monitoring: no project found with application default credentials") } o.projectID = creds.ProjectID } return newMetricExporter(&o) }

两个值得注意的实现细节:

  • 只有当用户没有通过WithProjectID显式指定项目时,才会触发google.FindDefaultCredentials探测;探测成功后,项目 ID 会直接取自凭据中的ProjectID字段;
  • 如果凭据探测失败或凭据中不包含项目 ID,New()会分别返回 "failed to find Google Cloud credentials" 与 "no project found with application default credentials" 两类错误,而非静默使用空项目。

本地运行时需要额外指定项目 ID

README 特别指出:在本地开发环境运行时,仅有GOOGLE_APPLICATION_CREDENTIALS往往还不够,还需要显式指定 Google Project ID。最佳实践是借助环境变量(例如GOOGLE_CLOUD_PROJECT)配合metric.WithProjectID方法完成:

projectID := os.Getenv("GOOGLE_CLOUD_PROJECT") opts := []mexporter.Option{ mexporter.WithProjectID(projectID), }

这样构造出的opts后续可传给mexporter.New(opts...),确保导出目标项目与凭据归属项目一致。


四、核心配置项全景:Option 与默认行为

本小节基于 option.go 的完整实现展开。

Option是一个函数类型func(*options),所有配置都以函数式选项的方式传入New()options结构体(option.go#L42-L94)完整定义如下:

配置项类型默认行为对应 Option 函数
contextcontext.Contextcontext.Background()无(仅内部字段,见New()初始化)
projectIDstring从 ADC 凭据自动探测WithProjectID(id)
metricDescriptorTypeFormatterfunc(metricdata.Metrics) string"workload.googleapis.com/[metric name]"WithMetricDescriptorTypeFormatter(f)
resourceAttributeFilterattribute.Filter仅保留service.nameservice.namespaceservice.instance.idWithFilteredResourceAttributes(filter)
monitoredResourceDescriptionMonitoredResourceDescription关闭,走通用 resourcemappingWithMonitoredResourceDescription(mrType, mrLabels)
compressionstring不压缩WithCompression(c)
monitoringClient*monitoring.MetricClient自动创建WithMonitoringClient(cl)
monitoringClientOptions[]apioption.ClientOptionWithMonitoringClientOptions(opts...)
destinationProjectQuotabool关闭WithDestinationProjectQuota()
disableCreateMetricDescriptorsbool关闭(自动创建描述符)WithDisableCreateMetricDescriptors()
enableSumOfSquaredDeviationbool关闭WithSumOfSquaredDeviation()
createServiceTimeSeriesbool关闭WithCreateServiceTimeSeries()

逐一说明各配置项的实际影响:

1.WithProjectID(id)— 指定目标项目

设置指标上传的目标 GCP 项目。若不调用此选项,项目 ID 会从默认凭据探测流程中自动获取(见上一节)。在metricExporter内部,该值被拼进三类请求的资源名:

  • 指标描述符查询/创建:projects/{projectID}/metricDescriptors/...projects/{projectID}(metric.go#L216-L233);
  • 时间序列上传:projects/{projectID}(metric.go#L244);
  • 直方图 Exemplar 中的 Span 关联:projects/{projectID}/traces/{traceID}/spans/{spanID}(metric.go#L785-L795)。

同时,该 projectID 会被用于 GCM 受监控资源的project_id标签——当资源本身不属于某个特定项目时(例如本地/自建环境下的k8s_containergeneric_task),这一标签尤为关键。

2.WithMetricDescriptorTypeFormatter(f)— 自定义指标类型命名

控制 MetricDescriptor 的Type字段格式。默认格式串为"workload.googleapis.com/[metric name]",定义于 metric.go#L61:

cloudMonitoringMetricDescriptorNameFormat = "workload.googleapis.com/%s"

自定义 formatter 的签名是func(metricdata.Metrics) string,实际生效逻辑见 metric.go#L276-L281。注意:自定义格式必须遵守 GCM 自定义指标命名约定(官方要求形如workload.googleapis.com/xxxcustom.googleapis.com/xxx等域前缀格式),否则 GCM API 会拒绝创建。

3.WithFilteredResourceAttributes(filter)— 控制资源属性是否下沉为指标标签

决定 OTel Resource 的哪些属性会作为额外的 metric label 附加到指标上。默认过滤器是DefaultResourceAttributesFilter(option.go#L157-L161),仅保留三个语义化约定属性且要求值非空:

func DefaultResourceAttributesFilter(kv attribute.KeyValue) bool { return (kv.Key == semconv.ServiceNameKey || kv.Key == semconv.ServiceNamespaceKey || kv.Key == semconv.ServiceInstanceIDKey) && len(kv.Value.AsString()) > 0 }

这样做是为了避免针对同一受监控资源写入重复的时间序列。若想完全关闭资源属性下沉,可传入NoAttributes()

mexporter.WithFilteredResourceAttributes(mexporter.NoAttributes())

4.WithDisableCreateMetricDescriptors()— 关闭自动描述符创建

默认情况下,导出器在遇到尚未注册的指标时会自动调用 GCM 的CreateMetricDescriptor。调用此选项可关闭该行为——适用于预先手工创建好 MetricDescriptor 的场景(例如为控制权限或严格管控指标 schema)。

5.WithCreateServiceTimeSeries()— 使用服务时间序列接口

配置导出器使用CreateServiceTimeSeries(而非CreateTimeSeries)写入时间序列。该接口适用于服务拥有者写入自身服务的时序数据。注意:使用该选项会隐式将disableCreateMetricDescriptors置为 true(option.go#L192-L199),即不再导出指标描述符。

6.WithCompression("gzip")— 开启 gRPC 压缩

对 gRPC 请求启用 gzip 压缩。在 metric.go#L122-L131 中,压缩器会被附加到GetMetricDescriptorCreateMetricDescriptorCreateTimeSeriesCreateServiceTimeSeries四个调用的 gRPC CallOptions 上。

7.WithMonitoringClient(cl)/WithMonitoringClientOptions(opts...)— 定制底层客户端

前者直接注入一个现成的monitoring.MetricClient;后者追加apioption.ClientOption(如自定义 endpoint、超时、拦截器等)供内部创建客户端时使用。两者互斥:若同时提供,WithMonitoringClient优先生效(option.go#L115-L131)。未注入客户端时,导出器会使用带opentelemetry-go <ver>; google-cloud-metric-exporter <ver>User-Agent 的 gRPC 客户端(option.go#L30)。

8.WithDestinationProjectQuota()— 使用目标项目配额

启用后,每次请求都会携带x-goog-user-project元数据头,值为projectID(去掉projects/前缀),从而使用目标项目的配额而非调用方项目的配额(metric.go#L154-L156)。典型场景是给指标设置gcp.project.id资源属性,将时序写入其他项目。

9.WithSumOfSquaredDeviation()— 直方图平方偏差估算

为直方图启用 SumOfSquaredDeviation 字段的计算。源码注释明确指出:该值是估算值而非真实平方偏差——它假设每个桶内的数据点都落在桶区间的中点(见 metric.go#L834-L849 的setSumOfSquaredDeviation),因此默认不发送。

10.WithMonitoredResourceDescription(mrType, mrLabels)— 指定受监控资源映射

配置导出器尝试把 OTel Resource 映射为指定的 GCM MonitoredResource。使用时需满足两个条件:

  • OTel Resource 中存在gcp.resource_type属性,且其值等于mrType
  • Resource 属性中包含mrLabels中列出的标签键。

命中后,这些标签会被组装进 MonitoredResource 的 Labels(metric.go#L374-L391);未配置或未命中时,则回落到resourcemapping.ResourceAttributesToMonitoringMonitoredResource的通用映射逻辑(metric.go#L393-L404)。


五、完整接入示例:从埋点到导出

综合 README 给出的WithProjectID示例与 OTel SDK 标准用法,一个最小可用的接入流程如下:

import ( "context" "os" mexporter "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric" "go.opentelemetry.io/otel/sdk/metric" ) func main() { ctx := context.Background() // 1. 构造 exporter(本地运行时显式指定项目 ID) projectID := os.Getenv("GOOGLE_CLOUD_PROJECT") exporter, err := mexporter.New( mexporter.WithProjectID(projectID), // mexporter.WithCompression("gzip"), // 可选:开启 gRPC gzip 压缩 // mexporter.WithFilteredResourceAttributes(mexporter.NoAttributes()), // 可选:禁止资源属性下沉 // mexporter.WithDisableCreateMetricDescriptors(), // 可选:关闭自动创建描述符 ) if err != nil { panic(err) // 常见于凭据探测失败或项目为空 } // 2. 注册到 OTel metric SDK(默认周期导出) provider := metric.NewMeterProvider( metric.WithReader(metric.NewPeriodicReader(exporter)), ) defer func() { _ = provider.Shutdown(ctx) }() }

在此之后,程序中通过 Meter 创建的任何 Counter、UpDownCounter、Histogram、ObservableGauge 等指标,都会在 SDK 周期导出时经过该 exporter 上传到 Google Cloud Monitoring。

需要说明的版本前提:本仓库 vendored 的 exporter 版本为0.55.0(见 version.go),其面向的 OTel Go SDK 为go.opentelemetry.io/otel/sdk/metric的 metricdata 模型,直接使用于 substrate 仓库的 Go 工具链(见 go.mod)。如需在其他项目中复用,请以对应 Go module 版本的 API 为准。


六、底层导出流程:描述符缓存、批量上传与类型映射

本小节深入 metric.go 的核心实现,回答"导出器内部到底做了什么"。

6.1 导出入口:两阶段处理

每次导出周期,Export依次执行两个阶段(metric.go#L147-L161):

func (me *metricExporter) Export(ctx context.Context, rm *metricdata.ResourceMetrics) error { // 若已 Shutdown 则直接返回错误 ... if me.o.destinationProjectQuota { ctx = metadata.NewOutgoingContext(ctx, metadata.New(map[string]string{"x-goog-user-project": strings.TrimPrefix(me.o.projectID, "projects/")})) } return errors.Join( me.exportMetricDescriptor(ctx, rm), // 阶段一:确保 MetricDescriptor 存在 me.exportTimeSeries(ctx, rm), // 阶段二:上传 TimeSeries ) }

6.2 阶段一:MetricDescriptor 的创建与缓存

exportMetricDescriptor(metric.go#L175-L214)以(指标名, instrumentation scope 名)为键维护一个进程内缓存mdCache。对每个新出现的指标:

  1. 先调用GetMetricDescriptor查询该类型是否已存在于 GCM;
  2. 若已存在则跳过创建(GCM 的描述符一旦创建便无法原地修改,只能删除重建,因此跳过是唯一合理路径);
  3. 若不存在则调用CreateMetricDescriptor创建,成功后写入缓存。

描述符内容由recordToMdpb组装(metric.go#L293-L312):包括Type(默认workload.googleapis.com/名称)、DisplayName(去掉域前缀后的路径)、MetricKindValueTypeUnitDescription以及从资源属性与数据点属性收集的Labels

6.3 阶段二:TimeSeries 转换与 200 条批量上传

exportTimeSeries(metric.go#L238-L267)把聚合数据逐点转换为 GCM 的TimeSeries,然后按每批最多 200 条分组发送:

const sendBatchSize = 200 // GCM API 硬性上限,绝不超发

这个 200 是 Cloud Monitoring API 的硬性限制(metric.go#L56-L59),因此导出器永远不会在一次请求中超过该值。

6.4 OTel 聚合类型 → GCM 指标类型映射

recordToMdpbKindType(metric.go#L409-L430)定义了完整映射关系:

OTel 聚合类型MetricKindValueType
Gauge[int64]GAUGEINT64
Gauge[float64]GAUGEDOUBLE
Sum[int64](单调)CUMULATIVEINT64
Sum[int64](非单调)GAUGEINT64
Sum[float64](单调)CUMULATIVEDOUBLE
Sum[float64](非单调)GAUGEDOUBLE
Histogram[int64]/Histogram[float64]CUMULATIVEDISTRIBUTION
未知类型返回 UNSPECIFIED,并由errUnexpectedAggregationKind(error.go)报告错误

关键设计点:非单调 Sum 会被当作 GAUGE 上传(metric.go#L494-L497),因为 GCM 的 CUMULATIVE 语义要求单调递增;直方图则映射为DISTRIBUTION,并支持把 Exemplar 中的 span 上下文编码为projects/{projectID}/traces/{traceID}/spans/{spanID}形式的附件,实现指标与链路关联。

6.5 时间间隔与标签规范化

  • 时间间隔toNonemptyTimeIntervalpb(metric.go#L684-L705)保证所有非 GAUGE 类型的时间间隔"结束时间至少比开始时间晚 1 毫秒"——若采样间隔过短,会自动把结束时间推进 1ms,满足 GCM API 约束;
  • 标签规范化normalizeLabelKey(metric.go#L880-L889)将标签键中所有非字母数字字符替换为下划线,且当键以数字开头时自动加key_前缀,以符合 GCM "仅允许字母、数字、下划线,且以字母或数字开头"的标签命名约束;
  • UTF-8 清洗:所有标签值经sanitizeUTF8处理,无效字节替换为替换符

6.6 生命周期管理

metricExporter提供ForceFlush(无状态,直接返回 ctx 错误)与Shutdownsync.Once保证只关闭一次,并关闭底层 gRPC 客户端连接),见 metric.go#L90-L101。接入 SDK 后,MeterProvider.Shutdown会顺带触发 exporter 的关闭。


七、版本与集成现状小结

  • 当前 vendored 版本:v0.55.0,其Version()返回值与 go.mod 中的间接依赖版本完全一致,可作为"仓库中实际使用的 exporter 版本"的可验证事实;
  • 该包为间接依赖,说明 substrate 仓库并未直接在业务代码中 import 此 exporter,而是经由其他依赖(如 OTel 相关工具链)带入;真正面向 GCP 观测的集成入口以仓库内 docs/observability.md 及 internal/otlprelay 等模块为准;
  • 相关资源标签常量的历史定义(k8s_containergce_instanceaws_ec2_instancegeneric_task等)仍保留在 constants.go 中,但均已标记 Deprecated,新代码应优先使用 OpenTelemetry Semantic Conventions(semconv)中的对应键。

八、快速参考:接入清单

要在自己的 Go 服务中通过该 exporter 向 Google Cloud Monitoring 上报指标,按以下清单核对即可:

  1. 创建 Workspace:在 Google Cloud 控制台 Monitoring 中预先创建 Workspace;
  2. 准备凭据:本地开发设置GOOGLE_APPLICATION_CREDENTIALS指向服务账号 JSON;生产环境使用默认服务账号或 Workload Identity;
  3. 指定项目:设置GOOGLE_CLOUD_PROJECT环境变量并调用mexporter.WithProjectID(projectID)(本地运行时必需);
  4. 选择可选配置:按需启用 gzip 压缩、关闭自动描述符创建、自定义指标类型前缀、指定受监控资源映射等;
  5. 注册 SDK:将 exporter 挂入metric.NewPeriodicReader,构造MeterProvider
  6. 验证:在 GCM 控制台的 Metrics Explorer 中检索workload.googleapis.com/前缀下对应指标名,确认数据已落库。
  • 人工智能
  • AI Agent
  • Agent 沙箱
  • 云原生
  • 容器运行时
  • 零信任

【免费下载链接】substrate

Agent Substrate: the core system

项目地址:https://gitcode.com/GitHub_Trending/substrate7/substrate
点击查看免费下载

相关推荐

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

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

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

立即咨询