edge
더 많은 정보: rubyonrails.org에서 확인하세요: 더 많은 Ruby on Rails

Active Support Instrumentation

Active Support는 Ruby 언어 확장 기능, 유틸리티 및 기타 기능을 제공하는 Rails의 핵심 부분입니다. 그 중 하나는 애플리케이션 내에서 발생하는 특정 동작을 측정하기 위해 사용할 수 있는 instrumentation API를 포함하고 있습니다. 이는 Rails 애플리케이션이나 프레임워크 내부의 Ruby 코드와 같은 곳에서 발생하는 동작을 측정하는 데 사용할 수 있습니다. 그러나 Rails에만 국한되지 않고 원하는 경우 다른 Ruby 스크립트에서도 독립적으로 사용할 수 있습니다.

이 가이드에서는 Active Support의 instrumentation API를 사용하여 Rails 및 다른 Ruby 코드 내에서 이벤트를 측정하는 방법을 알아보겠습니다.

이 가이드를 읽은 후에는 다음을 알게 될 것입니다:

1 Instrumentation 소개

Active Support에서 제공하는 instrumentation API를 사용하면 개발자가 다른 개발자가 후크를 사용할 수 있는 후크를 제공할 수 있습니다. Rails 프레임워크 내에는 여러 개의 후크가 있습니다. 이 API를 사용하면 개발자는 자신의 애플리케이션이나 다른 Ruby 코드 내에서 특정 이벤트가 발생할 때 알림을 받을 수 있습니다.

예를 들어, Active Record 내에서 제공되는 후크는 Active Record가 데이터베이스에서 SQL 쿼리를 사용할 때마다 호출됩니다. 이 후크는 구독할 수 있으며, 특정 동작 중에 발생하는 쿼리 수를 추적하는 데 사용할 수 있습니다. 또 다른 후크는 컨트롤러의 동작 처리 주변에 있습니다. 이는 특정 동작이 얼마나 오래 걸렸는지 추적하는 데 사용할 수 있습니다.

또한 나중에 구독할 수 있는 애플리케이션 내에서 사용자 정의 이벤트를 생성할 수도 있습니다.

2 이벤트에 구독하기

이벤트에 구독하는 것은 간단합니다. ActiveSupport::Notifications.subscribe를 사용하여 알림을 수신하기 위해 블록을 사용하면 됩니다.

블록은 다음 인수를 받습니다:

  • 이벤트의 이름
  • 시작 시간
  • 종료 시간
  • 이벤트를 발생시킨 instrumenter의 고유 ID
  • 이벤트의 페이로드
ActiveSupport::Notifications.subscribe "process_action.action_controller" do |name, started, finished, unique_id, data|
  # 사용자 정의 코드
  Rails.logger.info "#{name} Received! (started: #{started}, finished: #{finished})" # process_action.action_controller Received (started: 2019-05-05 13:43:57 -0800, finished: 2019-05-05 13:43:58 -0800)
end

startedfinished의 정확성에 대해 걱정된다면 ActiveSupport::Notifications.monotonic_subscribe를 사용하세요. 주어진 블록은 위와 동일한 인수를 받지만, startedfinished는 월-클록 시간 대신 정확한 단조 시간 값을 갖습니다.

ActiveSupport::Notifications.monotonic_subscribe "process_action.action_controller" do |name, started, finished, unique_id, data|
  # 사용자 정의 코드
  Rails.logger.info "#{name} Received! (started: #{started}, finished: #{finished})" # process_action.action_controller Received (started: 1560978.425334, finished: 1560979.429234)
end

매번 블록 인수를 정의하는 것은 번거로울 수 있습니다. 다음과 같이 블록 인수에서 ActiveSupport::Notifications::Event를 쉽게 생성할 수 있습니다:

ActiveSupport::Notifications.subscribe "process_action.action_controller" do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)

  event.name      # => "process_action.action_controller"
  event.duration  # => 10 (밀리초 단위)
  event.payload   # => {:extra=>information}

  Rails.logger.info "#{event} Received!"
