🫣

SigNozでRailsのAPMを取得&ログを無理やり転送する

2024/02/10に公開

結論

  • SigNozでAPMを取得するのはわりかし簡単
  • 2024/02現在でログを転送するは若干面倒

前提条件

  • Ruby on Rails7.1の環境をDockerとdocker-compose.ymlで構築済み

手順

SigNozを構築する

https://signoz.io/docs/install/docker/

を手順通りに実行

git clone -b main https://github.com/SigNoz/signoz.git && cd signoz/deploy/
docker compose -f docker/clickhouse-setup/docker-compose.yaml up -d

http://localhost:3301

にアクセス

SigNozでログの転送準備

https://signoz.io/docs/userguide/send-logs-http/
の手順通りに

  • deploy/docker/clickhouse-setup/docker-compose.yamlの8082ポートを解放する
...
otel-collector:
    image: signoz/signoz-otel-collector:0.88.11
    command: ["--config=/etc/otel-collector-config.yaml"]
    volumes:
      - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
    ports:
      - "8082:8082" ## ここのコメントアウトを外す
...
  • deploy/docker/clickhouse-setup/otel-collector-config.yamlにhttplogreceiverを追加
receivers: 
  httplogreceiver/json: #追加
    endpoint: 0.0.0.0:8082 #追加
    source: json #追加
...

service:
    ....
    logs:
        receivers: [otlp, httplogreceiver/json]  #httplogreceiver/jsonを追加
        processors: [batch]
        exporters: [clickhouselogsexporter]
docker compose -f docker/clickhouse-setup/docker-compose.yaml up -d
もしくは
docker compose -f docker/clickhouse-setup/docker-compose.yaml restart
でSigNozを再起動する

試しにログを送ってみる

curl --location 'http://localhost:8082' \
--header 'Content-Type: application/json' \
--data '[
  {
      "trace_id": "000000000000000018c51935df0b93b9",
      "span_id": "18c51935df0b93b9",
      "trace_flags": 0,
      "severity_text": "info",
      "severity_number": 4,
      "attributes": {
          "method": "GET",
          "path": "/api/users"
      },
      "resources": {
          "host": "myhost",
          "namespace": "prod"
      },
      "message": "This is a log line"
  }
]'

This is a log line というログがSigNozで出たら成功!

Railsの設定

https://signoz.io/blog/opentelemetry-ruby/
の手順通りに

Gemfileに以下を追加して

gem 'opentelemetry-sdk'
gem 'opentelemetry-exporter-otlp'
gem 'opentelemetry-instrumentation-all'
bundle install

を実行

  • config/environment.rbを編集
require 'opentelemetry/sdk'
require_relative 'application'

OpenTelemetry::SDK.configure do |c|
  c.use_all
end

Rails.application.initialize!

docker-compose.ymlを編集

  version: "3"
  services:
    rails
.
.
.

      environment:
        OTEL_EXPORTER: otlp
        OTEL_SERVICE_NAME: sample
        OTEL_EXPORTER_OTLP_ENDPOINT: http://localhost:4318
        OTEL_EXPORTER_OTLP_ENDPOINT_LOG: http://localhost:8082

環境変数にOTEL_EXPORTER/OTEL_SERVICE_NAME/OTEL_EXPORTER_OTLP_ENDPOINT/OTEL_EXPORTER_OTLP_ENDPOINT_LOGを追加する

Logを転送するJobを作成する

app/jobs/send_log_data_job.rbを作成する

class SendLogDataJob < ApplicationJob
  queue_as :default

  def perform(log_data)
    uri = URI((ENV['OTEL_EXPORTER_OTLP_ENDPOINT_LOG']).to_s)
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = uri.scheme == 'https'
    request = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
    request.body = log_data.is_a?(String) ? log_data : log_data.to_json
    response = http.request(request)

    Rails.logger.info "SendLogDataJob: HTTP Response Status: #{response.code}, Body: #{response.body}"
  rescue StandardError => e
    Rails.logger.error "SendLogDataJob: Failed to send log data: #{e.message}"
  end
end

app/controllers/application_controller.rbを編集しJobを呼び出す

class ApplicationController < ActionController::Base
  around_action :capture_action_log

  private

  def capture_action_log
    start_time = Time.current
    yield
    end_time = Time.current

    trace_id = OpenTelemetry::Trace.current_span.context.hex_trace_id
    span_id = OpenTelemetry::Trace.current_span.context.hex_span_id
    duration = (end_time - start_time) * 1000.0
    body_content = {
       ## 飛ばしたいメッセージなどをテキトーに
      test: 'test',
    }

    log_data = [{
      app: ENV['OTEL_SERVICE_NAME'],
      host: request.host,
      status: response.status,
      duration:,
      trace_id:,
      span_id:,
      body: body_content.to_json
    }]

    SendLogDataJob.perform_later(log_data.to_json)
  end
end

docker-compose upなどでRailsを起動して、アプリにアクセスしてみる

すると

OpenTelemetry::Instrumentation関連でめちゃくちゃログが出る
(主に警告が)

ログの中にこのようなログがでていれば、ログの転送に成功している

{"time":"2024-02-09T14:33:19.340+09:00","level":"INFO","message":"SendLogDataJob: HTTP Response Status: 200, Body: ","trace_id":"fe47f03f1b032cbb4055a94596fbef25","span_id":"995b4d6abe8cfb38","operation":"default process"}

参考

https://signoz.io/docs/userguide/send-logs-http/
https://signoz.io/blog/opentelemetry-ruby/

Discussion