通过OpenTelemetry上报Ruby应用数据

通过OpenTelemetry为应用埋点并上报链路数据至可观测链路 OpenTelemetry 版后,可观测链路 OpenTelemetry 版即可开始监控应用,您可以查看应用拓扑、调用链路、异常事务、慢事务和SQL分析等一系列监控数据。本文介绍如何使用OpenTelemetry为Ruby应用埋点并上报数据。

前提条件

获取接入点信息

新版控制台

  1. 登录可观测链路 OpenTelemetry 版控制台,在左侧导航栏单击接入中心

  2. 开源框架区域单击OpenTelemetry卡片。

  3. 在弹出的OpenTelemetry面板中选择数据需要上报的地域。

    说明

    初次接入的地域将会自动进行资源初始化。

  4. 选择连接方式上报方式,然后复制接入点信息。

    • 连接方式:若您的服务部署在阿里云上,且所属地域与选择的接入地域一致,推荐使用阿里云内网方式,否则选择公网方式。

    • 上报方式:根据客户端支持的协议类型选择HTTP或gRPC协议上报数据。

    image.png

旧版控制台

  1. 登录可观测链路 OpenTelemetry 版控制台

  2. 在左侧导航栏单击集群配置,然后在右侧页面单击接入点信息页签。

  3. 在页面顶部选择需要接入的地域,然后在集群信息区域打开显示Token开关。

  4. 客户端采集工具区域单击OpenTelemetry

    相关信息列中,获取接入点信息。ot旧版中.jpg

    说明

    如果应用部署于阿里云生产环境,则选择阿里云VPC网络接入点,否则选择公网接入点。

背景信息

  • Ruby版本限制:MRI Ruby ≥ 3.0,jruby ≥ 9.3.2.0,或者truffleruby ≥ 22.1。

  • OpenTelemetry Ruby支持手动埋点和半自动埋点(无需手动创建Span,但需添加一个配置文件),其中半自动埋点支持的框架请参见OpenTelemetry官方文档

展开查看支持的Ruby框架

  • action_pack

  • action_view

  • active_job

  • active_model_serializers

  • active_record

  • active_support

  • aws_sdk

  • bunny

  • concurrent_ruby

  • dalli

  • delayed_job

  • ethon

  • excon

  • faraday

  • grape

  • graphql

  • gruf

  • http

  • http_client

  • httpx

  • koala

  • lmdb

  • mongo

  • mysql2

  • net_http

  • pg

  • que

  • racecar

  • rack

  • rails

  • rake

  • rdkafka

  • redis

  • resque

  • restclient

  • rspec

  • ruby_kafka

  • sidekiq

  • sinatra

  • trilogy

示例Demo

示例代码仓库地址:ruby-opentelemetry-demo

方法一:使用HTTP协议上报数据

  1. 安装手动埋点所需的OpenTelemetry相关依赖。

    gem install opentelemetry-api
    gem install opentelemetry-sdk
    gem install opentelemetry-exporter-otlp
  2. OpenTelemetry初始化。

    添加导出观测数据的组件,将<endpoint>替换成前提条件中获取的对应地域的Endpoint。

    require 'opentelemetry/sdk'
    require 'opentelemetry-exporter-otlp'
    
    OpenTelemetry::SDK.configure do |c|
      c.add_span_processor(
        OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
          OpenTelemetry::Exporter::OTLP::Exporter.new(
            endpoint: '<endpoint>' # HTTP方式接入
          )
        )
      )
      c.resource = OpenTelemetry::SDK::Resources::Resource.create({
        OpenTelemetry::SemanticConventions::Resource::SERVICE_NAMESPACE => 'tracing',
        OpenTelemetry::SemanticConventions::Resource::SERVICE_NAME => 'ruby_demo', # 通过OpenTelemetry上报的Ruby应用名
        OpenTelemetry::SemanticConventions::Resource::SERVICE_VERSION => '0.0.1',
      })
    end
  3. 获取Tracer并创建新的Span。

    tracer = OpenTelemetry.tracer_provider.tracer('<your_tracer_name>', '0.1.0')
    
    tracer.in_span('parent_span') do |parent_span|
      # ...
    end
  4. 获取当前Span,向当前Span添加信息并获取Trace ID和Span ID。

    # ...
    tracer.in_span('parent_span') do |parent_span|
      # current_span即parent_span
      current_span = OpenTelemetry::Trace::current_span
      current_span.set_attribute('key', 'value')
      pp current_span.context.trace_id
      pp current_span.context.span_id
    end
  5. 创建嵌套的Span。

    # ...
    tracer.in_span('parent_span') do |parent_span|
      # ...
      tracer.in_span('child_span') do |child_span|
        # 此时current_span是child_span
        current_span = OpenTelemetry::Trace::current_span
        pp current_span
      end
    end

    展开查看完整代码

    require 'opentelemetry/sdk'
    require 'opentelemetry-exporter-otlp'
    
    OpenTelemetry::SDK.configure do |c|
      c.add_span_processor(
        OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
          OpenTelemetry::Exporter::OTLP::Exporter.new(
            endpoint: '<endpoint>' # HTTP方式接入
          )
        )
      )
      c.resource = OpenTelemetry::SDK::Resources::Resource.create({
        OpenTelemetry::SemanticConventions::Resource::SERVICE_NAMESPACE => 'tracing',
        OpenTelemetry::SemanticConventions::Resource::SERVICE_NAME => 'ruby_demo', # 通过OpenTelemetry上报的Ruby应用名
        OpenTelemetry::SemanticConventions::Resource::SERVICE_VERSION => '0.0.1',
      })
    
      # 不使用OpenTelemetry Resources API来设置应用名
      # c.service_name = 'ruby_demo'
    end
    
    tracer = OpenTelemetry.tracer_provider.tracer('instrumentation_library_name', '0.1.0')
    
    tracer.in_span('parent_span') do |parent_span|
      # 设置Attribute
      parent_span.set_attribute('language', 'ruby')
      parent_span.set_attribute("attribute_key", ["attribute_value1", "attribute_value1", "attribute_value1"])
      # 添加Event
      parent_span.add_event("event", attributes: {
        "pid" => 1234,
        "signal" => "SIGHUP"
      })
    
      # 获取Trace ID与当前Span的Span ID
      current_span = OpenTelemetry::Trace::current_span
      pp current_span.context.trace_id
      pp current_span.context.span_id
    
      tracer.in_span('child_span') do |child_span|
        child_span.add_attributes({
          "key1" => "value1",
          "key2" => "value2"
        })
    
        child_span.add_event("mock exception here")
    
        begin
          raise 'An error has occurred'
        rescue
          # 发生异常时,将child_span的status设置为error
          child_span.status = OpenTelemetry::Trace::Status.error("error in child span")
        end
    
        pp child_span
    
      end
    end
    
    sleep 10
  6. 运行程序。

    ruby manual.rb

