simple_apm 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8a450ff5329c11a826e738f055c77033e5623896367cc64a171f12ea2e22dab7
4
- data.tar.gz: 1ffafa80b66578969520c09ac9ec78e1d2a00d83ede6f551c28e30e019531154
3
+ metadata.gz: 69c8c44cd6c1c1c98083753871364bbeb78f9f8d6c26d1d4a4bdd791e22349a3
4
+ data.tar.gz: 507a53cdc6cb281eb76d765560638138010e26b125f515a9289b1a6472677e0f
5
5
  SHA512:
6
- metadata.gz: 254e51e5514a8fba9268e5d61c6b80d75da06045b2c6b7857006713a5ed60b2bb3a3a2bca22fb294d94c0e5bbdad6dce629cc688cd9ab70d1abbdbbc48ca6d97
7
- data.tar.gz: e72dba40ef3ba6666ae1a4d27d6a622cbf2abab24781cf44826f0e3c4b47d517e398b39e9d8b6bcf6d80c4ae333b913a27ac0a3c415268c690ae862c2fdf3026
6
+ metadata.gz: a04629e1d91833e080cf9b503379332fbd1e490855306fd93a20ef7700db0bb642959feec81356dfd8ea21cd9b22015e82f3a8c10cda045cc29cc3efd622e009
7
+ data.tar.gz: 9033e87a25ecf8890edf0f5e56fb71d4875e8c304e4c5c85e73f3567952ac2bc9853f4807e0a736b281614029d4d32d9713b02b68a7b4c088bac050ce406fcc6
@@ -24,6 +24,7 @@ module SimpleApm
24
24
  sec_str(request.during),
25
25
  sec_str(request.db_runtime),
26
26
  sec_str(request.view_runtime),
27
+ request.memory_during.to_f.round(1),
27
28
  request.host,
28
29
  request.remote_addr
29
30
  ]
@@ -4,7 +4,7 @@ module SimpleApm
4
4
  attr_accessor :request_id, :action_name,
5
5
  :during, :started, :db_runtime, :view_runtime,
6
6
  :controller, :action, :format, :method,
7
- :host, :remote_addr, :url,
7
+ :host, :remote_addr, :url, :completed_memory, :memory_during,
8
8
  :exception, :status
9
9
  def initialize(h)
10
10
  h.each do |k, v|
@@ -6,6 +6,7 @@
6
6
  <th>总耗时</th>
7
7
  <th>db_time</th>
8
8
  <th>view time</th>
9
+ <th>内存增幅(M)</th>
9
10
  <th>host</th>
10
11
  <th>remote_addr</th>
11
12
  </tr>
@@ -14,6 +14,13 @@
14
14
  (数据库:<%= sec_str @request.db_runtime %>, View: <%= sec_str @request.view_runtime %>)
15
15
  </span>
16
16
  </p>
17
+ <p>
18
+ <label>结束时内存:</label>
19
+ <span>
20
+ <%= @request.completed_memory.to_f.round(1) %>M
21
+ (增幅:<%= @request.memory_during.to_f.round(1) %>M)
22
+ </span>
23
+ </p>
17
24
  <p>
18
25
  <label>server:</label>
19
26
  <span><%= @request.host %></span>
@@ -10,4 +10,7 @@ action_slow_request_limit:
10
10
  # 项目名,默认为 'app',区分项目名可以多个项目数据存于一台redis server上
11
11
  app_name:
12
12
  # 记录SQL的最低时间(单位:秒),小于指定数值的则不记录
13
- sql_critical_time:
13
+ sql_critical_time:
14
+ # 不统计的请求(值为:xxxController#Action)(数组)
15
+ # - Devise::SessionsController#create
16
+ exclude_actions:
@@ -5,8 +5,10 @@ module SimpleApm
5
5
  end
6
6
 
7
7
  def call(env)
8
- if SimpleApm::Redis.running?
8
+ if SimpleApm::Redis.ping && SimpleApm::Redis.running?
9
+ SimpleApm::ProcessingThread.start!
9
10
  Thread.current['action_dispatch.request_id'] = env['action_dispatch.request_id']
11
+ Thread.current[:current_process_memory] = GetProcessMem.new.mb
10
12
  end
11
13
  @app.call(env)
12
14
  end
@@ -12,5 +12,8 @@ module SimpleApm
12
12
  APP_NAME = ApmSettings['app_name'].presence || 'app'
13
13
  # SQL临界值
14
14
  SQL_CRITICAL_TIME = ApmSettings['sql_critical_time'].to_f
15
+ # 不纳入统计的action
16
+ t = ApmSettings['exclude_actions']
17
+ EXCLUDE_ACTIONS = t.is_a?(Array) ? t : [t]
15
18
  end
16
19
  end
@@ -1,3 +1,3 @@
1
1
  module SimpleApm
2
- VERSION = '1.0.4'
2
+ VERSION = '1.0.5'
3
3
  end