end

인수가 하나뿐인 블록을 전달할 수도 있으며, 이 경우 이벤트 객체가 전달됩니다:

ActiveSupport::Notifications.subscribe "process_action.action_controller" do |event|
  event.name      # => "process_action.action_controller"
  event.duration  # => 10 (밀리초 단위)
  event.payload   # => {:extra=>information}

  Rails.logger.info "#{event} Received!"
end

정규 표현식과 일치하는 이벤트에도 구독할 수 있습니다. 이를 통해 한 번에 여러 이벤트에 구독할 수 있습니다. ActionController에서 모든 것을 구독하는 방법은 다음과 같습니다:

ActiveSupport::Notifications.subscribe(/action_controller/) do |*args|
  # 모든 ActionController 이벤트를 검사
end

3 브라우저에서 Instrumentation의 타이밍 확인하기

Rails는 Server Timing 표준을 구현하여 타이밍 정보를 웹 브라우저에서 사용할 수 있게 합니다. 활성화하려면 환경 설정(일반적으로 development.rb가 가장 많이 사용됨)을 편집하여 다음을 포함하면 됩니다:

  config.server_timing = true

설정을 완료한 후(서버를 다시 시작 포함), 브라우저의 개발자 도구 창으로 이동한 다음 Network를 선택하고 페이지를 다시로드합니다. 그런 다음 Rails 서버로의 요청 중 하나를 선택하면 타이밍 탭에서 서버 타이밍을 볼 수 있습니다. 이에 대한 예는 Firefox 문서를 참조하십시오.

4 Rails 프레임워크 후크

Ruby on Rails 프레임워크 내에서는 일반적인 이벤트에 대한 여러 후크가 제공됩니다. 이러한 이벤트와 해당 페이로드에 대한 자세한 내용은 아래에서 확인할 수 있습니다.

4.1 액션 컨트롤러

4.1.1 start_processing.action_controller

:controller 컨트롤러 이름
:action 액션
:params 필터링된 매개변수 없이 요청 매개변수의 해시
:headers 요청 헤더
:format html/js/json/xml 등
:method HTTP 요청 동사
:path 요청 경로
{
  controller: "PostsController",
  action: "new",
  params: { "action" => "new", "controller" => "posts" },
  headers: #<ActionDispatch::Http::Headers:0x0055a67a519b88>,
  format: :html,
  method: "GET",
  path: "/posts/new"
}

4.1.2 process_action.action_controller

:controller 컨트롤러 이름
:action 액션
:params 필터링된 매개변수 없이 요청 매개변수의 해시
:headers 요청 헤더
:format html/js/json/xml 등
:method HTTP 요청 동사
:path 요청 경로
:request ActionDispatch::Request 객체
:response ActionDispatch::Response 객체
:status HTTP 상태 코드
:view_runtime 뷰에서 소요된 시간 (밀리초)
:db_runtime 데이터베이스 쿼리 실행에 소요된 시간 (밀리초)
{
  controller: "PostsController",
  action: "index",
  params: {"action" => "index", "controller" => "posts"},
  headers: #<ActionDispatch::Http::Headers:0x0055a67a519b88>,
  format: :html,
  method: "GET",
  path: "/posts",
  request: #<ActionDispatch::Request:0x00007ff1cb9bd7b8>,
  response: #<ActionDispatch::Response:0x00007f8521841ec8>,
  status: 200,
  view_runtime: 46.848,
  db_runtime: 0.157
}

4.1.3 send_file.action_controller

:path 파일의 전체 경로

호출자에 의해 추가 키가 추가될 수 있습니다.

4.1.4 send_data.action_controller

ActionController는 페이로드에 특정 정보를 추가하지 않습니다. 모든 옵션은 페이로드로 전달됩니다.

4.1.5 redirect_to.action_controller