方法二:自动上报

OpenTelemetry Ruby也可以自动在应用程序中埋点,实现自动观测。下面以基于Rails框架的Ruby Web应用为例,演示使用OpenTelemetry自动追踪链路并上报数据。

  1. 下载开源Web应用框架Rails。

    gem install rails
  2. 使用Rails创建Web项目。

    rails new <your-project-name>
    • 请将<your-project-name>替换为应用名,例如:rails new auto-demo

    • 如果运行命令后出现Rails is not currently installed on this system.的报错,请关闭终端并重新打开,然后在新打开的终端中重新输入命令。

  3. 在应用目录下的Gemfile文件中添加以下内容。

    gem 'opentelemetry-sdk'
    gem 'opentelemetry-exporter-otlp'
    gem 'opentelemetry-instrumentation-all'
  4. 下载此Web应用所需的第三方依赖。

    1. 进入项目根目录。

      cd <your-project-name>
    2. 下载Ruby依赖管理工具Bundler。

      gem install bundler
    3. 下载Gemfile中的依赖。

      bundle install
  5. <your-project-name>/config/initializers目录下创建opentelemetry.rb文件,并添加以下内容。

    # config/initializers/opentelemetry.rb
    require 'opentelemetry/sdk'
    require 'opentelemetry/exporter/otlp'
    require 'opentelemetry/instrumentation/all'
    
    OpenTelemetry::SDK.configure do |c|
      c.add_span_processor(
        OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
          OpenTelemetry::Exporter::OTLP::Exporter.new(
            endpoint: '<endpoint>' # HTTP方式接入
          )
        )
      )
      c.resource = OpenTelemetry::SDK::Resources::Resource.create({
        OpenTelemetry::SemanticConventions::Resource::HOST_NAME => '<your-host-name>', # 主机名
      })
      c.service_name = '<your-service-name>'    # 服务名
      c.use_all()    # 自动观测opentelemetry支持的所有库,
    end
    • <endpoint>替换成前提条件中获取的对应地域的Endpoint。

    • 根据实际情况替换<your-host-name><your-service-name>

  6. 运行项目。

    rails server

    如果输出以下内容,则表示运行成功。

    * Puma version: 5.6.5 (ruby 2.7.2-p137) ("Birdie's Version")
    *  Min threads: 5
    *  Max threads: 5
    *  Environment: development
    *          PID: 79842
    * Listening on http://127.0.0.1:3000
    * Listening on http://[::1]:3000
    Use Ctrl-C to stop
  7. 在浏览器中访问http://127.0.0.1:3000,终端输出以下内容则说明数据已上报至可观测链路 OpenTelemetry 版控制台。

    Started GET "/" for 127.0.0.1 at 2023-01-01 10:00:00 +0800
    Processing by Rails::WelcomeController#index as HTML
      Rendering /Users/username/.rvm/gems/ruby-2.7.2/gems/railties-7.0.4.3/lib/rails/templates/rails/welcome/index.html.erb
      Rendered /Users/username/.rvm/gems/ruby-2.7.2/gems/railties-7.0.4.3/lib/rails/templates/rails/welcome/index.html.erb (Duration: 0.8ms | Allocations: 665)
    Completed 200 OK in 6ms (Views: 2.1ms | ActiveRecord: 0.0ms | Allocations: 5440)

查看监控数据

可观测链路 OpenTelemetry 版控制台应用列表页面选择目标应用,查看链路数据。