gri 10.0.0

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.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/MIT-LICENSE.txt +20 -0
  4. data/README.md +132 -0
  5. data/Rakefile +5 -0
  6. data/bin/grapher +17 -0
  7. data/bin/gri +5 -0
  8. data/bin/gricast +17 -0
  9. data/bin/grispark +5 -0
  10. data/bin/griwalk +9 -0
  11. data/bin/trad +19 -0
  12. data/bin/trad-http +17 -0
  13. data/gri.gemspec +21 -0
  14. data/lib/fluent/plugin/out_gri.rb +56 -0
  15. data/lib/gri/api.rb +28 -0
  16. data/lib/gri/app_collector.rb +154 -0
  17. data/lib/gri/app_walker.rb +23 -0
  18. data/lib/gri/blank.rb +49 -0
  19. data/lib/gri/builtindefs.rb +211 -0
  20. data/lib/gri/cast.rb +84 -0
  21. data/lib/gri/cgraph.rb +37 -0
  22. data/lib/gri/clist.rb +163 -0
  23. data/lib/gri/collector.rb +284 -0
  24. data/lib/gri/config.rb +134 -0
  25. data/lib/gri/ds_list.rb +166 -0
  26. data/lib/gri/format_helper.rb +112 -0
  27. data/lib/gri/gparams.rb +43 -0
  28. data/lib/gri/graph.rb +239 -0
  29. data/lib/gri/grapher.rb +70 -0
  30. data/lib/gri/ldb.rb +160 -0
  31. data/lib/gri/list.rb +242 -0
  32. data/lib/gri/log.rb +140 -0
  33. data/lib/gri/loop.rb +109 -0
  34. data/lib/gri/ltsv.rb +58 -0
  35. data/lib/gri/main.rb +107 -0
  36. data/lib/gri/mlog.rb +22 -0
  37. data/lib/gri/mmsgpack.rb +57 -0
  38. data/lib/gri/msnmp.rb +601 -0
  39. data/lib/gri/page.rb +235 -0
  40. data/lib/gri/pcollector.rb +209 -0
  41. data/lib/gri/plugin.rb +75 -0
  42. data/lib/gri/plugin/bootstrap.rb +65 -0
  43. data/lib/gri/plugin/cisco.rb +98 -0
  44. data/lib/gri/plugin/exec_collector.rb +89 -0
  45. data/lib/gri/plugin/juniper.rb +5 -0
  46. data/lib/gri/plugin/netsnmp.rb +8 -0
  47. data/lib/gri/plugin/ucdavis.rb +176 -0
  48. data/lib/gri/plugin/writer_fluentd.rb +26 -0
  49. data/lib/gri/polling_unit.rb +88 -0
  50. data/lib/gri/q.rb +5 -0
  51. data/lib/gri/request.rb +29 -0
  52. data/lib/gri/rrd.rb +438 -0
  53. data/lib/gri/scheduler.rb +68 -0
  54. data/lib/gri/sgraph.rb +147 -0
  55. data/lib/gri/spark.rb +94 -0
  56. data/lib/gri/tra_collector.rb +80 -0
  57. data/lib/gri/trad.rb +170 -0
  58. data/lib/gri/updater.rb +201 -0
  59. data/lib/gri/util_daemon.rb +19 -0
  60. data/lib/gri/util_marshal.rb +13 -0
  61. data/lib/gri/utils.rb +63 -0
  62. data/lib/gri/vendor.rb +76 -0
  63. data/lib/gri/version.rb +3 -0
  64. data/lib/gri/wmain.rb +67 -0
  65. data/lib/gri/writer.rb +184 -0
  66. data/mcollector +47 -0
  67. data/test/mock.rb +60 -0
  68. data/test/root/gra/.sysdb/sysdb.txt +3 -0
  69. data/test/root/gra/testhost/.records.txt +2 -0
  70. data/test/root/if.def +2 -0
  71. data/test/root/test.conf +4 -0
  72. data/test/root/testtab +9 -0
  73. data/test/root/testtab2 +2 -0
  74. data/test/root/tra/testhost/_/20130614 +20 -0
  75. data/test/test_app.rb +58 -0
  76. data/test/test_builtindefs.rb +24 -0
  77. data/test/test_collector.rb +58 -0
  78. data/test/test_config.rb +62 -0
  79. data/test/test_ds_list.rb +48 -0
  80. data/test/test_exec_collector.rb +33 -0
  81. data/test/test_format_helper.rb +68 -0
  82. data/test/test_graph.rb +69 -0
  83. data/test/test_ldb.rb +29 -0
  84. data/test/test_list.rb +65 -0
  85. data/test/test_log.rb +16 -0
  86. data/test/test_loop.rb +35 -0
  87. data/test/test_ltsv.rb +38 -0
  88. data/test/test_main.rb +19 -0
  89. data/test/test_mmsgpack.rb +27 -0
  90. data/test/test_msnmp.rb +147 -0
  91. data/test/test_page.rb +51 -0
  92. data/test/test_pcollector.rb +71 -0
  93. data/test/test_plugin.rb +62 -0
  94. data/test/test_plugin_cisco.rb +23 -0
  95. data/test/test_polling_unit.rb +58 -0
  96. data/test/test_request.rb +26 -0
  97. data/test/test_rrd.rb +53 -0
  98. data/test/test_rrd_updater.rb +139 -0
  99. data/test/test_scheduler.rb +31 -0
  100. data/test/test_tra_collector.rb +40 -0
  101. data/test/test_trad.rb +33 -0
  102. data/test/test_util_marshal.rb +17 -0
  103. data/test/test_utils.rb +15 -0
  104. data/test/test_vendor.rb +40 -0
  105. data/test/test_writer.rb +33 -0
  106. data/test/unittest_helper.rb +27 -0
  107. metadata +208 -0
