rails activesupport通知 - 錯誤的db運行時值

[英]rails activesupport notifications - wrong db runtime value


I'm trying to log requests for my REST API application. I'm using rails notifications for this , like here http://railscasts.com/episodes/249-notifications-in-rails-3

我正在嘗試記錄我的REST API應用程序的請求。我正在使用rails通知,例如http://railscasts.com/episodes/249-notifications-in-rails-3

I can't understand how to solve one problem with rails notifications.

我無法理解如何解決rails通知的一個問題。

my initializer code

我的初始化代碼

ActiveSupport::Notifications.subscribe "process_action.action_controller" do |name, start, finish, id, payload|
 p name
 p start 
 p finish
 p id
 p payload
end



Controller respond section

    class PostsController < ApplicationController
      # GET /posts
      # GET /posts.json

      respond_to  :json, :html
     ....
end

Controller create action

控制器創建動作

  def create
    @post = Post.new(params[:post])
    @post.save!
    respond_with(@post, :location => nil)
 end

Console output

控制台輸出

"process_action.action_controller"
2013-02-02 20:13:11 +0200
2013-02-02 20:13:11 +0200
"951b8999e9b71d4a8949"
{:controller=>"PostsController", :action=>"create", :params=>{"utf8"=>"✓", "authenticity_token"=>"1WugY9gh6ZCRXjfBTuckye3c9XDvtCqMQ2JdBpCo88s=", "post"=>{"name"=>"post3", "title"=>"post3", "content"=>"post3"}, "commit"=>"Create Post", "action"=>"create", "controller"=>"posts"}, :format=>:html, :method=>"POST", :path=>"/posts", :status=>302, :view_runtime=>nil, :db_runtime=>0}

As you can see :db_runtime=>0

如您所見:db_runtime => 0

However if I change controller action code to default scaffold

但是,如果我將控制器操作代碼更改為默認支架

  def create
    @post = Post.new(params[:post])
    #@post.save!
    #respond_with(@post)
    respond_to do |format|
      if @post.save
        format.html { redirect_to @post, notice: 'Post was successfully created.' }
        format.json { render json: @post, status: :created, location: @post }
      else
        format.html { render action: "new" }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

I can see

我可以看到

"process_action.action_controller"
2013-02-02 20:22:51 +0200
2013-02-02 20:22:51 +0200
"bf2a3173c08a0fd9008e"
{:controller=>"PostsController", :action=>"create", :params=>{"utf8"=>"✓", "authenticity_token"=>"1WugY9gh6ZCRXjfBTuckye3c9XDvtCqMQ2JdBpCo88s=", "post"=>{"name"=>"post3", "title"=>"post3", "content"=>"post3"}, "commit"=>"Create Post", "action"=>"create", "controller"=>"posts"}, :format=>:html, :method=>"POST", :path=>"/posts", :status=>302, :view_runtime=>nil, :db_runtime=>4.727}

:db_runtime=>4.727

:db_runtime => 4.727

What is the reason of that and how I can fix it to make it work in first example ? Thanks !

這是什么原因以及我如何解決它以使其在第一個例子中起作用?謝謝 !

UPD

UPD

 bundle show rails
/Users/admin/.rvm/gems/ruby-1.9.3-p125/gems/rails-3.2.11
rvm current
ruby-1.9.3-p125

UPD2

UPD2

It seems like it doesn't work when I use respond_with! Can someone tell me why? Thanks

當我使用respond_with時,它似乎不起作用!有人可以告訴我為什么嗎?謝謝

3 个解决方案

#1


2  

Ok, it seems like a bug. Let see, what's going on:

好吧,這似乎是一個bug。讓我們看看,發生了什么:

First of all, we have AR railtie for controller action and its implementation for setting db_runtime by using cleanup_view_runtime hook

首先,我們有控制器動作的AR railtie及其使用cleanup_view_runtime鈎子設置db_runtime的實現

def cleanup_view_runtime
      if ActiveRecord::Base.connected?
       db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
       runtime = super
       db_rt_after_render = ActiveRecord::LogSubscriber.reset_runtime
       self.db_runtime = db_rt_before_render + db_rt_after_render
       runtime - db_rt_after_render
     else
       super
     end
end

App calls controller action -> action doing some db queries and renders some stuff -> before and after rendering AR Logger saves runtime data. Good.

