-
Notifications
You must be signed in to change notification settings - Fork 1
/
nginx_stat.rb
158 lines (124 loc) · 3.2 KB
/
nginx_stat.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
require "English"
unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
end
require 'thread'
require 'curses'
require "nginx_stat/io_tail"
##
# NginxStat displays the current requests per second and average request time.
# Default interval is 10 seconds.
class NginxStat
VERSION = "0.1.0"
##
# NginxStat.start 'online-43things.log', 'online-43people.log', 10
#
# Starts a new NginxStat for +filenames+ that prints every +interval+
# seconds.
#
# Stats for multiple log files requires curses.
def self.start(*args)
interval = 10
interval = Float(args.pop) if Float(args.last) rescue nil
stats = []
# if args.length > 1 and not defined? Curses then
# $stderr.puts "Multiple logfile support requires curses"
# exit 1
# end
# if defined? Curses then
# Curses.init_screen
# Curses.clear
# Curses.addstr "Collecting data...\n"
# Curses.refresh
# end
args.each_with_index do |filename, offset|
stat = self.new File.open(filename), interval, offset
stat.start
stats << stat
end
stats.each { |stat| stat.thread.join }
end
##
# The log reading thread
attr_reader :thread
##
# Current status line
attr_reader :status
##
# Creates a new NginxStat that will listen on +io+ and print every
# +interval+ seconds. +offset+ is only used for multi-file support.
def initialize(io, interval, offset = 0)
@io = io
@io_path = File.basename io.path rescue 'unknown'
@interval = interval.to_f
@offset = offset
@mutex = Mutex.new
@status = ''
@last_len = 0
@count = 0
@time = 0.0
@thread = nil
end
##
# Starts the NginxStat running. This method never returns.
def start
trap 'INT' do
Curses.close_screen if defined? Curses
exit
end
start_printer
read_log
end
def print
# if defined? Curses then
# Curses.setpos @offset, 0
# Curses.addstr ' ' * @last_len
# Curses.setpos @offset, 0
# Curses.addstr "#{@io_path}\t#{@status}"
# Curses.refresh
# else
# print "\r"
# print ' ' * @last_len
# print "\r"
puts @status
$stdout.flush
# end
end
private
##
# Starts a thread that prints log information every +interval+ seconds.
def start_printer
Thread.start do
count_sec = 0
average_time = 0.0
loop do
sleep @interval
@mutex.synchronize do
count_sec = @count / @interval
average_time = @time / @count.to_f
@count = 0
@time = 0.0
end
@status = "%5.1f req/sec, %.2f sec per req" % [count_sec, average_time]
print
@last_len = status.length
end
end
end
##
# Starts a thread that reads from +io+, updating NginxStat counters as it
# goes.
def read_log
@thread = Thread.start do
@io.tail_lines do |line|
unless exclude?(line)
@mutex.synchronize { @time += line.strip.split.last.to_f }
@mutex.synchronize { @count += 1 }
end
end
end
end
def exclude?(line)
line =~ /\.(gif|jpg|jpeg|png|ico)/
end
end