sitehub 0.4.3 → 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +31 -0
- data/.gitignore +2 -1
- data/.reek +41 -0
- data/.simplecov +7 -0
- data/Gemfile.lock +61 -33
- data/README.md +4 -0
- data/Rakefile +1 -1
- data/circle.yml +1 -1
- data/lib/sitehub/builder.rb +19 -36
- data/lib/sitehub/collection/split_route_collection.rb +18 -13
- data/lib/sitehub/collection/split_route_collection/split.rb +6 -4
- data/lib/sitehub/constants.rb +2 -1
- data/lib/sitehub/constants/http_header_keys.rb +2 -0
- data/lib/sitehub/constants/rack_http_header_keys.rb +2 -0
- data/lib/sitehub/cookie.rb +4 -13
- data/lib/sitehub/cookie/attribute.rb +10 -9
- data/lib/sitehub/cookie/flag.rb +5 -8
- data/lib/sitehub/cookie_rewriting.rb +12 -5
- data/lib/sitehub/downstream_client.rb +37 -0
- data/lib/sitehub/equality.rb +28 -0
- data/lib/sitehub/forward_proxy.rb +19 -62
- data/lib/sitehub/forward_proxy_builder.rb +70 -49
- data/lib/sitehub/getter_setter_methods.rb +21 -0
- data/lib/sitehub/http_headers.rb +45 -48
- data/lib/sitehub/location_rewriter.rb +29 -0
- data/lib/sitehub/location_rewriters.rb +23 -0
- data/lib/sitehub/memoize.rb +25 -0
- data/lib/sitehub/middleware.rb +16 -6
- data/lib/sitehub/middleware/error_handling.rb +20 -0
- data/lib/sitehub/middleware/forward_proxies.rb +54 -0
- data/lib/sitehub/{logging.rb → middleware/logging.rb} +0 -0
- data/lib/sitehub/middleware/logging/access_logger.rb +36 -0
- data/lib/sitehub/middleware/logging/error_logger.rb +38 -0
- data/lib/sitehub/middleware/logging/log_entry.rb +16 -0
- data/lib/sitehub/middleware/logging/log_stash.rb +12 -0
- data/lib/sitehub/middleware/logging/log_wrapper.rb +24 -0
- data/lib/sitehub/middleware/logging/request_log.rb +74 -0
- data/lib/sitehub/middleware/reverse_proxy.rb +37 -0
- data/lib/sitehub/middleware/transaction_id.rb +18 -0
- data/lib/sitehub/nil_location_rewriter.rb +7 -0
- data/lib/sitehub/nil_proxy.rb +11 -0
- data/lib/sitehub/request.rb +101 -0
- data/lib/sitehub/request_mapping.rb +16 -18
- data/lib/sitehub/resolver.rb +1 -1
- data/lib/sitehub/response.rb +10 -0
- data/lib/sitehub/string_utils.rb +13 -0
- data/lib/sitehub/version.rb +1 -1
- data/sitehub.gemspec +4 -1
- data/spec/equality_spec.rb +32 -0
- data/spec/sitehub/builder_spec.rb +29 -22
- data/spec/sitehub/collection/route_collection_spec.rb +15 -14
- data/spec/sitehub/collection/split_route_collection/split_spec.rb +26 -0
- data/spec/sitehub/collection/split_route_collection_spec.rb +15 -3
- data/spec/sitehub/cookie/flag_spec.rb +1 -1
- data/spec/sitehub/cookie_rewriting_spec.rb +6 -10
- data/spec/sitehub/downstream_client_spec.rb +72 -0
- data/spec/sitehub/equality_spec.rb +32 -0
- data/spec/sitehub/forward_proxy_builder_spec.rb +92 -55
- data/spec/sitehub/forward_proxy_spec.rb +29 -97
- data/spec/sitehub/http_headers_spec.rb +32 -52
- data/spec/sitehub/integration_spec.rb +1 -1
- data/spec/sitehub/location_rewriter_spec.rb +46 -0
- data/spec/sitehub/{path_directives_spec.rb → location_rewriters_spec.rb} +8 -8
- data/spec/sitehub/memoize_spec.rb +56 -0
- data/spec/sitehub/middleware/error_handling_spec.rb +34 -0
- data/spec/sitehub/middleware/forward_proxies_spec.rb +105 -0
- data/spec/sitehub/middleware/logging/access_logger_spec.rb +51 -0
- data/spec/sitehub/middleware/logging/error_logger_spec.rb +84 -0
- data/spec/sitehub/middleware/logging/log_entry_spec.rb +33 -0
- data/spec/sitehub/middleware/logging/log_stash_spec.rb +21 -0
- data/spec/sitehub/middleware/logging/log_wrapper_spec.rb +31 -0
- data/spec/sitehub/middleware/logging/request_log_spec.rb +108 -0
- data/spec/sitehub/middleware/reverse_proxy_spec.rb +113 -0
- data/spec/sitehub/middleware/transaction_id_spec.rb +30 -0
- data/spec/sitehub/middleware_spec.rb +23 -13
- data/spec/sitehub/nil_location_rewriter_spec.rb +10 -0
- data/spec/sitehub/nil_proxy_spec.rb +14 -0
- data/spec/sitehub/request_mapping_spec.rb +21 -23
- data/spec/sitehub/request_spec.rb +228 -0
- data/spec/sitehub/resolver_spec.rb +2 -5
- data/spec/sitehub/response_spec.rb +30 -0
- data/spec/spec_helper.rb +12 -6
- data/spec/support/async/middleware.rb +1 -0
- data/spec/support/patch/rack/response.rb +7 -5
- data/spec/support/shared_contexts.rb +3 -0
- data/spec/support/shared_contexts/http_proxy_rules_context.rb +36 -0
- data/spec/support/shared_contexts/middleware_context.rb +6 -6
- data/spec/support/shared_contexts/module_spec_context.rb +7 -0
- data/spec/support/shared_contexts/rack_request_context.rb +18 -0
- data/spec/support/shared_contexts/rack_test_context.rb +0 -1
- data/spec/support/shared_examples.rb +3 -0
- data/spec/support/shared_examples/memoized_helpers.rb +7 -0
- data/spec/support/shared_examples/prohibited_http_header_filter.rb +16 -0
- data/spec/support/silent_warnings.rb +1 -1
- data/tasks/code_quality.rake +6 -0
- metadata +99 -29
- data/lib/sitehub/forward_proxies.rb +0 -49
- data/lib/sitehub/logging/access_logger.rb +0 -78
- data/lib/sitehub/logging/error_logger.rb +0 -36
- data/lib/sitehub/logging/log_entry.rb +0 -15
- data/lib/sitehub/logging/log_stash.rb +0 -10
- data/lib/sitehub/logging/log_wrapper.rb +0 -23
- data/lib/sitehub/path_directive.rb +0 -32
- data/lib/sitehub/path_directives.rb +0 -22
- data/lib/sitehub/reverse_proxy.rb +0 -57
- data/lib/sitehub/string_sanitiser.rb +0 -7
- data/lib/sitehub/transaction_id.rb +0 -16
- data/spec/sitehub/error_handling_spec.rb +0 -20
- data/spec/sitehub/forward_proxies_spec.rb +0 -103
- data/spec/sitehub/logging/access_logger_spec.rb +0 -128
- data/spec/sitehub/logging/error_logger_spec.rb +0 -78
- data/spec/sitehub/logging/log_entry_spec.rb +0 -31
- data/spec/sitehub/logging/log_stash_spec.rb +0 -19
- data/spec/sitehub/logging/log_wrapper_spec.rb +0 -29
- data/spec/sitehub/path_directive_spec.rb +0 -47
- data/spec/sitehub/reverse_proxy_spec.rb +0 -111
- data/spec/sitehub/transaction_id_spec.rb +0 -28
- data/spec/support/async/response_handler.rb +0 -16
- data/spec/support/shared_contexts/async_context.rb +0 -14
@@ -0,0 +1,21 @@
|
|
1
|
+
class SiteHub
|
2
|
+
module GetterSetterMethods
|
3
|
+
def getter_setters(*method_names)
|
4
|
+
method_names.each do |method_name|
|
5
|
+
getter_setter method_name.to_sym
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def getter_setter(method_name, default = nil)
|
10
|
+
define_method method_name do |arg = nil|
|
11
|
+
attribute_name = "@#{method_name}"
|
12
|
+
if arg
|
13
|
+
instance_variable_set(attribute_name, arg)
|
14
|
+
self
|
15
|
+
else
|
16
|
+
instance_variable_get(attribute_name) || default
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/sitehub/http_headers.rb
CHANGED
@@ -1,73 +1,70 @@
|
|
1
|
-
require 'sitehub/constants'
|
2
1
|
class SiteHub
|
3
|
-
|
4
|
-
include Constants::HttpHeaderKeys
|
5
|
-
include Constants
|
6
|
-
|
7
|
-
HTTP_OR_SSL_PORT = /:80(?!\d+)|:443/
|
2
|
+
class HttpHeaders < Hash
|
8
3
|
HTTP_PREFIX = /^HTTP_/
|
9
4
|
RACK_HTTP_HEADER_ID = /#{HTTP_PREFIX.source}[A-Z_]+$/
|
10
|
-
COMMAND_FOLLOWED_BY_SPACES = /,\s+/
|
11
|
-
|
12
|
-
SHOULD_NOT_TRANSFER = [PROXY_CONNECTION].freeze
|
13
5
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
TE,
|
19
|
-
TRAILERS,
|
20
|
-
TRANSFER_ENCODING,
|
21
|
-
CONTENT_ENCODING].freeze
|
6
|
+
class << self
|
7
|
+
def from_rack_env(env)
|
8
|
+
new(format_keys(remove_rack_specific_headers(env.dup)))
|
9
|
+
end
|
22
10
|
|
23
|
-
|
24
|
-
f ? f.split(COMMAND_FOLLOWED_BY_SPACES).collect(&:downcase) : []
|
25
|
-
end
|
11
|
+
private
|
26
12
|
|
27
|
-
|
28
|
-
|
13
|
+
def remove_rack_specific_headers(env)
|
14
|
+
env.reject do |key, value|
|
15
|
+
!Constants::RackHttpHeaderKeys::HTTP_HEADER_FILTER_EXCEPTIONS.include?(key.to_s.upcase) &&
|
16
|
+
(!RACK_HTTP_HEADER_ID.match(key) || !value)
|
17
|
+
end
|
18
|
+
end
|
29
19
|
|
30
|
-
|
31
|
-
|
32
|
-
key =
|
33
|
-
|
34
|
-
sanitised_headers[key] = value
|
20
|
+
def format_keys(env)
|
21
|
+
env.each_with_object({}) do |key_value, hash|
|
22
|
+
key, value = *key_value
|
23
|
+
hash[header_name(key)] = value
|
35
24
|
end
|
25
|
+
end
|
36
26
|
|
37
|
-
|
27
|
+
def header_name(name)
|
28
|
+
name.sub(HTTP_PREFIX, EMPTY_STRING).downcase.gsub(UNDERSCORE, HYPHEN)
|
38
29
|
end
|
39
30
|
end
|
40
31
|
|
41
|
-
|
42
|
-
|
32
|
+
include Constants, Constants::HttpHeaderKeys
|
33
|
+
|
34
|
+
EXCLUDED_HEADERS = [CONNECTION_HEADER,
|
35
|
+
KEEP_ALIVE,
|
36
|
+
PROXY_CONNECTION,
|
37
|
+
PROXY_AUTHENTICATE,
|
38
|
+
PROXY_AUTHORIZATION,
|
39
|
+
TE,
|
40
|
+
TRAILERS,
|
41
|
+
TRANSFER_ENCODING,
|
42
|
+
CONTENT_ENCODING,
|
43
|
+
UPGRADE].freeze
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
hash
|
45
|
+
def initialize(env)
|
46
|
+
env.each do |key, value|
|
47
|
+
self[key.to_s.downcase] = value
|
48
48
|
end
|
49
49
|
|
50
|
-
|
51
|
-
headers.merge!(X_FORWARDED_FOR_HEADER => x_forwarded_for_value(headers, remote_address))
|
50
|
+
filter_prohibited_headers
|
52
51
|
end
|
53
52
|
|
54
|
-
|
55
|
-
(forwarded_address_list(headers) << remote_address).join(COMMA_WITH_SPACE)
|
56
|
-
end
|
53
|
+
private
|
57
54
|
|
58
|
-
def
|
59
|
-
|
55
|
+
def filter_prohibited_headers
|
56
|
+
remove_headers(hop_by_hop_headers.concat(EXCLUDED_HEADERS))
|
60
57
|
end
|
61
58
|
|
62
|
-
def
|
63
|
-
|
64
|
-
|
65
|
-
(!RACK_HTTP_HEADER_ID.match(k) || v.nil?)
|
66
|
-
end
|
59
|
+
def hop_by_hop_headers
|
60
|
+
field = self[CONNECTION_HEADER] || EMPTY_STRING
|
61
|
+
field.split(COMMA).collect(&:downcase)
|
67
62
|
end
|
68
63
|
|
69
|
-
def
|
70
|
-
|
64
|
+
def remove_headers(excluded)
|
65
|
+
reject! do |key, _value|
|
66
|
+
excluded.member?(key)
|
67
|
+
end
|
71
68
|
end
|
72
69
|
end
|
73
70
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'sitehub/equality'
|
2
|
+
class SiteHub
|
3
|
+
class LocationRewriter
|
4
|
+
include Equality
|
5
|
+
|
6
|
+
attr_reader :matcher, :path_template
|
7
|
+
|
8
|
+
def initialize(matcher, path_template)
|
9
|
+
@matcher = matcher
|
10
|
+
@path_template = path_template
|
11
|
+
end
|
12
|
+
|
13
|
+
def match?(url)
|
14
|
+
matcher.match(url).is_a?(MatchData)
|
15
|
+
end
|
16
|
+
|
17
|
+
def apply(downstream_url, source_url)
|
18
|
+
url_components = matcher.match(downstream_url).captures
|
19
|
+
|
20
|
+
path = path_template.dup.tap do |template|
|
21
|
+
url_components.each.with_index(1) do |component, index|
|
22
|
+
template.gsub!(RequestMapping::CAPTURE_GROUP_REFERENCE % index, component)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
"#{source_url[RequestMapping::BASE_URL_MATCHER]}#{path}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'sitehub/location_rewriter'
|
2
|
+
require 'sitehub/nil_location_rewriter'
|
3
|
+
class SiteHub
|
4
|
+
class LocationRewriters < Array
|
5
|
+
DEFAULT = NilLocationRewriter.new
|
6
|
+
|
7
|
+
def initialize(map = {})
|
8
|
+
enriched = map.collect do |pattern, path_template|
|
9
|
+
matcher = pattern.is_a?(Regexp) ? pattern : /#{pattern}/
|
10
|
+
LocationRewriter.new(matcher, path_template)
|
11
|
+
end
|
12
|
+
|
13
|
+
super enriched
|
14
|
+
end
|
15
|
+
|
16
|
+
def find(url)
|
17
|
+
result = super() do |directive|
|
18
|
+
directive.match?(url)
|
19
|
+
end
|
20
|
+
result || DEFAULT
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class SiteHub
|
2
|
+
module Memoize
|
3
|
+
def memoize(*methods)
|
4
|
+
methods.each do |method|
|
5
|
+
method_alias = "_#{method}"
|
6
|
+
alias_method method_alias, method
|
7
|
+
|
8
|
+
define_memoized_method(method, method_alias)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def define_memoized_method(method, method_alias)
|
15
|
+
define_method(method) do |*args, &block|
|
16
|
+
attribute = "@#{method}".gsub('?', 'question_mark')
|
17
|
+
return instance_variable_get(attribute) if instance_variable_defined? attribute
|
18
|
+
|
19
|
+
send(method_alias, *args, &block).tap do |result|
|
20
|
+
instance_variable_set(attribute, result)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/sitehub/middleware.rb
CHANGED
@@ -1,20 +1,30 @@
|
|
1
|
+
$LOAD_PATH.unshift(__dir__)
|
2
|
+
require 'middleware/logging'
|
3
|
+
require 'middleware/transaction_id'
|
4
|
+
require 'middleware/error_handling'
|
5
|
+
require 'middleware/forward_proxies'
|
6
|
+
require 'middleware/reverse_proxy'
|
7
|
+
require 'rack/ssl-enforcer'
|
8
|
+
require 'rack/fiber_pool'
|
9
|
+
|
1
10
|
class SiteHub
|
2
11
|
module Middleware
|
3
12
|
def middlewares
|
4
13
|
@middleware ||= []
|
5
14
|
end
|
6
15
|
|
16
|
+
def middleware?
|
17
|
+
!middlewares.empty?
|
18
|
+
end
|
19
|
+
|
7
20
|
def use(middleware_clazz, *args, &block)
|
8
|
-
middlewares << [middleware_clazz, args, block
|
21
|
+
middlewares << [middleware_clazz, args, block]
|
9
22
|
end
|
10
23
|
|
11
24
|
def apply_middleware(forward_proxy)
|
12
25
|
middlewares.reverse.inject(forward_proxy) do |app, middleware_def|
|
13
|
-
middleware = middleware_def
|
14
|
-
args
|
15
|
-
block = middleware_def[2] || proc {}
|
16
|
-
|
17
|
-
middleware.new(app, *args, &block)
|
26
|
+
middleware, args, block = *middleware_def
|
27
|
+
middleware.new(app, *args, &(block || proc {}))
|
18
28
|
end
|
19
29
|
end
|
20
30
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class SiteHub
|
2
|
+
module Middleware
|
3
|
+
class ErrorHandling
|
4
|
+
ERROR_RESPONSE = Rack::Response.new(['error'], 500, {})
|
5
|
+
|
6
|
+
attr_reader :app
|
7
|
+
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
@app.call env
|
14
|
+
rescue StandardError => exception
|
15
|
+
env[ERRORS] << exception.message
|
16
|
+
ERROR_RESPONSE.dup
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'sitehub/constants'
|
2
|
+
require 'sitehub/nil_proxy'
|
3
|
+
require 'rack/request'
|
4
|
+
require 'rack/response'
|
5
|
+
require 'rack/utils'
|
6
|
+
require 'em-http'
|
7
|
+
|
8
|
+
class SiteHub
|
9
|
+
module Middleware
|
10
|
+
class ForwardProxies
|
11
|
+
NIL_PROXY = NilProxy.new
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
source_request = Rack::Request.new(env)
|
15
|
+
|
16
|
+
forward_proxy = mapped_proxy(path: source_request.path, request: source_request)
|
17
|
+
|
18
|
+
forward_proxy.call(env)
|
19
|
+
end
|
20
|
+
|
21
|
+
def init
|
22
|
+
forward_proxies.values.each(&:build)
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def <<(route)
|
27
|
+
forward_proxies[route.mapped_path] = route
|
28
|
+
end
|
29
|
+
|
30
|
+
def mapped_proxy(path:, request:)
|
31
|
+
forward_proxies[mapping(path)].resolve(id: request.cookies[RECORDED_ROUTES_COOKIE], env: request.env)
|
32
|
+
end
|
33
|
+
|
34
|
+
def mapping(path)
|
35
|
+
forward_proxies.keys.find do |key|
|
36
|
+
case key
|
37
|
+
when Regexp
|
38
|
+
key.match(path)
|
39
|
+
else
|
40
|
+
path == key
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def forward_proxies
|
46
|
+
@forward_proxies ||= begin
|
47
|
+
{}.tap do |hash|
|
48
|
+
hash.default = NIL_PROXY
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
File without changes
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'rack/commonlogger'
|
3
|
+
require_relative 'log_wrapper'
|
4
|
+
require 'sitehub/constants'
|
5
|
+
require 'sitehub/middleware/logging/request_log'
|
6
|
+
require 'sitehub/response'
|
7
|
+
|
8
|
+
class SiteHub
|
9
|
+
module Middleware
|
10
|
+
module Logging
|
11
|
+
class AccessLogger
|
12
|
+
attr_reader :logger, :start_time
|
13
|
+
|
14
|
+
include Constants
|
15
|
+
|
16
|
+
FORMAT = %(%s - %s [%s] transaction_id:%s: "%s %s%s => %s %s" %d %s %0.4f\n).freeze
|
17
|
+
ZERO_STRING = '0'.freeze
|
18
|
+
STATUS_RANGE = 0..3
|
19
|
+
|
20
|
+
def initialize(app, logger = ::Logger.new(STDOUT))
|
21
|
+
@app = app
|
22
|
+
@logger = LogWrapper.new(logger)
|
23
|
+
end
|
24
|
+
|
25
|
+
def call(env)
|
26
|
+
request = env[REQUEST] = Request.new(env: env)
|
27
|
+
@app.call(env).tap do |response|
|
28
|
+
status, headers, body = response.to_a
|
29
|
+
response = Response.new(body, status, headers)
|
30
|
+
logger.write(RequestLog.new(request, response).to_s)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'sitehub/constants'
|
3
|
+
require_relative 'log_wrapper'
|
4
|
+
require_relative 'log_stash'
|
5
|
+
class SiteHub
|
6
|
+
module Middleware
|
7
|
+
module Logging
|
8
|
+
class ErrorLogger
|
9
|
+
include Constants
|
10
|
+
LOG_TEMPLATE = '[%s] ERROR: %s - %s'.freeze
|
11
|
+
|
12
|
+
attr_reader :logger
|
13
|
+
|
14
|
+
def initialize(app, logger = Logger.new(STDERR))
|
15
|
+
@app = app
|
16
|
+
@logger = LogWrapper.new(logger)
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env)
|
20
|
+
errors = env[ERRORS] ||= LogStash.new
|
21
|
+
@app.call(env).tap do
|
22
|
+
unless errors.empty?
|
23
|
+
messages = errors.collect do |log_entry|
|
24
|
+
log_message(error: log_entry.message, transaction_id: env[RackHttpHeaderKeys::TRANSACTION_ID])
|
25
|
+
end
|
26
|
+
|
27
|
+
logger.write(messages.join(NEW_LINE))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def log_message(error:, transaction_id:)
|
33
|
+
format(LOG_TEMPLATE, Time.now.strftime(TIME_STAMP_FORMAT), transaction_id, error)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'sitehub/equality'
|
2
|
+
class SiteHub
|
3
|
+
module Middleware
|
4
|
+
module Logging
|
5
|
+
class LogEntry
|
6
|
+
include Equality
|
7
|
+
attr_reader :message, :time
|
8
|
+
|
9
|
+
def initialize(message, time = Time.now)
|
10
|
+
@message = message
|
11
|
+
@time = time
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|