:status HTTP 응답 코드
:location 리디렉션할 URL
:request ActionDispatch::Request 객체
{
  status: 302,
  location: "http://localhost:3000/posts/new",
  request: <ActionDispatch::Request:0x00007ff1cb9bd7b8>
}

4.1.6 halted_callback.action_controller

:filter 액션을 중단시킨 필터
{
  filter: ":halting_filter"
}

4.1.7 unpermitted_parameters.action_controller

:keys 허용되지 않은 키
:context 다음 키를 가진 해시: :controller, :action, :params, :request

4.2 액션 컨트롤러 — 캐싱

4.2.1 write_fragment.action_controller

:key 전체 키
{
  key: 'posts/1-dashboard-view'
}

4.2.2 read_fragment.action_controller

:key 전체 키
{
  key: 'posts/1-dashboard-view'
}

4.2.3 expire_fragment.action_controller

:key 전체 키
{
  key: 'posts/1-dashboard-view'
}

4.2.4 exist_fragment?.action_controller

:key 전체 키
{
  key: 'posts/1-dashboard-view'
}

4.3 액션 디스패치

4.3.1 process_middleware.action_dispatch

:middleware 미들웨어의 이름

4.3.2 redirect.action_dispatch

:status HTTP 응답 코드
:location 리디렉션할 URL
:request ActionDispatch::Request 객체

4.3.3 request.action_dispatch

:request ActionDispatch::Request 객체

4.4 액션 뷰

4.4.1 render_template.action_view

:identifier 템플릿의 전체 경로
:layout 적용 가능한 레이아웃
:locals 템플릿에 전달된 로컬 변수
{
  identifier: "/Users/adam/projects/notifications/app/views/posts/index.html.erb",
  layout: "layouts/application",
  locals: { foo: "bar" }
}

4.4.2 render_partial.action_view

:identifier 템플릿의 전체 경로
:locals 템플릿에 전달된 로컬 변수
{
  identifier: "/Users/adam/projects/notifications/app/views/posts/_form.html.erb",
  locals: { foo: "bar" }
}

4.4.3 render_collection.action_view

:identifier 템플릿의 전체 경로
:count 컬렉션의 크기
:cache_hits 캐시에서 가져온 부분의 수

:cache_hits 키는 컬렉션이 cached: true로 렌더링된 경우에만 포함됩니다. ruby { identifier: "/Users/adam/projects/notifications/app/views/posts/_post.html.erb", count: 3, cache_hits: 0 }

4.4.4 render_layout.action_view

:identifier 템플릿의 전체 경로
{
  identifier: "/Users/adam/projects/notifications/app/views/layouts/application.html.erb"
}

4.5 Active Record

4.5.1 sql.active_record

:sql SQL 문장
:name 작업의 이름
:connection 연결 객체
:binds 바인드 매개변수
:type_casted_binds 형변환된 바인드 매개변수
:statement_name SQL 문장의 이름
:cached 캐시된 쿼리를 사용할 때 true가 추가됨

어댑터는 자체 데이터를 추가할 수도 있습니다.

{
  sql: "SELECT \"posts\".* FROM \"posts\" ",
  name: "Post Load",
  connection: <ActiveRecord::ConnectionAdapters::SQLite3Adapter:0x00007f9f7a838850>,
  binds: [<ActiveModel::Attribute::WithCastValue:0x00007fe19d15dc00>],
  type_casted_binds: [11],
  statement_name: nil
}

4.5.2 strict_loading_violation.active_record

이 이벤트는 config.active_record.action_on_strict_loading_violation:log로 설정된 경우에만 발생합니다.

:owner strict_loading이 활성화된 모델
:reflection 로드를 시도한 연관관계의 리플렉션

4.5.3 instantiation.active_record

:record_count 인스턴스화된 레코드의 수
:class_name 레코드의 클래스
{
  record_count: 1,
  class_name: "User"
}

4.6 Action Mailer

4.6.1 deliver.action_mailer