應用程序調用控制器操作 - >執行某些數據庫查詢並呈現一些內容 - >在呈現AR Logger之前和之后保存運行時數據。好。

Let see how works respond_with

讓我們看看如何工作respond_with

def respond_with(*resources, &block)
  raise "In order to use respond_with, first you need to declare the formats your " <<
        "controller responds to in the class level" if self.class.mimes_for_respond_to.empty?

  if collector = retrieve_collector_from_mimes(&block)
    options = resources.size == 1 ? {} : resources.extract_options!
    options[:default_response] = collector.response
    (options.delete(:responder) || self.class.responder).call(self, resources, options)
  end
end

def self.call(*args)
  new(*args).respond
end

def to_format
  if get? || !has_errors? || response_overridden?
    default_render
  else
    display_errors
  end
rescue ActionView::MissingTemplate => e
  api_behavior(e)
end

It seems like too much code here, but you should see the callstack for this issue: respond_with -> self.class.responder.respond -> self.class.responder.to_format -> default_render -> default_renderer raise ActionView::MissingTemplate(because we don't have any). At this moment we can see implementation for rendering :json and :xml(api_behaviour) through catching ActionView::MissingTemplate.

這里似乎有太多代碼,但你應該看到這個問題的callstack:respond_with - > self.class.responder.respond - > self.class.responder.to_format - > default_render - > default_renderer引發ActionView :: MissingTemplate(因為我們沒有任何)。此時我們可以通過捕獲ActionView :: MissingTemplate看到渲染的實現:json和:xml(api_behaviour)。

Now we know how respond_with works, but AR Logger does'nt know.. cleanup_view_runtime hook is called twice: for default_renderer(at that time template data was prepared and some db queries were called, but we catch ActionView::MissingTemplate in rendering proccess)

現在我們知道respond_with是如何工作的,但是AR Logger不知道.. cleanup_view_runtime鈎子被調用兩次:對於default_renderer(那時模板數據已經准備好並且調用了一些數據庫查詢,但我們在渲染過程中捕獲了ActionView :: MissingTemplate)

db_rt_before_render = ActiveRecord::LogSubscriber.reset_runtime
runtime = super # <-- here
db_rt_after_render = ActiveRecord::LogSubscriber.reset_runtime

and for api_behavour(at that time all template data was ready for rendering and no db queries)

並為api_behavour(當時所有模板數據都准備好渲染,沒有數據庫查詢)

Some messy explanation, but I hope it will be helpful :)

一些凌亂的解釋,但我希望它會有所幫助:)

#2


0  

The Rails instrumentation works by wrapping the request at the Rack metal level and recording events for the different metrics. In both cases, the entire block should be wrapped and tracked by the standard instrumentation.

Rails工具通過將請求包裝在Rack金屬級別並記錄不同指標的事件來工作。在這兩種情況下,整個塊應該由標准儀器包裝和跟蹤。

The only difference I can see after digging into the source is calling save() vs. save!(). It looks like the underlying method event subscriptions in ActiveRecord may behave differently.

在深入挖掘源代碼后,我能看到的唯一區別是調用save()與save!()。看起來ActiveRecord中的基礎方法事件訂閱可能表現不同。

Try changing your respond_with() example to use save vs. save! and see if it records the db_runtime properly? If so, that's a Rails bug, and you can work around it by mimicking the save! features using save.

嘗試更改您的respond_with()示例以使用save vs. save!並查看它是否正確記錄了db_runtime?如果是這樣,那就是一個Rails錯誤,你可以通過模仿保存來解決它!功能使用保存。

#3


0  

UPDATE:

更新:

It's not straightforward and needs some tweak around..

這不是直截了當的,需要一些調整..

Not unless you write your own Railtie to hook into this like Active Record, but it's a bit more complex than copying what Active Record has...

除非你把自己的Railtie編寫成像Active Record一樣掛鈎,但它比復制Active Record有的復雜一點......

But here's how it does it:

但這是它如何做到的:

1) Log Subscriber

1)日志訂戶

2) Railtie

2)鐵路

3) Controller Runtime

3)控制器運行時

I hope that you got the hint of how to start getting into it.

我希望你能得到如何開始進入它的暗示。

Cheers!

干杯!


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2013/02/02/725ecc6a46cc77b51a5cbb55cb97bfe.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com