【文章标题】:How we configured OpenTelemetry logs in Rails
【文章标题】:我们如何在Rails中配置OpenTelemetry日志

【文章正文】:
Recently, we needed to add observability to a Rails project without getting locked into a single vendor. OpenTelemetry was the natural choice.
最近,我们需要为一个Rails项目添加可观测性,同时避免被单一供应商锁定。OpenTelemetry成为自然之选。

It generates three kinds of telemetry data, called signals: logs, metrics, and traces. Each signal is independent, so you can adopt one without the others.
它生成三种遥测数据(称为信号):日志、指标和追踪。每种信号相互独立,因此可以单独采用某一种。

All of these signals travel in a standard, vendor-agnostic format known as OTLP (OpenTelemetry Protocol). Because this format is standard across the industry, we can switch backends (like Datadog, New Relic, or Grafana Cloud) in the future without rewriting any application code.
所有信号都以名为OTLP(OpenTelemetry协议)的标准供应商中立格式传输。由于该格式是行业标准,未来我们可以切换后端(如Datadog、New Relic或Grafana Cloud)而无需重写应用代码。

In this post, we will explain how we configured the OpenTelemetry Ruby SDK to export logs directly to our vendor, Grafana Cloud. We will also discuss a few issues we encountered along the way and the upstream fixes we contributed.
本文将阐述如何配置OpenTelemetry Ruby SDK直接将日志导出至供应商Grafana Cloud,并分享我们遇到的若干问题及向上游提交的修复方案。

Exporting directly to the vendor
直接导出至供应商

The standard OpenTelemetry deployment involves running an OpenTelemetry Collector alongside your application. The Collector is a separate process, usually a sidecar container or a service on the same host. Your application sends telemetry to it over the local network, and the Collector then batches that data and forwards it to the vendor.
标准OpenTelemetry部署需要在应用旁运行OpenTelemetry Collector。Collector是独立进程,通常作为边车容器或同主机服务运行。应用通过本地网络将遥测数据发送给它,Collector会批量处理并转发给供应商。

To keep our infrastructure simple, we bypassed the Collector and exported logs directly from the Ruby SDK to Grafana Cloud. The Scout APM logging gem uses a similar approach and sends logs directly from the app.
为简化基础设施,我们绕过Collector,直接从Ruby SDK向Grafana Cloud导出日志。Scout APM日志组件采用类似方案,直接从应用发送日志。

Our log volume is small, so the SDK’s built-in batching is enough. A Collector is still the better choice if you need buffering, sampling, or scrubbing outside the app.
我们日志量较小,SDK内置批处理已足够。若需在应用外进行缓冲、采样或清洗,Collector仍是更优选择。

Setting up the Ruby SDK for logs
配置Ruby SDK日志功能

Add the following gems to your Gemfile:
在Gemfile中添加以下组件:

gem "opentelemetry-sdk"
gem "opentelemetry-logs-sdk"
gem "opentelemetry-exporter-otlp"
gem "opentelemetry-exporter-otlp-logs"
gem "opentelemetry-instrumentation-all"
gem "opentelemetry-instrumentation-logger"

OpenTelemetry is highly modular, so each gem handles a specific responsibility:
OpenTelemetry高度模块化,每个组件各司其职:

  • opentelemetry-sdk : The core OpenTelemetry framework (traces and the configuration entry point).
    核心框架(追踪功能与配置入口)
  • opentelemetry-logs-sdk : Adds support for the logging signal (which is separate from traces).
    添加日志信号支持(独立于追踪)
  • opentelemetry-exporter-otlp : Exports traces over the network via OTLP.
    通过OTLP协议导出追踪数据
  • opentelemetry-exporter-otlp-logs : Exports logs over the network via OTLP.
    通过OTLP协议导出日志数据
  • opentelemetry-instrumentation-all : Bundles the instrumentation gems, including Rails, Rack, and Active Record.
    集成所有仪表化组件(含Rails/Rack/Active Record)
  • opentelemetry-instrumentation-logger : Hooks into the standard RubyLogger so log messages become OpenTelemetry log records.
    挂钩标准RubyLogger,将日志转为OpenTelemetry日志记录