:mailer 메일러 클래스의 이름
:message_id Mail 젬에 의해 생성된 메시지의 ID
:subject 메일의 제목
:to 메일의 수신자 주소
:from 메일의 발신자 주소
:bcc 메일의 숨은 참조 주소
:cc 메일의 참조 주소
:date 메일의 날짜
:mail 메일의 인코딩된 형태
:perform_deliveries 이 메시지의 전송이 수행되는지 여부
{
  mailer: "Notification",
  message_id: "[email protected]",
  subject: "Rails Guides",
  to: ["[email protected]", "[email protected]"],
  from: ["[email protected]"],
  date: Sat, 10 Mar 2012 14:18:09 +0100,
  mail: "...", # 생략
  perform_deliveries: true
}

4.6.2 process.action_mailer

:mailer 메일러 클래스의 이름
:action 액션의 이름
:args 인수
{
  mailer: "Notification",
  action: "welcome_email",
  args: []
}

4.7 Active Support — Caching

4.7.1 cache_read.active_support

:key 스토어에서 사용된 키
:store 스토어 클래스의 이름
:hit 이 읽기가 캐시 히트인지 여부
:super_operation fetch로 읽기가 수행된 경우 :fetch

4.7.2 cache_read_multi.active_support

:key 스토어에서 사용된 키들
:store 스토어 클래스의 이름
:hits 캐시 히트된 키들
:super_operation fetch_multi로 읽기가 수행된 경우 :fetch_multi

4.7.3 cache_generate.active_support

이 이벤트는 블록이 있는 fetch 호출시에만 발생합니다.

:key 스토어에서 사용된 키
:store 스토어 클래스의 이름

fetch에 전달된 옵션은 스토어에 쓸 때 페이로드와 병합됩니다.

