simple_apm 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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