@@ -0,0 +1,68 @@
1
+ module GRI
2
+ class Scheduler
3
+ attr_accessor :queue, :writers, :fake_descr_hash
4
+
5
+ def initialize loop, metrics
6
+ @loop = loop
7
+ @metrics = metrics
8
+ @loop.on_detach {process_queue}
9
+ @writers = []
10
+ end
11
+
12
+ def process_queue
13
+ while @loop.collectors.size < 5
14
+ host, options = queue.shift
15
+ break unless host
16
+ next if host =~ /^GRIMETRICS/
17
+
18
+ ts = options['type']
19
+ col_types = ts ? ts.split(',') : ['snmp']
20
+ for col_type in col_types
21
+ process1 col_type, host, options
22
+ end
23
+ end
24
+ end
25
+
26
+ def process1 col_type, host, options
27
+ collector = Collector.create(col_type, host, options,
28
+ @fake_descr_hash) {|records|
29
+ for writer in @writers
30
+ writer.write records
31
+ end
32
+ @metrics[:record_count] += records.size
33
+ }
34
+ if collector
35
+ #puts "#{collector.class} (#{col_type}): #{host}" if $debug
36
+ interval = (options['interval'] || 300).to_i
37
+ collector.interval = interval
38
+ collector.timeout = [90, interval].min
39
+ collector.on_error {@metrics[:error_count] += 1}
40
+ collector.on_retry {@metrics[:retry_count] += 1}
41
+ Log.info "[#{$$}] #{host}: collect #{col_type}"
42
+ begin
43
+ @loop.run if collector.sync?
44
+ @loop.attach collector
45
+ rescue SystemCallError
46
+ Log.error "#{host}: ERROR: #{$!}"
47
+ @loop.detach collector
48
+ end
49
+ @metrics[:run_count] += 1
50
+ end
51
+ end
52
+
53
+ def finalize
54
+ @writers.each {|w| w.finalize if w.respond_to? :finalize}
55
+ end
56
+ end
57
+
58
+ class UScheduler < Scheduler
59
+ def process_queue
60
+ while @loop.collectors.size < 5
61
+ host, options = queue.shift
62
+ break unless host
63
+ @metrics[:nometrics] = 1 if host =~ /^GRIMETRICS/
64
+ process1 'tra', host, options
65
+ end
66
+ end
67
+ end
68
+ end
data/lib/gri/sgraph.rb ADDED
@@ -0,0 +1,147 @@
1
+ # -*- coding: utf-8 -*-
2
+ module GRI
3
+ class Sgraph
4
+ @height = 20
5
+
6
+ def initialize options
7
+ @options = options
8
+ end
9
+
10
+ BARS = [" ", "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█" ]
11
+ def bar(val, unit, non_fullwidth_font = false)
12
+ n = (val.to_f/unit)
13
+ @height.times.map{|i|
14
+ x = n - (i * 8)
15
+ if x <= 0
16
+ BARS.first
17
+ else
18
+ bar_symbol = if x < 8
19
+ BARS[x]
20
+ else
21
+ BARS.last
22
+ end
23
+ bar_symbol += " " if non_fullwidth_font
24
+ bar_symbol
25
+ end
26
+ }
27
+ end
28
+
29
+ def render(json, summary, url = nil)
30
+ #@options = {:t=>'d', :non_fullwidth_font=>false}
31
+ @height = 16
32
+ rowss = json['data']
33
+ meta = json['meta']
34
+ step = meta['step']
35
+ start_timestamp = meta["start"]
36
+ end_timestamp = meta["end"].to_i
37
+ s = Time.at(start_timestamp).localtime.strftime("%Y-%m-%d %H:%M:%S")
38
+ e = Time.at(end_timestamp ).localtime.strftime("%Y-%m-%d %H:%M:%S")
39
+
40
+ rowss.transpose.each_with_index {|rows, i|
41
+ #puts "i: #{i}"
42
+ max = rows.flatten.compact.max
43
+
44
+ u0 = (max / @height)
45
+ ex0 = (Math.log(u0) / Math.log(10)).floor
46
+ unit = (u0 / 8 / (10**(ex0-1))).ceil * (10**(ex0-1))
47
+
48
+ max_val = unit*@height
49
+ #max_val = max
50
+ #unit = max_val / (@height * 8).to_f
51
+
52
+ puts " #{(url)}"
53
+ puts " #{s} -"
54
+ puts " #{meta['legend'][i].center(78)}"
55
+ render_graph rows, unit
56
+ render_x_axis_labels(rows, start_timestamp, step)
57
+ puts ""
58
+
59
+ #sums = summary.first.last
60
+ #puts " #{sprintf("cur: %.1f ave: %.1f max: %.1f min %.1f", *sums)}"
61
+ }
62
+ end
63
+
64
+ def render_graph rows, unit
65
+ result = []
66
+
67
+ rows.map{|row|
68
+ bar(row, unit, @options[:non_fullwidth_font])
69
+ }.transpose.reverse.each_with_index do |row, i|
70
+ i = (@height- i)
71
+ if i.even?
72
+ n = unit * i * 8
73
+ if n > 10
74
+ label = sprintf("%6s", to_scalestr(unit * i * 8))
75
+ else
76
+ label = sprintf("%6g", unit * i * 8)
77
+ end
78
+ else
79
+ label = ''
80
+ end
81
+ line = row.join
82
+ if color = @options[:color]
83
+ line = Term::ANSIColor.send(color, line)
84
+ end
85
+ result << "#{sprintf('%6s', label)}|#{line}|"
86
+ end
87
+ puts result.join("\n")
88
+ end
89
+
90
+ def to_scalestr v, base=1000
91
+ if v == nil or base == nil or base == 0
92
+ return(v.to_i == v ? v.to_i : v)
93
+ end
94
+ v = v.to_f
95
+ if v >= base ** 4
96
+ "%gT" % (v / (base ** 4))
97
+ elsif v >= base ** 3
98
+ "%gG" % (v / (base ** 3))
99
+ elsif v >= base ** 2
100
+ "%gM" % (v / (base ** 2))
101
+ elsif v >= base
102
+ "%gK" % (v / base)
103
+ else
104
+ v.to_s
105
+ end
106
+ end
107
+
108
+ def render_x_axis_labels(rows, start_timestamp, step)
109
+ tm = rows.size * step
110
+
111
+ x_axis_labels = rows.length.times.select{|n| n % 8 == 0}. map{|n|
112
+ t = Time.at(start_timestamp + (n * step)).localtime
113
+ sprintf("%-8s", to_axis_label(t, tm))
114
+ }.join
115
+ x_axis_arrows= rows.length.times.select{|n| n % 8 == 0}. map{|n|
116
+ " / "
117
+ }.join
118
+
119
+ case 'show'#@options[:x_axis_label]
120
+ when "show"
121
+ puts sprintf("%6s%s", "", x_axis_arrows)
122
+ puts sprintf("%6s%s", "", x_axis_labels)
123
+ when "simple"
124
+ puts sprintf("%6s%s", "", x_axis_labels)
125
+ end
126
+ end
127
+
128
+ def to_axis_label t, tm
129
+ f = if tm <= 3600
130
+ '%M'
131
+ elsif tm <= 48*3600
132
+ '%H:%M'
133
+ elsif tm <= 8*24*3600
134
+ '%a'
135
+ elsif tm <= 35*24*3600
136
+ '%d'
137
+ else
138
+ '%m'
139
+ end
140
+ t.strftime f
141
+ end
142
+
143
+ TERMS = {'sh'=>['Hour', 3600], 's8h'=>['8Hours', 8*3600],
144
+ 'd'=>['Day', 24*3600], 'w'=>['Week', 7*24*3600],
145
+ 'm'=>['Month', 31*24*3600], 'y'=>['Year', 366*24*3600]}
146
+ end
147
+ end
data/lib/gri/spark.rb ADDED
@@ -0,0 +1,94 @@
1
+ require 'optparse'
2
+ require 'uri'
3
+ require 'open-uri'
4
+ require 'yaml'
5
+
6
+ require 'gri/q'
7
+ require 'gri/gparams'
8
+ require 'gri/sgraph'
9
+
10
+ module GRI
11
+ class Spark
12
+ def run options={}
13
+ optparser = optparse options
14
+ optparser.parse!
15
+ exit unless (url_s = ARGV.shift)
16
+
17
+ url = URI.parse url_s
18
+ params = GParams.new
19
+ parse_query url.query, params
20
+ fix_params params, options
21
+ url.query = mk_query params
22
+ if options[:user]
23
+ if options[:pass]
24
+ http_basic_authentication = [options[:user], options[:pass]]
25
+ else
26
+ print "Password:"
27
+ system "stty -echo"
28
+ password = $stdin.gets.chop
29
+ system "stty echo"
30
+ http_basic_authentication = [options[:user], password]
31
+ end
32
+ end
33
+ obj = fetch url, http_basic_authentication
34
+ graph = Sgraph.new options
35
+ graph.render obj, {}, url
36
+ end
37
+
38
+ def fix_params params, options
39
+ etime = params['etime'].to_i
40
+ etime = (Time.now + etime).to_i if etime <= 0
41
+ if (t = options[:t]) and (v = Sgraph::TERMS[t])
42
+ stime = (stime = params['stime']) ? stime.to_i : -v[1]
43
+ stime = (etime + stime).to_i if stime <= 0
44
+ else
45
+ stime = (stime = params['stime']) ? stime.to_i : -28*3600
46
+ stime = (etime + stime).to_i if stime <= 0
47
+ end
48
+ params['stime'] = stime
49
+ params['etime'] = etime
50
+ params['maxrows'] = 70
51
+ params['fmt'] = 'json'
52
+ end
53
+
54
+ def fetch url, http_basic_authentication
55
+ if http_basic_authentication
56
+ str = open(url,
57
+ :http_basic_authentication=>http_basic_authentication).read
58
+ else
59
+ str = open(url).read
60
+ end
61
+ obj = YAML.load str
62
+ obj
63
+ end
64
+
65
+ def mk_query params
66
+ params.map {|k, v|
67
+ (Array === v) ? v.map {|vv| "#{k}=#{vv}"} : "#{k}=#{v}"
68
+ }.flatten.join('&')
69
+ end
70
+
71
+ def parse_query qs, params={}
72
+ (qs || '').split(/[&;] */n).each {|item|
73
+ k, v = item.split('=', 2)
74
+ params[k] = v
75
+ }
76
+ params
77
+ end
78
+
79
+ def optparse opts
80
+ op = OptionParser.new
81
+ op.on('--debug') {$debug = true; STDOUT.sync = true;
82
+ opts['log-level'] = 'debug'}
83
+ op.on('--Doption=STR') {|arg| (opts['Doption'] ||= []).push arg}
84
+ op.on('-O OPT_STR') {|arg| (opts['O'] ||= []).push arg}
85
+ op.on('-c', '--config-path=PATH') {|arg| opts[:config_path] = arg}
86
+ op.on('--log-level=LEVEL') {|arg| opts['log-level'] = arg}
87
+ op.on('--nop') {opts['nop'] = true}
88
+ op.on('-t ARG') {|arg| opts[:t] = arg}
89
+ op.on('-u', '--user=USER') {|arg| opts[:user] = arg}
90
+ op.on('-p', '--password=PASSWORD') {|arg| opts[:pass] = arg}
91
+ op
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,80 @@
1
+ require 'gri/collector'
2
+ require 'gri/ldb'
3
+
4
+ module GRI
5
+ class TraCollector < Collector
6
+ TYPES['tra'] = self
7
+
8
+ def on_attach
9
+ # @loop.detach self if @config['nop']
10
+ dir = "#{self.class.gra_dir}/#{host}"
11
+ Dir.mkdir dir unless File.directory? dir
12
+
13
+ db_class = self.class.db_class
14
+ db = (db_class <= RemoteLDB) ? db_class.new(self.class.tra_uri, host) :
15
+ db_class.new("#{self.class.tra_dir}/#{host}")
16
+
17
+ @loop.next_tick {
18
+ begin
19
+ update_rrd_dir dir, db, options
20
+ ensure
21
+ @loop.detach self
22
+ db.close
23
+ end
24
+ }
25
+ end
26
+
27
+ def update_rrd_dir dir, db, options
28
+ data_names = db.get_data_names
29
+ for data_name, interval in data_names
30
+ lu_path = "#{dir}/.lu_#{data_name}"
31
+ lu_time = nil
32
+ lu_pos = nil
33
+ if File.exist? lu_path
34
+ str = File.read(lu_path)
35
+ if str =~ /\A(\d+) (\d+)\Z/
36
+ lu_time = Time.at $1.to_i
37
+ lu_pos = $2.to_i
38
+ end
39
+ end
40
+ lu_time ||= Time.at(0)
41
+ lu_pos ||= 0
42
+
43
+ update_p = false
44
+ t = nil
45
+ records = []
46
+ db.get_after(data_name, lu_time, lu_pos) {|t, record, pos|
47
+ if $debug
48
+ ts = t.strftime '%Y-%m-%d %H:%M:%S'
49
+ puts "update #{ts} #{record['_host']} #{record['_key']}"
50
+ end
51
+ record['_interval'] = interval
52
+ records.push record
53
+ update_p = true
54
+ lu_time = t
55
+ lu_pos = pos
56
+ if records.size > 2000
57
+ @cb.call records
58
+ records.clear
59
+ end
60
+ }
61
+ if update_p
62
+ @cb.call records
63
+ open(lu_path, 'w') {|f| f.print "#{lu_time.to_i} #{lu_pos}"}
64
+ end
65
+ end
66
+ end
67
+
68
+ def recdump dir, records
69
+ path = dir + '/.rdump'
70
+ open(path, 'a') {|f|
71
+ records.each {|r| f.puts r.inspect}
72
+ }
73
+ end
74
+
75
+ class <<self
76
+ attr_accessor :tra_dir, :gra_dir
77
+ attr_accessor :db_class, :tra_uri
78
+ end
79
+ end
80
+ end
data/lib/gri/trad.rb ADDED
@@ -0,0 +1,170 @@
1
+ require 'gri/ldb'
2
+
3
+ module GRI
4
+ class Trad
5
+ def initialize
6
+ @acls = nil
7
+ @tra_dir = nil
8
+ end
9
+
10
+ def public_dir
11
+ '/notexist'
12
+ end
13
+
14
+ def load_acls config
15
+ acls = config.getvar 'acl-permit'
16
+ acls = acls ? acls.map {|pat| Regexp.new pat} : []
17
+ acls.push(/^127\.0\.0\.1$/)
18
+ acls.push(/^::ffff:127\.0\.0\.1$/)
19
+ acls.push(/^::1$/)
20
+ acls
21
+ end
22
+
23
+ def allowed? acls, remote_addr
24
+ acls.detect {|re| remote_addr =~ re}
25
+ end
26
+
27
+ def call env
28
+ @acls ||= load_acls Config
29
+ unless allowed?(@acls, env['REMOTE_ADDR'])
30
+ return [401, {}, ['Unauthorized']]
31
+ end
32
+
33
+ @root_dir ||= Config['root-dir'] || Config::ROOT_PATH
34
+ @tra_dir ||= (Config['tra-dir'] || @root_dir + '/tra')
35
+
36
+ req = Rack::Request.new env
37
+ serve @tra_dir, req.path_info, req
38
+ end
39
+
40
+ def serve tra_dir, path_info, params
41
+ headers = {}
42
+ body = []
43
+
44
+ if path_info =~ /\A\/get\b/ #/
45
+ s = params['s']
46
+ dir = "#{tra_dir}/#{params['h']}"
47
+ if File.directory?(dir)
48
+ t = Time.at(params['t'].to_i)
49
+ pos = params['pos'].to_i
50
+ ldb = LocalLDB.new dir
51
+ headers.clear
52
+ prev_time = 0
53
+ ldb.getl_after(s, t, pos) {|time, line, pos|
54
+ if body.size > 1000 and time.to_i > prev_time
55
+ headers['X-GRI-Continue'] = "#{prev_time.to_s} #{pos}"
56
+ break
57
+ end
58
+ prev_time = time.to_i
59
+ body.push(line+"\n")
60
+ }
61
+ headers['X-GRI-Pos'] = pos.to_s
62
+ end
63
+ elsif path_info =~ /\A\/get_data_names\b/ #/
64
+ dir = "#{tra_dir}/#{params['h']}"
65
+ ldb = LocalLDB.new dir
66
+ ldb.get_data_names.each {|k, v| body.push "#{k}_#{v}\n"}
67
+ elsif path_info =~ /\A\/gritab\b/ #/
68
+ gritab_path = Config['gritab-path'] || @root_dir + '/gritab'
69
+ if File.exist? gritab_path
70
+ open(gritab_path) {|f|
71
+ while line = f.gets
72
+ next if line =~ /\A\s*#|\A\z/
73
+ body.push line
74
+ end
75
+ }
76
+ end
77
+ end
78
+ [200, headers, body]
79
+ end
80
+
81
+ def run options={}
82
+ optparser = optparse options
83
+ optparser.parse!
84
+ Process.daemon true if options[:daemonize] and !$debug
85
+ config_path = options[:config_path] || GRI::Config::DEFAULT_PATH
86
+ config = GRI::Config.init config_path
87
+ @acls ||= load_acls config
88
+ @root_dir ||= config['root-dir'] || GRI::Config::ROOT_PATH
89
+ @tra_dir ||= (config['tra-dir'] || @root_dir + '/tra')
90
+ log_dir = config['log-dir'] || @root_dir + '/log'
91
+ Dir.mkdir log_dir unless File.exist? log_dir
92
+ Log.init "#{log_dir}/#{optparser.program_name}.log"
93
+
94
+ bind_address = options[:bind_address] || '0.0.0.0'
95
+ port = options[:port] || 7079
96
+ server_sock = TCPServer.new bind_address, port
97
+ rs0 = [server_sock]
98
+ params = {}
99
+ while true
100
+ next unless (a = IO.select(rs0, nil, nil, 1))
101
+ rs, = a
102
+ for io in rs
103
+ begin
104
+ if io.kind_of? TCPServer
105
+ sock = server_sock.accept
106
+ peername = sock.peeraddr[2]
107
+ peeraddr = sock.peeraddr[3]
108
+ if allowed?(@acls, peeraddr)
109
+ puts "#{peeraddr}: accespt #{sock.object_id}" if $debug
110
+ else
111
+ sock.close
112
+ puts "#{peeraddr}: reject" if $debug
113
+ next
114
+ end
115
+ rs0.push sock
116
+ elsif io.eof?
117
+ io.close
118
+ rs0.delete io
119
+ else
120
+ line = io.gets
121
+ line.chomp!
122
+ if line =~ /\A(\/\w+)\s*(\S+)?$/ #/
123
+ pi = $1
124
+ qs = $2
125
+ params.clear
126
+ (qs || '').split(/[&;] */n).each {|item|
127
+ k, v = item.split('=', 2)
128
+ params[k] = v
129
+ }
130
+ puts "#{io.object_id}: serve #{pi} #{params.inspect}" if $debug
131
+ code, h, body = serve @tra_dir, pi, params
132
+ h.each {|k, v| io.puts "#{k}: #{v}"}
133
+ io.puts
134
+ body.each {|l|
135
+ if l =~ /\A\./
136
+ io.puts ".#{l}"
137
+ else
138
+ io.puts l
139
+ end
140
+ }
141
+ io.puts "."
142
+ end
143
+ end
144
+ rescue Exception
145
+ Log.error "ERROR: #{$!}: #{$@.inspect}"
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ def optparse opts
152
+ op = OptionParser.new
153
+ op.on('--debug') {$debug = true; STDOUT.sync = true}
154
+ op.on('-c', '--config-path=PATH') {|arg| opts[:config_path] = arg}
155
+ op.on('-d', '--daemonize') {opts[:daemonize] = true}
156
+ op.on('-b', '--bind-address=ADDRESS') {|arg| opts[:bind_address] = arg}
157
+ op.on('-p', '--port=PORT', Integer) {|arg| opts[:port] = arg}
158
+ end
159
+
160
+ if __FILE__ == $0
161
+ require 'socket'
162
+ require 'optparse'
163
+ require 'gri/q'
164
+ require 'gri/config'
165
+ require 'gri/log'
166
+ require 'gri/util_daemon'
167
+ new.run
168
+ end
169
+ end
170
+ end