{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.7.4 cache_fetch_hit.active_support

이 이벤트는 블록이 있는 fetch 호출시에만 발생합니다.

:key 스토어에서 사용된 키
:store 스토어 클래스의 이름

fetch에 전달된 옵션은 페이로드와 병합됩니다.

{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.7.5 cache_write.active_support

:key 스토어에서 사용된 키
:store 스토어 클래스의 이름

캐시 스토어는 자체 데이터를 추가할 수도 있습니다.

{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.7.6 cache_write_multi.active_support

:key 스토어에 쓰여진 키와 값
:store 스토어 클래스의 이름

4.7.7 cache_increment.active_support

이 이벤트는 MemCacheStore 또는 RedisCacheStore를 사용할 때만 발생합니다.

:key 스토어에서 사용된 키
:store 스토어 클래스의 이름
:amount 증가량
{
  key: "bottles-of-beer",
  store: "ActiveSupport::Cache::RedisCacheStore",
  amount: 99
}

4.7.8 cache_decrement.active_support

이 이벤트는 Memcached 또는 Redis 캐시 스토어를 사용할 때만 발생합니다.

:key 스토어에서 사용된 키
:store 스토어 클래스의 이름
:amount 감소량
{
  key: "bottles-of-beer",
  store: "ActiveSupport::Cache::RedisCacheStore",
  amount: 1
}

4.7.9 cache_delete.active_support

:key 스토어에서 사용된 키
:store 스토어 클래스의 이름
{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.7.10 cache_delete_multi.active_support

:key 스토어에서 사용된 키들
:store 스토어 클래스의 이름

4.7.11 cache_delete_matched.active_support

이 이벤트는 RedisCacheStore, FileStore, 또는 MemoryStore를 사용할 때만 발생합니다.

:key 사용된 키 패턴
:store 스토어 클래스의 이름
{
  key: "posts/*",
  store: "ActiveSupport::Cache::RedisCacheStore"
}

4.7.12 cache_cleanup.active_support

이 이벤트는 MemoryStore를 사용할 때만 발생합니다.

:store 스토어 클래스의 이름
:size 정리 전 캐시의 항목 수
{
  store: "ActiveSupport::Cache::MemoryStore",
  size: 9001
}

4.7.13 cache_prune.active_support

이 이벤트는 MemoryStore를 사용할 때만 발생합니다.

:store 스토어 클래스의 이름
:key 캐시의 대상 크기 (바이트)
:from 정리 전 캐시의 크기 (바이트)
{
  store: "ActiveSupport::Cache::MemoryStore",
  key: 5000,
  from: 9001
}

4.7.14 cache_exist?.active_support

:key 스토어에서 사용된 키
:store 스토어 클래스의 이름
{
  key: "name-of-complicated-computation",
  store: "ActiveSupport::Cache::MemCacheStore"
}

4.8 Active Support — Messages

4.8.1 message_serializer_fallback.active_support

:serializer 주요 (원래 의도된) 직렬화기
:fallback 대체 (실제) 직렬화기
:serialized 직렬화된 문자열
:deserialized 역직렬화된 값
{
  serializer: :json_allow_marshal,
  fallback: :marshal,
  serialized: "\x04\b{\x06I\"\nHello\x06:\x06ETI\"\nWorld\x06;\x00T",
  deserialized: { "Hello" => "World" },
}

4.9 Active Job

4.9.1 enqueue_at.active_job

:adapter 작업을 처리하는 QueueAdapter 객체
:job 작업 객체

4.9.2 enqueue.active_job

:adapter 작업을 처리하는 QueueAdapter 객체
:job 작업 객체

4.9.3 enqueue_retry.active_job

:job 작업 객체
:adapter 작업을 처리하는 QueueAdapter 객체
:error 재시도를 발생시킨 오류
:wait 재시도의 지연 시간

4.9.4 enqueue_all.active_job

:adapter 작업을 처리하는 QueueAdapter 객체
:jobs 작업 객체의 배열

4.9.5 perform_start.active_job

:adapter 작업을 처리하는 QueueAdapter 객체
:job 작업 객체

4.9.6 perform.active_job

:adapter 작업을 처리하는 QueueAdapter 객체
:job 작업 객체
:db_runtime 데이터베이스 쿼리 실행에 소요된 시간 (밀리초)

4.9.7 retry_stopped.active_job

:adapter 작업을 처리하는 QueueAdapter 객체
:job 작업 객체
:error 재시도를 발생시킨 오류

4.9.8 discard.active_job

:adapter 작업을 처리하는 QueueAdapter 객체
:job 작업 객체
:error 폐기를 발생시킨 오류

4.10 액션 케이블

4.10.1 perform_action.action_cable

:channel_class 채널 클래스의 이름
:action 액션
:data 데이터의 해시

4.10.2 transmit.action_cable

:channel_class 채널 클래스의 이름
:data 데이터의 해시
:via 경로

4.10.3 transmit_subscription_confirmation.action_cable

:channel_class 채널 클래스의 이름

4.10.4 transmit_subscription_rejection.action_cable

:channel_class 채널 클래스의 이름

4.10.5 broadcast.action_cable

:broadcasting 이름이 지정된 브로드캐스팅
:message 메시지의 해시
:coder 코더

4.11 액티브 스토리지

4.11.1 preview.active_storage

:key 보안 토큰

4.11.2 transform.active_storage

4.11.3 analyze.active_storage

:analyzer 분석기의 이름, 예: ffprobe

4.12 액티브 스토리지 - 스토리지 서비스

4.12.1 service_upload.active_storage

:key 보안 토큰
:service 서비스의 이름
:checksum 무결성을 보장하기 위한 체크섬

4.12.2 service_streaming_download.active_storage

:key 보안 토큰
:service 서비스의 이름

4.12.3 service_download_chunk.active_storage

:key 보안 토큰
:service 서비스의 이름
:range 읽으려고 시도한 바이트 범위

4.12.4 service_download.active_storage

:key 보안 토큰
:service 서비스의 이름

4.12.5 service_delete.active_storage

:key 보안 토큰
:service 서비스의 이름

4.12.6 service_delete_prefixed.active_storage

:prefix 키의 접두사
:service 서비스의 이름

4.12.7 service_exist.active_storage

:key 보안 토큰
:service 서비스의 이름
:exist 파일 또는 블롭이 존재하는지 여부

4.12.8 service_url.active_storage

:key 보안 토큰
:service 서비스의 이름
:url 생성된 URL

4.12.9 service_update_metadata.active_storage

이 이벤트는 Google Cloud Storage 서비스를 사용할 때만 발생합니다.

:key 보안 토큰
:service 서비스의 이름
:content_type HTTP Content-Type 필드
:disposition HTTP Content-Disposition 필드

4.13 액션 메일박스

4.13.1 process.action_mailbox

:mailbox ActionMailbox::Base를 상속하는 메일박스 클래스의 인스턴스
:inbound_email 처리 중인 인바운드 이메일에 대한 데이터를 포함한 해시
{
  mailbox: #<RepliesMailbox:0x00007f9f7a8388>,
  inbound_email: {
    id: 1,
    message_id: "[email protected]",
    status: "processing"
  }
}

4.14 Railties

4.14.1 load_config_initializer.railties

:initializer config/initializers에서 로드된 초기화 파일의 경로

4.15 Rails

4.15.1 deprecation.rails

:message 폐기 경고 메시지
:callstack 폐기 경고가 발생한 위치
:gem_name 폐기 경고를 보고하는 젬의 이름
:deprecation_horizon 폐기될 동작이 제거될 버전

5 예외

계측 중에 예외가 발생하면 페이로드에 관련 정보가 포함됩니다.

:exception 예외 클래스 이름과 메시지로 구성된 두 개의 요소로 이루어진 배열
:exception_object 예외 객체

6 사용자 정의 이벤트 생성

사용자 정의 이벤트를 추가하는 것도 매우 쉽습니다. Active Support가 모든 번거로운 작업을 처리해줍니다. name, payload 및 블록을 사용하여 ActiveSupport::Notifications.instrument를 호출하기만 하면 됩니다. 블록이 반환된 후에 알림이 전송됩니다. Active Support가 시작 및 종료 시간을 생성하고 계측기의 고유 ID를 추가합니다. instrument 호출에 전달된 모든 데이터가 페이로드로 전달됩니다. 다음은 예시입니다:

ActiveSupport::Notifications.instrument "my.custom.event", this: :data do
  # 여기에 사용자 정의 작업을 수행하세요
end

이제 다음과 같이 이벤트를 수신할 수 있습니다:

ActiveSupport::Notifications.subscribe "my.custom.event" do |name, started, finished, unique_id, data|
  puts data.inspect # {:this=>:data}
end

블록을 전달하지 않고도 instrument를 호출할 수도 있습니다. 이를 통해 다른 메시징 용도에도 기구를 활용할 수 있습니다.

ActiveSupport::Notifications.instrument "my.custom.event", this: :data

ActiveSupport::Notifications.subscribe "my.custom.event" do |name, started, finished, unique_id, data|
  puts data.inspect # {:this=>:data}
end

사용자 정의 이벤트를 정의할 때는 Rails 규칙을 따라야 합니다. 형식은 event.library입니다. 예를 들어 애플리케이션이 트윗을 보내는 경우 tweet.twitter라는 이벤트를 생성해야 합니다.

피드백

이 가이드의 품질을 개선하는 데 도움을 주시기를 권장합니다.

오타나 사실적인 오류를 발견하면 기여해주십시오. 시작하려면 문서 기여 섹션을 읽어보세요.

불완전한 내용이나 최신 정보가 아닌 내용을 발견할 수도 있습니다. 주요한 부분에 누락된 문서를 추가해주세요. Edge 가이드에서 이미 문제가 해결되었는지 확인하세요. 스타일과 규칙은 Ruby on Rails 가이드 지침을 확인하세요.

수정할 내용을 발견했지만 직접 수정할 수 없는 경우 이슈를 열어주세요.

마지막으로, Ruby on Rails 문서에 관한 모든 토론은 공식 Ruby on Rails 포럼에서 환영합니다.