right_support 1.4.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +94 -68
- data/lib/right_support.rb +1 -1
- data/lib/right_support/{config.rb → data.rb} +4 -6
- data/lib/right_support/data/uuid.rb +175 -0
- data/lib/right_support/log.rb +0 -1
- data/lib/right_support/log/system_logger.rb +1 -1
- data/lib/right_support/net.rb +1 -1
- data/lib/right_support/net/http_client.rb +118 -32
- data/lib/right_support/net/{balancing.rb → lb.rb} +4 -4
- data/lib/right_support/net/{balancing → lb}/health_check.rb +1 -1
- data/lib/right_support/net/{balancing → lb}/round_robin.rb +1 -1
- data/lib/right_support/net/{balancing/sticky_policy.rb → lb/sticky.rb} +2 -3
- data/lib/right_support/net/request_balancer.rb +1 -1
- data/lib/right_support/rack.rb +2 -1
- data/lib/right_support/rack/{custom_logger.rb → log_setter.rb} +21 -33
- data/lib/right_support/rack/request_logger.rb +47 -21
- data/lib/right_support/{config/recursive_true_class.rb → rack/request_tracker.rb} +33 -33
- data/lib/right_support/ruby/object_extensions.rb +0 -22
- data/lib/right_support/stats/helpers.rb +36 -65
- data/lib/right_support/validation/ssh.rb +2 -2
- data/right_support.gemspec +3 -3
- metadata +15 -16
- data/lib/right_support/config/feature_set.rb +0 -95
- data/lib/right_support/config/yaml_config.rb +0 -62
- data/lib/right_support/log/tag_logger.rb +0 -72
@@ -24,10 +24,10 @@
|
|
24
24
|
# A namespace to hold load-balancing policies to be used with RequestBalancer
|
25
25
|
# and potentially other networking classes.
|
26
26
|
#
|
27
|
-
module RightSupport::Net::
|
27
|
+
module RightSupport::Net::LB
|
28
28
|
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
require 'right_support/net/lb/health_check'
|
32
|
+
require 'right_support/net/lb/round_robin'
|
33
|
+
require 'right_support/net/lb/sticky'
|
@@ -22,7 +22,7 @@
|
|
22
22
|
|
23
23
|
require 'set'
|
24
24
|
|
25
|
-
module RightSupport::Net::
|
25
|
+
module RightSupport::Net::LB
|
26
26
|
|
27
27
|
# TODO refactor this class. We store too much unstructured data about EPs; should have a simple
|
28
28
|
# class representing EP state, and then perhaps move what logic remains into the HealthCheck class
|
@@ -20,7 +20,7 @@
|
|
20
20
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
|
23
|
-
module RightSupport::Net::
|
23
|
+
module RightSupport::Net::LB
|
24
24
|
class RoundRobin
|
25
25
|
|
26
26
|
def initialize(options ={})
|
@@ -20,8 +20,7 @@
|
|
20
20
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
|
23
|
-
module RightSupport::Net::
|
24
|
-
|
23
|
+
module RightSupport::Net::LB
|
25
24
|
# Implementation concepts: Create a policy that selects an endpoint and sticks with it.
|
26
25
|
#
|
27
26
|
# The policy should:
|
@@ -30,7 +29,7 @@ module RightSupport::Net::Balancing
|
|
30
29
|
# - re-iterate through each endpoint when it's endpoint loses validity;
|
31
30
|
# - return an Exception if it performs a complete iteration though each endpoint and finds none valid;
|
32
31
|
|
33
|
-
class
|
32
|
+
class Sticky
|
34
33
|
|
35
34
|
def initialize(options = {})
|
36
35
|
@health_check = options.delete(:health_check)
|
@@ -108,7 +108,7 @@ module RightSupport::Net
|
|
108
108
|
raise ArgumentError, "Must specify at least one endpoint"
|
109
109
|
end
|
110
110
|
|
111
|
-
@options[:policy] ||= RightSupport::Net::
|
111
|
+
@options[:policy] ||= RightSupport::Net::LB::RoundRobin
|
112
112
|
@policy = @options[:policy]
|
113
113
|
@policy = @policy.new(options) if @policy.is_a?(Class)
|
114
114
|
|
data/lib/right_support/rack.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c)
|
2
|
+
# Copyright (c) 2012 RightScale Inc
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -23,11 +23,15 @@
|
|
23
23
|
require 'logger'
|
24
24
|
|
25
25
|
module RightSupport::Rack
|
26
|
-
# A Rack middleware that
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
|
26
|
+
# A Rack middleware that logs information about every HTTP request received and
|
27
|
+
# every exception raised while processing a request.
|
28
|
+
#
|
29
|
+
# The middleware can be configured to use its own logger, but defaults to using
|
30
|
+
# env['rack.logger'] for logging if it is present. If 'rack.logger' is not set,
|
31
|
+
# this middleware will set it before calling the next middleware. Therefore,
|
32
|
+
# RequestLogger can be used standalone to fulfill all logging needs, or combined
|
33
|
+
# with Rack::Logger or another middleware that provides logging services.
|
34
|
+
class LogSetter
|
31
35
|
# Initialize an instance of the middleware. For backward compatibility, the order of the
|
32
36
|
# logger and level parameters can be switched.
|
33
37
|
#
|
@@ -36,22 +40,9 @@ module RightSupport::Rack
|
|
36
40
|
# logger(Logger):: (optional) the Logger object to use, defaults to a STDERR logger
|
37
41
|
# level(Integer):: (optional) a Logger level-constant (INFO, ERROR) to set the logger to
|
38
42
|
#
|
39
|
-
def initialize(app,
|
40
|
-
if arg1.is_a?(Integer)
|
41
|
-
level = arg1
|
42
|
-
elsif arg1.is_a?(Logger)
|
43
|
-
logger = arg1
|
44
|
-
end
|
45
|
-
|
46
|
-
if arg2.is_a?(Integer)
|
47
|
-
level = arg2
|
48
|
-
elsif arg2.is_a?(Logger)
|
49
|
-
logger = arg2
|
50
|
-
end
|
51
|
-
|
43
|
+
def initialize(app, options={})
|
52
44
|
@app = app
|
53
|
-
@logger = logger
|
54
|
-
@level = level
|
45
|
+
@logger = options[:logger]
|
55
46
|
end
|
56
47
|
|
57
48
|
# Add a logger to the Rack environment and call the next middleware.
|
@@ -62,18 +53,15 @@ module RightSupport::Rack
|
|
62
53
|
# === Return
|
63
54
|
# always returns whatever value is returned by the next layer of middleware
|
64
55
|
def call(env)
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
if @level
|
70
|
-
old_level = @logger.level
|
71
|
-
@logger.level = @level
|
56
|
+
if @logger
|
57
|
+
logger = @logger
|
58
|
+
elsif env['rack.logger']
|
59
|
+
logger = env['rack.logger']
|
72
60
|
end
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
return
|
61
|
+
|
62
|
+
env['rack.logger'] ||= logger
|
63
|
+
|
64
|
+
return @app.call(env)
|
77
65
|
end
|
78
|
-
|
66
|
+
end
|
79
67
|
end
|
@@ -32,17 +32,13 @@ module RightSupport::Rack
|
|
32
32
|
# RequestLogger can be used standalone to fulfill all logging needs, or combined
|
33
33
|
# with Rack::Logger or another middleware that provides logging services.
|
34
34
|
class RequestLogger
|
35
|
-
# Initialize an instance of the middleware.
|
36
|
-
# logger and level parameters can be switched.
|
35
|
+
# Initialize an instance of the middleware.
|
37
36
|
#
|
38
37
|
# === Parameters
|
39
38
|
# app(Object):: the inner application or middleware layer; must respond to #call
|
40
|
-
# logger(Logger):: (optional) the Logger object to use, defaults to a STDERR logger
|
41
|
-
# level(Integer):: (optional) a Logger level-constant (INFO, ERROR) to set the logger to
|
42
39
|
#
|
43
|
-
def initialize(app
|
44
|
-
@app
|
45
|
-
@logger = options[:logger]
|
40
|
+
def initialize(app)
|
41
|
+
@app = app
|
46
42
|
end
|
47
43
|
|
48
44
|
# Add a logger to the Rack environment and call the next middleware.
|
@@ -53,17 +49,13 @@ module RightSupport::Rack
|
|
53
49
|
# === Return
|
54
50
|
# always returns whatever value is returned by the next layer of middleware
|
55
51
|
def call(env)
|
56
|
-
|
57
|
-
logger = @logger
|
58
|
-
elsif env['rack.logger']
|
59
|
-
logger = env['rack.logger']
|
60
|
-
end
|
61
|
-
|
62
|
-
env['rack.logger'] ||= logger
|
52
|
+
logger = env["rack.logger"]
|
63
53
|
|
64
54
|
began_at = Time.now
|
55
|
+
|
56
|
+
log_request_begin(logger, env)
|
65
57
|
status, header, body = @app.call(env)
|
66
|
-
|
58
|
+
log_request_end(logger, env, status, began_at)
|
67
59
|
log_exception(logger, env['sinatra.error']) if env['sinatra.error']
|
68
60
|
|
69
61
|
return [status, header, body]
|
@@ -74,10 +66,15 @@ module RightSupport::Rack
|
|
74
66
|
|
75
67
|
private
|
76
68
|
|
77
|
-
#
|
78
|
-
|
79
|
-
|
80
|
-
|
69
|
+
# Log beginning of request
|
70
|
+
#
|
71
|
+
# === Parameters
|
72
|
+
# logger(Object):: the Rack logger
|
73
|
+
# env(Hash):: the Rack environment
|
74
|
+
#
|
75
|
+
# === Return
|
76
|
+
# always returns true
|
77
|
+
def log_request_begin(logger, env)
|
81
78
|
# Assuming remote addresses are IPv4, make them all align to the same width
|
82
79
|
remote_addr = env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-"
|
83
80
|
remote_addr = remote_addr.ljust(15)
|
@@ -96,13 +93,42 @@ module RightSupport::Rack
|
|
96
93
|
env["PATH_INFO"],
|
97
94
|
query_info,
|
98
95
|
env["HTTP_VERSION"],
|
96
|
+
env["rack.request_uuid"] || ''
|
97
|
+
]
|
98
|
+
|
99
|
+
logger.info %Q{Begin: %s "%s %s%s %s" %s} % params
|
100
|
+
end
|
101
|
+
|
102
|
+
# Log end of request
|
103
|
+
#
|
104
|
+
# === Parameters
|
105
|
+
# logger(Object):: the Rack logger
|
106
|
+
# env(Hash):: the Rack environment
|
107
|
+
# status(Fixnum):: status of the Rack request
|
108
|
+
# began_at(Time):: time of the Rack request begging
|
109
|
+
#
|
110
|
+
# === Return
|
111
|
+
# always returns true
|
112
|
+
def log_request_end(logger, env, status, began_at)
|
113
|
+
duration = Time.now - began_at
|
114
|
+
|
115
|
+
params = [
|
99
116
|
status,
|
100
|
-
duration
|
117
|
+
duration,
|
118
|
+
env["rack.request_uuid"] || ''
|
101
119
|
]
|
102
120
|
|
103
|
-
logger.info %Q{
|
121
|
+
logger.info %Q{End: %d %0.3f %s} % params
|
104
122
|
end
|
105
123
|
|
124
|
+
# Log exception
|
125
|
+
#
|
126
|
+
# === Parameters
|
127
|
+
# logger(Object):: the Rack logger
|
128
|
+
# e(Exception):: Exception to be logged
|
129
|
+
#
|
130
|
+
# === Return
|
131
|
+
# always returns true
|
106
132
|
def log_exception(logger, e)
|
107
133
|
msg = ["#{e.class} - #{e.message}", *e.backtrace].join("\n")
|
108
134
|
logger.error(msg)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c)
|
2
|
+
# Copyright (c) 2011 RightScale Inc
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -20,44 +20,44 @@
|
|
20
20
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
|
23
|
-
module RightSupport::
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
def initialize
|
32
|
-
@value = true
|
33
|
-
end
|
34
|
-
|
35
|
-
def [](something)
|
36
|
-
self
|
37
|
-
end
|
38
|
-
|
39
|
-
# supporting standart boolean
|
40
|
-
# opeimplementation
|
41
|
-
def ==(other)
|
42
|
-
@value==other
|
43
|
-
end
|
23
|
+
module RightSupport::Rack
|
24
|
+
# TODO docs
|
25
|
+
class RequestTracker
|
26
|
+
REQUEST_LINEAGE_UUID_HEADER = "HTTP_X_REQUEST_LINEAGE_UUID".freeze
|
27
|
+
REQUEST_UUID_HEADER = "X-Request-Uuid".freeze
|
28
|
+
REQUEST_UUID_ENV_NAME = "rack.request_uuid".freeze
|
29
|
+
UUID_SEPARATOR = " ".freeze
|
44
30
|
|
45
|
-
|
46
|
-
|
31
|
+
# Make a new Request tracker.
|
32
|
+
#
|
33
|
+
# Tags the requset with a new request UUID
|
34
|
+
#
|
35
|
+
# === Parameters
|
36
|
+
# app(Rack client): application to run
|
37
|
+
def initialize(app)
|
38
|
+
@app = app
|
47
39
|
end
|
48
40
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
41
|
+
def call(env)
|
42
|
+
if env.has_key? REQUEST_LINEAGE_UUID_HEADER
|
43
|
+
request_uuid = env[REQUEST_LINEAGE_UUID_HEADER] + UUID_SEPARATOR +
|
44
|
+
generate_request_uuid
|
45
|
+
else
|
46
|
+
request_uuid = generate_request_uuid
|
47
|
+
end
|
52
48
|
|
53
|
-
|
54
|
-
|
55
|
-
|
49
|
+
env[REQUEST_UUID_ENV_NAME] = request_uuid
|
50
|
+
|
51
|
+
status, headers, body = @app.call(env)
|
56
52
|
|
57
|
-
|
58
|
-
|
53
|
+
headers[REQUEST_UUID_HEADER] = request_uuid
|
54
|
+
[status, headers,body]
|
59
55
|
end
|
60
56
|
|
57
|
+
|
58
|
+
def generate_request_uuid
|
59
|
+
::RightSupport::Data::UUID.generate
|
60
|
+
end
|
61
61
|
end
|
62
62
|
|
63
|
-
end
|
63
|
+
end
|
@@ -16,28 +16,6 @@ module RightSupport::Ruby
|
|
16
16
|
rescue LoadError => e
|
17
17
|
return false
|
18
18
|
end
|
19
|
-
|
20
|
-
# Attempt to require one or more source files; if the require succeeds (or
|
21
|
-
# if the files have already been successfully required), yield to the block.
|
22
|
-
#
|
23
|
-
# This method is useful to conditionally define code depending on the availability
|
24
|
-
# of gems or standard-library source files.
|
25
|
-
#
|
26
|
-
# === Parameters
|
27
|
-
# Forwards all parameters transparently through to Kernel#require.
|
28
|
-
#
|
29
|
-
# === Block
|
30
|
-
# The block will be called if the require succeeds (if it does not raise LoadError).
|
31
|
-
#
|
32
|
-
# === Return
|
33
|
-
# Preserves the return value of Kernel#require (generally either true or false).
|
34
|
-
def if_require_succeeds(*args)
|
35
|
-
result = require(*args)
|
36
|
-
yield if block_given?
|
37
|
-
return result
|
38
|
-
rescue LoadError => e
|
39
|
-
return false
|
40
|
-
end
|
41
19
|
end
|
42
20
|
end
|
43
21
|
|
@@ -33,6 +33,9 @@ module RightSupport
|
|
33
33
|
# Maximum characters in sub-stat value line
|
34
34
|
MAX_SUB_STAT_VALUE_WIDTH = 80
|
35
35
|
|
36
|
+
# Maximum characters displayed for exception message
|
37
|
+
MAX_EXCEPTION_MESSAGE_WIDTH = 60
|
38
|
+
|
36
39
|
# Separator between stat name and stat value
|
37
40
|
SEPARATOR = " : "
|
38
41
|
|
@@ -130,67 +133,37 @@ module RightSupport
|
|
130
133
|
end
|
131
134
|
end
|
132
135
|
|
133
|
-
# Wrap string by breaking it into lines at the specified
|
134
|
-
# Allow for presence of color encoding when measuring string length
|
136
|
+
# Wrap string by breaking it into lines at the specified separator
|
135
137
|
#
|
136
138
|
# === Parameters
|
137
139
|
# string(String):: String to be wrapped
|
138
|
-
# max_length(Integer
|
139
|
-
#
|
140
|
-
#
|
141
|
-
# indent(String):: Indentation for each line after first
|
142
|
-
# separators(Regexp):: Separators where string can wrap
|
140
|
+
# max_length(Integer):: Maximum length of a line excluding indentation
|
141
|
+
# indent(String):: Indentation for each line
|
142
|
+
# separator(String):: Separator at which to make line breaks
|
143
143
|
#
|
144
144
|
# === Return
|
145
|
-
# (String
|
146
|
-
def self.wrap(string, max_length, indent,
|
147
|
-
# Strip color encoding from string
|
148
|
-
strip = lambda { |string| string.gsub(/\e\[[0-9]*m/, "") }
|
149
|
-
|
150
|
-
# Split string at specified separators and return an array of arrays
|
151
|
-
# containing string segments and associated separator
|
152
|
-
split = lambda do |string, separators|
|
153
|
-
head, sep, tail = string.partition(separators)
|
154
|
-
if tail == ""
|
155
|
-
[[head, sep]]
|
156
|
-
else
|
157
|
-
[[head, sep]].concat(split.call(tail, separators))
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
145
|
+
# (String):: Multi-line string
|
146
|
+
def self.wrap(string, max_length, indent, separator)
|
161
147
|
all = []
|
162
|
-
line =
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
if (length + strip.call(str).size + last_sep.size + sep.size) > limit
|
168
|
-
all.push(line) unless line[0] == ""
|
169
|
-
line = [indent, last_sep = ""]
|
170
|
-
length = indent.size
|
171
|
-
limit = max_length.is_a?(Array) ? max_length[1] : max_length
|
148
|
+
line = ""
|
149
|
+
for l in string.split(separator)
|
150
|
+
if (line + l).length >= max_length
|
151
|
+
all.push(line)
|
152
|
+
line = ""
|
172
153
|
end
|
173
|
-
line
|
174
|
-
line[1] = last_sep = sep
|
175
|
-
length += strip.call(str).size
|
154
|
+
line += line == "" ? l : separator + l
|
176
155
|
end
|
177
|
-
all.push(line)
|
178
|
-
all[0..-2].inject("") { |a, (str, sep)| a + str + sep + "\n" } + all[-1][0]
|
156
|
+
all.push(line).join(separator + "\n" + indent)
|
179
157
|
end
|
180
158
|
|
181
159
|
# Format UTC time value
|
182
160
|
#
|
183
161
|
# === Parameters
|
184
162
|
# time(Integer):: Time in seconds in Unix-epoch to be formatted
|
185
|
-
# with_year(Boolean):: Whether to include year, defaults to false
|
186
163
|
#
|
187
164
|
# (String):: Formatted time string
|
188
|
-
def self.time_at(time
|
189
|
-
|
190
|
-
Time.at(time).strftime("%a %b %d %H:%M:%S %Y")
|
191
|
-
else
|
192
|
-
Time.at(time).strftime("%a %b %d %H:%M:%S")
|
193
|
-
end
|
165
|
+
def self.time_at(time)
|
166
|
+
Time.at(time).strftime("%a %b %d %H:%M:%S")
|
194
167
|
end
|
195
168
|
|
196
169
|
# Sort hash elements by key in ascending order into array of key/value pairs
|
@@ -219,9 +192,9 @@ module RightSupport
|
|
219
192
|
# Converts server statistics to a displayable format
|
220
193
|
#
|
221
194
|
# === Parameters
|
222
|
-
# stats(Hash):: Statistics with generic keys "name", "identity", "hostname", "
|
195
|
+
# stats(Hash):: Statistics with generic keys "name", "identity", "hostname", "service uptime",
|
223
196
|
# "machine uptime", "memory KB", "stat time", "last reset time", "version", and "broker" with
|
224
|
-
# the latter two and "
|
197
|
+
# the latter two and "machine uptime", "memory KB", "version", and "broker" being optional;
|
225
198
|
# any other keys ending with "stats" have an associated hash value that is displayed in sorted
|
226
199
|
# key order, unless "stats" is preceded by a non-blank, in which case that character is prepended
|
227
200
|
# to the key to drive the sort order
|
@@ -229,6 +202,7 @@ module RightSupport
|
|
229
202
|
# :name_width(Integer):: Maximum characters in displayed stat name
|
230
203
|
# :sub_name_width(Integer):: Maximum characters in displayed sub-stat name
|
231
204
|
# :sub_stat_value_width(Integer):: Maximum characters in displayed sub-stat value line
|
205
|
+
# :exception_message_width(Integer):: Maximum characters displayed for exception message
|
232
206
|
#
|
233
207
|
# === Return
|
234
208
|
# (String):: Display string
|
@@ -237,12 +211,9 @@ module RightSupport
|
|
237
211
|
|
238
212
|
str = stats["name"] ? sprintf("%-#{name_width}s#{SEPARATOR}%s\n", "name", stats["name"]) : ""
|
239
213
|
str += sprintf("%-#{name_width}s#{SEPARATOR}%s\n", "identity", stats["identity"]) +
|
240
|
-
sprintf("%-#{name_width}s#{SEPARATOR}%s\n", "hostname", stats["hostname"])
|
241
|
-
|
242
|
-
|
243
|
-
end
|
244
|
-
str += sprintf("%-#{name_width}s#{SEPARATOR}%s\n", "stat time", time_at(stats["stat time"], with_year = true)) +
|
245
|
-
sprintf("%-#{name_width}s#{SEPARATOR}%s\n", "last reset", time_at(stats["last reset time"], with_year = true)) +
|
214
|
+
sprintf("%-#{name_width}s#{SEPARATOR}%s\n", "hostname", stats["hostname"]) +
|
215
|
+
sprintf("%-#{name_width}s#{SEPARATOR}%s\n", "stat time", time_at(stats["stat time"])) +
|
216
|
+
sprintf("%-#{name_width}s#{SEPARATOR}%s\n", "last reset", time_at(stats["last reset time"])) +
|
246
217
|
sprintf("%-#{name_width}s#{SEPARATOR}%s\n", "service up", elapsed(stats["service uptime"]))
|
247
218
|
if stats.has_key?("machine uptime")
|
248
219
|
str += sprintf("%-#{name_width}s#{SEPARATOR}%s\n", "machine up", elapsed(stats["machine uptime"]))
|
@@ -285,6 +256,7 @@ module RightSupport
|
|
285
256
|
# :name_width(Integer):: Fixed width for left-justified name display
|
286
257
|
# :sub_name_width(Integer):: Maximum characters in displayed sub-stat name
|
287
258
|
# :sub_stat_value_width(Integer):: Maximum characters in displayed sub-stat value line
|
259
|
+
# :exception_message_width(Integer):: Maximum characters displayed for exception message
|
288
260
|
#
|
289
261
|
# === Return
|
290
262
|
# str(String):: Broker display with one line per broker plus exceptions
|
@@ -330,8 +302,7 @@ module RightSupport
|
|
330
302
|
str += if brokers["returns"].nil? || brokers["returns"].empty?
|
331
303
|
"none\n"
|
332
304
|
else
|
333
|
-
wrap(activity_str(brokers["returns"]),
|
334
|
-
sub_value_indent, /, /) + "\n"
|
305
|
+
wrap(activity_str(brokers["returns"]), sub_stat_value_width, sub_value_indent, ", ") + "\n"
|
335
306
|
end
|
336
307
|
end
|
337
308
|
|
@@ -354,6 +325,7 @@ module RightSupport
|
|
354
325
|
# :name_width(Integer):: Fixed width for left-justified name display
|
355
326
|
# :sub_name_width(Integer):: Maximum characters in displayed sub-stat name
|
356
327
|
# :sub_stat_value_width(Integer):: Maximum characters in displayed sub-stat value line
|
328
|
+
# :exception_message_width(Integer):: Maximum characters displayed for exception message
|
357
329
|
#
|
358
330
|
# === Return
|
359
331
|
# (String):: Single line display of stat
|
@@ -377,15 +349,13 @@ module RightSupport
|
|
377
349
|
if v.empty? || v["total"] == 0
|
378
350
|
"none"
|
379
351
|
elsif v["total"]
|
380
|
-
wrap(activity_str(v),
|
381
|
-
sub_value_indent, ", ")
|
352
|
+
wrap(activity_str(v), sub_stat_value_width, sub_value_indent, ", ")
|
382
353
|
elsif k =~ /last$/
|
383
354
|
last_activity_str(v)
|
384
355
|
elsif k == "exceptions"
|
385
356
|
exceptions_str(v, sub_value_indent, options)
|
386
357
|
else
|
387
|
-
wrap(hash_str(v),
|
388
|
-
sub_value_indent, /, /)
|
358
|
+
wrap(hash_str(v), sub_stat_value_width, sub_value_indent, ", ")
|
389
359
|
end
|
390
360
|
else
|
391
361
|
"#{v || "none"}"
|
@@ -457,19 +427,20 @@ module RightSupport
|
|
457
427
|
# "recent"(Array):: Most recent as a hash of "count", "type", "message", "when", and "where"
|
458
428
|
# indent(String):: Indentation for each line
|
459
429
|
# options(Hash):: Formatting options
|
460
|
-
# :
|
430
|
+
# :exception_message_width(Integer):: Maximum characters displayed for exception message
|
461
431
|
#
|
462
432
|
# === Return
|
463
433
|
# (String):: Exceptions in displayable format with line separators
|
464
434
|
def self.exceptions_str(exceptions, indent, options = {})
|
465
|
-
|
435
|
+
exception_message_width = options[:exception_message_width] || MAX_EXCEPTION_MESSAGE_WIDTH
|
466
436
|
indent2 = indent + (" " * 4)
|
467
437
|
exceptions.to_a.sort.map do |k, v|
|
468
438
|
sprintf("%s total: %d, most recent:\n", k, v["total"]) + v["recent"].reverse.map do |e|
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
439
|
+
message = e["message"]
|
440
|
+
if message && message.size > (exception_message_width - 3)
|
441
|
+
message = e["message"][0, exception_message_width - 3] + "..."
|
442
|
+
end
|
443
|
+
indent + "(#{e["count"]}) #{time_at(e["when"])} #{e["type"]}: #{message}\n" + indent2 + "#{e["where"]}"
|
473
444
|
end.join("\n")
|
474
445
|
end.join("\n" + indent)
|
475
446
|
end
|