data/lib/simple_apm.rb CHANGED
@@ -2,80 +2,153 @@ require "simple_apm/setting"
2
2
  require "simple_apm/redis"
3
3
  require "simple_apm/engine"
4
4
  require 'callsite'
5
+ require 'get_process_mem'
5
6
  module SimpleApm
6
- # RUBY_PLATFORM darwin linux win32
7
- # ps aux | grep -w 30057 | awk '$2==30057 {print $6}'
7
+ # 订阅log ---- start ----
8
8
  ActiveSupport::Notifications.subscribe('process_action.action_controller') do |name, started, finished, unique_id, payload|
9
- begin
10
- SimpleApm::RedisKey.query_date = nil
11
- request_id = Thread.current['action_dispatch.request_id']
12
- need_skip = payload[:controller] == 'SimpleApm::ApmController'
13
- need_skip = true if payload[:status].to_s=='302' && payload[:path].to_s=~/login/ && payload[:method].to_s.downcase=='get'
14
- if request_id.present?
15
- if need_skip
16
- SimpleApm::Sql.delete_by_request_id(request_id)
17
- else
18
- action_name = "#{payload[:controller]}##{payload[:action]}" #payload[:format]
19
- info = {
20
- request_id: request_id,
21
- action_name: action_name,
22
- url: payload[:path],
23
- during: finished - started,
24
- started: started.to_s,
25
- db_runtime: payload[:db_runtime].to_f / 1000,
26
- view_runtime: payload[:view_runtime].to_f / 1000,
27
- controller: payload[:controller],
28
- action: payload[:action],
29
- host: Socket.gethostname,
30
- remote_addr: (payload[:headers]['HTTP_X_REAL_IP'] rescue nil),
31
- method: payload[:method],
32
- format: payload[:format],
33
- exception: payload[:exception].presence.to_json
34
- }.with_indifferent_access
35
- info[:status] = '500' if payload[:exception]
36
- # 存储
37
- in_slow = SimpleApm::SlowRequest.update_by_request info
38
- in_action_info = SimpleApm::Action.update_by_request info
39
- SimpleApm::Hit.update_by_request info
40
- if in_action_info || in_slow
41
- SimpleApm::Request.create info
42
- else
43
- SimpleApm::Sql.delete_by_request_id(request_id)
9
+ ProcessingThread.add_event(
10
+ name: name,
11
+ request_id: Thread.current['action_dispatch.request_id'],
12
+ started: started, finished: finished,
13
+ payload: payload,
14
+ started_memory: Thread.current[:current_process_memory],
15
+ completed_memory: GetProcessMem.new.mb
16
+ )
17
+ Thread.current['action_dispatch.request_id'] = nil
18
+ end
19
+
20
+ ActiveSupport::Notifications.subscribe 'sql.active_record' do |name, started, finished, unique_id, payload|
21
+ request_id = Thread.current['action_dispatch.request_id'].presence || Thread.main['action_dispatch.request_id']
22
+ if request_id
23
+ if dev_caller = caller.detect {|c| c.include? Rails.root.to_s}
24
+ c = ::Callsite.parse(dev_caller)
25
+ payload.merge!(:line => c.line, :filename => c.filename.to_s.gsub(Rails.root.to_s, ''), :method => c.method)
26
+ end
27
+ ProcessingThread.add_event(
28
+ name: name,
29
+ request_id: request_id,
30
+ started: started, finished: finished,
31
+ payload: payload
32
+ )
33
+ end
34
+ end
35
+ # 订阅log ---- end ----
36
+
37
+
38
+ # 开启一个接收事件的并行thread,每隔一秒处理一次
39
+ class ProcessingThread
40
+ class << self
41
+ def add_event(e)
42
+ @processing_thread && @processing_thread[:events].push(e)
43
+ end
44
+ def start!
45
+ @main_thread ||= Thread.current
46
+ @processing_thread ||= Thread.new do
47
+ Thread.current.name = 'simple-apm-processing-thread'
48
+ Thread.current[:events] ||= []
49
+ loop do
50
+ while e = Thread.current[:events].shift
51
+ Worker.process! e
52
+ end
53
+ sleep 1
44
54
  end
45
55
  end
46
56
  end
47
- rescue => e
48
- Logger.new("#{Rails.root}/log/simple_apm.log").info e.backtrace.join("\n")
49
57
  end
50
58
  end
51
59
 