With these gems installed, the exporter needs to know where to send the data. Set your vendor’s endpoint and authentication token as environment variables (the SDK automatically detects standard OTLP exporter environment variables):
安装组件后,需配置导出目标。将供应商终端和认证令牌设为环境变量(SDK会自动检测标准OTLP导出变量):

OTEL_EXPORTER_OTLP_ENDPOINT="https://your-vendor.com/otlp"
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic <your-token>"

Finally, we need to initialize the SDK so it starts collecting and exporting data. Create an initializer (config/initializers/opentelemetry.rb):
最后初始化SDK以启动数据收集和导出。创建初始化文件:

return if ENV["OTEL_EXPORTER_OTLP_ENDPOINT"].blank?
 
OpenTelemetry::SDK.configure do |c|
  c.service_name = "our-rails-app"
  c.use_all
end

Here, c.use_all enables every instrumentation that has been required, which means the ones bundled in opentelemetry-instrumentation-all plus opentelemetry-instrumentation-logger.
c.use_all会启用所有已引入的仪表化功能,即opentelemetry-instrumentation-all和opentelemetry-instrumentation-logger中的组件。

Testing it locally
本地测试

Now that the SDK is configured, you can test it by setting OTEL_LOGS_EXPORTER=console. This prints log records in your terminal instead of sending them to the vendor, which is the quickest way to confirm your setup works before deploying.
配置完成后,可通过设置OTEL_LOGS_EXPORTER=console测试。这会在终端打印日志记录而非发送给供应商,是部署前快速验证配置的有效方式。

Issues we found and fixed in the Ruby SDK
我们在Ruby SDK中发现并修复的问题

When we exported logs to Grafana Cloud, we found two issues where the Ruby SDK behaved differently than other language SDKs and the OpenTelemetry specification.
向Grafana Cloud导出日志时,我们发现Ruby SDK存在两个与其他语言SDK及OpenTelemetry规范不一致的问题。

  1. Exporter dropped the base path
    导出器遗漏基础路径

Some vendor backends require sending OTLP data to an endpoint with a specific base path, such as /otlp in our case with Grafana Cloud, but the exporter dropped it while appending the signal path.
部分供应商后端要求将OTLP数据发送至含特定基础路径(如Grafana Cloud的/otlp)的终端,但导出器在追加信号路径时遗漏了该路径。

Endpoint:  https://your-vendor.com/otlp
Expected:  https://your-vendor.com/otlp/v1/logs
Actual:    https://your-vendor.com/v1/logs

We reported this in issue #2157 and fixed it in PR #2158, which was released in opentelemetry-exporter-otlp-logs v0.5.1.
我们在2157号issue报告此问题,并通过2158号PR修复,该修复已包含在opentelemetry-exporter-otlp-logs v0.5.1版本中。

  1. Handling HTTP 204 responses
    处理HTTP 204响应

Grafana Cloud returns 204 No Content after ingesting logs, but the exporter only treated 200 OK as success. The exports actually succeeded, but our app logged each one as a failure.
Grafana Cloud在接收日志后会返回204 No Content,但导出器仅将200 OK视为成功。虽然导出实际成功,但应用会错误记录为失败。

We raised issue #2043 and fixed it in PR #2044, which was released in opentelemetry-exporter-otlp-logs v0.4.0.
我们提出2043号issue并通过2044号PR修复,该修复已包含在opentelemetry-exporter-otlp-logs v0.4.0版本中。

Next steps: structured logging
下一步:结构化日志

Now that logs are being successfully exported, the next logical step is structured logging. That’s too much to cover here, but the rails_semantic_logger gem is a great place to start, and we might even cover the full OpenTelemetry setup for it in a future post!
成功导出日志后,下一步自然是实现结构化日志。本文篇幅有限,但rails_semantic_logger组件是个不错的起点——未来我们可能会专门撰文介绍其完整的OpenTelemetry配置方案!