52
- ActiveSupport::Notifications.subscribe 'sql.active_record' do |name, started, finished, unique_id, payload|
53
- begin
54
- SimpleApm::RedisKey.query_date = nil
55
- request_id = Thread.current['action_dispatch.request_id'].presence || Thread.main['action_dispatch.request_id']
56
- during = finished - started
57
- if request_id.present? || during < SimpleApm::Setting::SQL_CRITICAL_TIME
58
- dev_caller = caller.detect {|c| c.include? Rails.root.to_s}
59
- if dev_caller
60
- c = ::Callsite.parse(dev_caller)
61
- payload.merge!(:line => c.line, :filename => c.filename.to_s.gsub(Rails.root.to_s, ''), :method => c.method)
60
+ # 处理信息的操作方法
61
+ class Worker
62
+ class << self
63
+ def process!(event)
64
+ SimpleApm::RedisKey.query_date = nil
65
+ if event[:name]=='process_action.action_controller'
66
+ process_controller(event)
67
+ elsif event[:name]=='sql.active_record'
68
+ process_sql(event)
69
+ end
70
+ end
71
+
72
+ private
73
+ def process_controller(event)
74
+ payload = event[:payload]
75
+ started_memory = event[:started_memory]
76
+ completed_memory = event[:completed_memory]
77
+ finished = event[:finished]
78
+ started = event[:started]
79
+ request_id = event[:request_id]
80
+ begin
81
+ need_skip = payload[:controller] == 'SimpleApm::ApmController'
82
+ need_skip = true if SimpleApm::Setting::EXCLUDE_ACTIONS.include?("#{payload[:controller]}##{payload[:action]}")
83
+ need_skip = true if payload[:status].to_s=='302' && payload[:path].to_s=~/login/ && payload[:method].to_s.downcase=='get'
84
+
85
+ if request_id.present?
86
+ if need_skip
87
+ SimpleApm::Sql.delete_by_request_id(request_id)
88
+ else
89
+ action_name = "#{payload[:controller]}##{payload[:action]}"
90
+ memory_during = completed_memory - started_memory rescue 0
91
+ info = {
92
+ request_id: request_id,
93
+ action_name: action_name,
94
+ url: payload[:path],
95
+ during: finished - started,
96
+ started: started.to_s,
97
+ db_runtime: payload[:db_runtime].to_f / 1000,
98
+ view_runtime: payload[:view_runtime].to_f / 1000,
99
+ controller: payload[:controller],
100
+ action: payload[:action],
101
+ host: Socket.gethostname,
102
+ remote_addr: (payload[:headers]['HTTP_X_REAL_IP'] rescue nil),
103
+ method: payload[:method],
104
+ completed_memory: completed_memory,
105
+ memory_during: memory_during,
106
+ format: payload[:format],
107
+ exception: payload[:exception].presence.to_json
108
+ }.with_indifferent_access
109
+ info[:status] = '500' if payload[:exception]
110
+ # 存储
111
+ in_slow = SimpleApm::SlowRequest.update_by_request info
112
+ in_action_info = SimpleApm::Action.update_by_request info
113
+ SimpleApm::Hit.update_by_request info
114
+ if in_action_info || in_slow
115
+ SimpleApm::Request.create info
116
+ else
117
+ SimpleApm::Sql.delete_by_request_id(request_id)
118
+ end
119
+ end
120
+ end
121
+ rescue => e
122
+ Logger.new("#{Rails.root}/log/simple_apm.log").info e.backtrace.join("\n")
123
+ end
124
+ end
125
+
126
+ def process_sql(event)
127
+ payload = event[:payload]
128
+ finished = event[:finished]
129
+ started = event[:started]
130
+ request_id = event[:request_id]
131
+ begin
132
+ during = finished - started
133
+ if request_id.present? && ( SimpleApm::Setting::SQL_CRITICAL_TIME.blank? || during > SimpleApm::Setting::SQL_CRITICAL_TIME)
134
+ # ActiveRecord::Relation::QueryAttribute
135
+ sql_value = payload[:binds].map {|q| [q.name, q.value]} rescue nil
136
+ info = {
137
+ request_id: request_id,
138
+ name: payload[:name],
139
+ during: during,
140
+ started: started,
141
+ sql: payload[:sql],
142
+ value: sql_value,
143
+ filename: payload[:filename],
144
+ line: payload[:line]
145
+ }.with_indifferent_access
146
+ SimpleApm::Sql.create request_id, info
147
+ end
148
+ rescue => e
149
+ Logger.new("#{Rails.root}/log/simple_apm.log").info e.backtrace.join("\n")
62
150
  end
63
- # ActiveRecord::Relation::QueryAttribute
64
- sql_value = payload[:binds].map {|q| [q.name, q.value]} rescue nil
65
- info = {
66
- request_id: request_id,
67
- name: payload[:name],
68
- during: during,
69
- started: started,
70
- sql: payload[:sql],
71
- value: sql_value,
72
- filename: payload[:filename],
73
- line: payload[:line]
74
- }.with_indifferent_access
75
- SimpleApm::Sql.create request_id, info
76
151
  end
77
- rescue => e
78
- Logger.new("#{Rails.root}/log/simple_apm.log").info e.backtrace.join("\n")
79
152
  end
80
153
  end
81
154
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_apm
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - yuanyin.xia
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-13 00:00:00.000000000 Z
11
+ date: 2018-07-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: 0.0.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: get_process_mem
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  description: 'xyy: Simple Apm View for rails using redis.'
56
70
  email:
57
71
  - xiayuanyin@qq.com