chook 1.0.1.b2 → 1.1.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.
- checksums.yaml +5 -5
- data/CHANGES.md +21 -0
- data/README.md +243 -36
- data/bin/chook-server +29 -1
- data/data/chook.conf.example +104 -0
- data/data/sample_handlers/RestAPIOperation.rb +12 -8
- data/data/sample_handlers/SmartGroupComputerMembershipChange.rb +3 -6
- data/data/sample_jsons/SmartGroupComputerMembershipChange.json +3 -1
- data/data/sample_jsons/SmartGroupMobileDeviceMembershipChange.json +3 -1
- data/lib/chook/configuration.rb +20 -8
- data/lib/chook/event/handled_event.rb +15 -12
- data/lib/chook/event/handled_event/handlers.rb +136 -83
- data/lib/chook/event/handled_event_logger.rb +86 -0
- data/lib/chook/event_handling.rb +1 -0
- data/lib/chook/foundation.rb +2 -0
- data/lib/chook/procs.rb +17 -1
- data/lib/chook/server.rb +71 -74
- data/lib/chook/server/log.rb +215 -0
- data/lib/chook/server/public/css/chook.css +125 -0
- data/lib/chook/server/public/imgs/ChookLogoAlMcWhiggin.png +0 -0
- data/lib/chook/server/public/js/chook.js +127 -0
- data/lib/chook/server/public/js/logstream.js +101 -0
- data/lib/chook/server/routes.rb +45 -0
- data/lib/chook/server/routes/handle_webhook_event.rb +22 -3
- data/lib/chook/server/routes/handlers.rb +52 -0
- data/lib/chook/server/routes/home.rb +34 -1
- data/lib/chook/server/routes/log.rb +106 -0
- data/lib/chook/server/views/admin.haml +11 -0
- data/lib/chook/server/views/bak.haml +48 -0
- data/lib/chook/server/views/config.haml +15 -0
- data/lib/chook/server/views/handlers.haml +48 -0
- data/lib/chook/server/views/layout.haml +39 -0
- data/lib/chook/server/views/logstream.haml +32 -0
- data/lib/chook/server/views/sketch_admin +44 -0
- data/lib/chook/subject.rb +1 -2
- data/lib/chook/subject/smart_group.rb +6 -0
- data/lib/chook/version.rb +1 -1
- metadata +73 -18
@@ -0,0 +1,86 @@
|
|
1
|
+
### Copyright 2017 Pixar
|
2
|
+
|
3
|
+
###
|
4
|
+
### Licensed under the Apache License, Version 2.0 (the "Apache License")
|
5
|
+
### with the following modification; you may not use this file except in
|
6
|
+
### compliance with the Apache License and the following modification to it:
|
7
|
+
### Section 6. Trademarks. is deleted and replaced with:
|
8
|
+
###
|
9
|
+
### 6. Trademarks. This License does not grant permission to use the trade
|
10
|
+
### names, trademarks, service marks, or product names of the Licensor
|
11
|
+
### and its affiliates, except as required to comply with Section 4(c) of
|
12
|
+
### the License and to reproduce the content of the NOTICE file.
|
13
|
+
###
|
14
|
+
### You may obtain a copy of the Apache License at
|
15
|
+
###
|
16
|
+
### http://www.apache.org/licenses/LICENSE-2.0
|
17
|
+
###
|
18
|
+
### Unless required by applicable law or agreed to in writing, software
|
19
|
+
### distributed under the Apache License with the above modification is
|
20
|
+
### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
21
|
+
### KIND, either express or implied. See the Apache License for the specific
|
22
|
+
### language governing permissions and limitations under the Apache License.
|
23
|
+
###
|
24
|
+
###
|
25
|
+
|
26
|
+
module Chook
|
27
|
+
|
28
|
+
# a simple object embedded in a Handled Event that
|
29
|
+
# allows a standardize way to note event-related log entries
|
30
|
+
# with the event object_id.
|
31
|
+
#
|
32
|
+
# Every Handled Event has one of these instances exposed in it's
|
33
|
+
# #logger attribute, and usable from within 'internal' handlers
|
34
|
+
#
|
35
|
+
# Here's an example.
|
36
|
+
#
|
37
|
+
# Say you have a ComputerSmartGroupMembershipChanged event
|
38
|
+
#
|
39
|
+
# calling `event.logger.info "foobar"` will generate the log message:
|
40
|
+
#
|
41
|
+
# Event 1234567: foobar
|
42
|
+
#
|
43
|
+
class HandledEventLogger
|
44
|
+
|
45
|
+
def initialize(event)
|
46
|
+
@event = event
|
47
|
+
end
|
48
|
+
|
49
|
+
def event_message(msg)
|
50
|
+
"Event #{@event.object_id}: #{msg}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def debug(msg)
|
54
|
+
Chook::Server::Log.logger.debug event_message(msg)
|
55
|
+
end
|
56
|
+
|
57
|
+
def info(msg)
|
58
|
+
Chook::Server::Log.logger.info event_message(msg)
|
59
|
+
end
|
60
|
+
|
61
|
+
def warn(msg)
|
62
|
+
Chook::Server::Log.logger.warn event_message(msg)
|
63
|
+
end
|
64
|
+
|
65
|
+
def error(msg)
|
66
|
+
Chook::Server::Log.logger.error event_message(msg)
|
67
|
+
end
|
68
|
+
|
69
|
+
def fatal(msg)
|
70
|
+
Chook::Server::Log.logger.fatal event_message(msg)
|
71
|
+
end
|
72
|
+
|
73
|
+
def unknown(msg)
|
74
|
+
Chook::Server::Log.logger.unknown event_message(msg)
|
75
|
+
end
|
76
|
+
|
77
|
+
# log an exception - multiple log lines
|
78
|
+
# the first being the error message the rest being indented backtrace
|
79
|
+
def log_exception(exception)
|
80
|
+
error "#{exception.class}: #{exception}"
|
81
|
+
exception.backtrace.each { |l| error "..#{l}" }
|
82
|
+
end
|
83
|
+
|
84
|
+
end # class HandledEventLogger
|
85
|
+
|
86
|
+
end # module
|
data/lib/chook/event_handling.rb
CHANGED
data/lib/chook/foundation.rb
CHANGED
data/lib/chook/procs.rb
CHANGED
@@ -30,12 +30,28 @@ module Chook
|
|
30
30
|
module Procs
|
31
31
|
|
32
32
|
TRUE_RE = /^\s*(true|yes)\s*$/i
|
33
|
+
|
33
34
|
JSS_EPOCH_TO_TIME = proc { |val| Time.strptime val.to_s[0..-4], '%s' }
|
35
|
+
|
34
36
|
STRING_TO_BOOLEAN = proc { |val| val =~ TRUE_RE ? true : false }
|
37
|
+
|
35
38
|
STRING_TO_PATHNAME = proc { |val| Pathname.new val }
|
39
|
+
|
40
|
+
STRING_TO_LOG_LEVEL = proc do |level|
|
41
|
+
if (0..5).cover? level
|
42
|
+
level
|
43
|
+
else
|
44
|
+
lvl = Chook::Server::Log::LOG_LEVELS[level.to_sym]
|
45
|
+
lvl ? lvl : Logger::UNKNOWN
|
46
|
+
end # if..else
|
47
|
+
end
|
48
|
+
|
36
49
|
MOBILE_USERID = proc { |_device| '-1' }
|
50
|
+
|
37
51
|
PRODUCT = proc { |_device| nil }
|
38
|
-
|
52
|
+
|
53
|
+
ALWAYS_TRUE = proc { |_boolean| true }
|
54
|
+
|
39
55
|
COMPUTER_USERID = proc do |comp|
|
40
56
|
id = '-1' unless comp.groups_accounts[:local_accounts].find { |acct| acct[:name] == comp.username }
|
41
57
|
id.is_a?(Hash) ? id[:uid] : '-1'
|
data/lib/chook/server.rb
CHANGED
@@ -22,9 +22,14 @@
|
|
22
22
|
### language governing permissions and limitations under the Apache License.
|
23
23
|
###
|
24
24
|
###
|
25
|
-
|
25
|
+
|
26
26
|
require 'sinatra/base'
|
27
|
+
require 'sinatra/custom_logger'
|
28
|
+
# require 'haml'
|
27
29
|
require 'openssl'
|
30
|
+
require 'chook/event_handling'
|
31
|
+
require 'chook/server/log'
|
32
|
+
require 'chook/server/routes'
|
28
33
|
|
29
34
|
module Chook
|
30
35
|
|
@@ -32,90 +37,82 @@ module Chook
|
|
32
37
|
# the engine of your choice.
|
33
38
|
class Server < Sinatra::Base
|
34
39
|
|
35
|
-
|
36
|
-
|
40
|
+
DEFAULT_PORT = 80
|
41
|
+
DEFAULT_SSL_PORT = 443
|
42
|
+
DEFAULT_CONCURRENCY = true
|
37
43
|
|
38
|
-
|
39
|
-
|
40
|
-
@server_port = Chook::CONFIG.server_port || DEFAULT_PORT
|
44
|
+
# set defaults in config
|
45
|
+
Chook.config.port ||= Chook.config.use_ssl ? DEFAULT_SSL_PORT : DEFAULT_PORT
|
41
46
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
when :webrick
|
51
|
-
super
|
52
|
-
when :thin
|
53
|
-
if Chook::CONFIG.use_ssl
|
54
|
-
super do |server|
|
55
|
-
server.ssl = true
|
56
|
-
server.ssl_options = {
|
57
|
-
cert_chain_file: Chook::CONFIG.ssl_cert_path.to_s,
|
58
|
-
private_key_file: Chook::CONFIG.ssl_private_key_path.to_s,
|
59
|
-
verify_peer: false
|
60
|
-
}
|
61
|
-
end # super do
|
62
|
-
else
|
63
|
-
super
|
64
|
-
end # if use ssl
|
65
|
-
end # case
|
66
|
-
end # self.run
|
47
|
+
# can't use ||= here cuz nil and false have different meanings
|
48
|
+
Chook.config.concurrency = DEFAULT_CONCURRENCY if Chook.config.concurrency.nil?
|
49
|
+
|
50
|
+
# Run the server
|
51
|
+
###################################
|
52
|
+
def self.run!(log_level: nil)
|
53
|
+
log_level ||= Chook.config.log_level
|
54
|
+
@log_level = Chook::Procs::STRING_TO_LOG_LEVEL.call log_level
|
67
55
|
|
68
|
-
# Sinatra Settings
|
69
|
-
def self.chook_configure
|
70
56
|
configure do
|
71
|
-
set :
|
72
|
-
|
57
|
+
set :logger, Log.startup(@log_level)
|
58
|
+
set :server, :thin
|
73
59
|
set :bind, '0.0.0.0'
|
74
|
-
set :
|
75
|
-
set :
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
when :webrick
|
80
|
-
require 'webrick/https'
|
81
|
-
key = Chook::CONFIG.ssl_private_key_path.read
|
82
|
-
cert = Chook::CONFIG.ssl_cert_path.read
|
83
|
-
cert_name = Chook::CONFIG.ssl_cert_name
|
84
|
-
set :SSLEnable, true
|
85
|
-
set :SSLVerifyClient, OpenSSL::SSL::VERIFY_NONE
|
86
|
-
set :SSLPrivateKey, OpenSSL::PKey::RSA.new(key, ssl_key_password)
|
87
|
-
set :SSLCertificate, OpenSSL::X509::Certificate.new(cert)
|
88
|
-
set :SSLCertName, [['CN', cert_name]]
|
89
|
-
when :thin
|
90
|
-
true
|
91
|
-
end # case
|
92
|
-
end # if ssl
|
60
|
+
set :port, Chook.config.port
|
61
|
+
set :show_exceptions, :after_handler if development?
|
62
|
+
set :root, "#{File.dirname __FILE__}/server"
|
63
|
+
enable :static
|
64
|
+
enable :lock unless Chook.config.concurrency
|
93
65
|
end # configure
|
94
|
-
end # chook_configure
|
95
66
|
|
96
|
-
|
97
|
-
path = Chook::CONFIG.ssl_private_key_pw_path
|
98
|
-
raise 'No config setting for "ssl_private_key_pw_path"' unless path
|
99
|
-
file = Pathname.new path
|
67
|
+
Chook::HandledEvent::Handlers.load_handlers
|
100
68
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
69
|
+
if Chook.config.use_ssl
|
70
|
+
super do |server|
|
71
|
+
server.ssl = true
|
72
|
+
server.ssl_options = {
|
73
|
+
cert_chain_file: Chook.config.ssl_cert_path.to_s,
|
74
|
+
private_key_file: Chook.config.ssl_private_key_path.to_s,
|
75
|
+
verify_peer: false
|
76
|
+
}
|
77
|
+
end # super do
|
78
|
+
else
|
79
|
+
super
|
80
|
+
end # if use ssl
|
81
|
+
end # self.run
|
82
|
+
|
83
|
+
# Learn the client password, if we're using basic auth
|
84
|
+
###################################
|
85
|
+
def self.webhooks_user_pw
|
86
|
+
return @webhooks_user_pw if @webhooks_user_pw
|
87
|
+
return nil unless Chook.config.webhooks_user_pw
|
108
88
|
|
109
|
-
|
110
|
-
stat = file.stat
|
111
|
-
raise "Password file for '#{pw}' has insecure permissions, must be 0600." unless ('%o' % stat.mode).end_with? '0600'
|
89
|
+
setting = Chook.config.webhooks_user_pw
|
112
90
|
|
113
|
-
|
114
|
-
|
115
|
-
|
91
|
+
@webhooks_user_pw =
|
92
|
+
if setting.end_with? '|'
|
93
|
+
# if the path ends with a pipe, its a command that will
|
94
|
+
# return the desired password, so remove the pipe,
|
95
|
+
# execute it, and return stdout from it.
|
96
|
+
cmd = setting.chomp '|'
|
97
|
+
output = `#{cmd} 2>&1`.chomp
|
98
|
+
raise "Can't get webhooks user password: #{output}" unless $CHILD_STATUS.exitstatus.zero?
|
99
|
+
output
|
100
|
+
|
101
|
+
else
|
102
|
+
# otherwise its a file path, and read the pw from the contents
|
103
|
+
file = Pathname.new setting
|
104
|
+
return nil unless file.file?
|
105
|
+
stat = file.stat
|
106
|
+
mode = format('%o', stat.mode)
|
107
|
+
raise 'Password file for webhooks user has insecure mode, must be 0600.' unless mode.end_with?('0600')
|
108
|
+
raise "Password file for webhooks user has insecure owner, must be owned by UID #{Process.euid}." unless stat.owned?
|
109
|
+
|
110
|
+
# chomping an empty string removes all trailing \n's and \r\n's
|
111
|
+
file.read.chomp('')
|
112
|
+
|
113
|
+
end # if else
|
114
|
+
end # self.webhooks_user_pw
|
116
115
|
|
117
116
|
end # class server
|
118
117
|
|
119
118
|
end # module
|
120
|
-
|
121
|
-
require 'chook/server/routes'
|
@@ -0,0 +1,215 @@
|
|
1
|
+
### Copyright 2017 Pixar
|
2
|
+
|
3
|
+
###
|
4
|
+
### Licensed under the Apache License, Version 2.0 (the "Apache License")
|
5
|
+
### with the following modification; you may not use this file except in
|
6
|
+
### compliance with the Apache License and the following modification to it:
|
7
|
+
### Section 6. Trademarks. is deleted and replaced with:
|
8
|
+
###
|
9
|
+
### 6. Trademarks. This License does not grant permission to use the trade
|
10
|
+
### names, trademarks, service marks, or product names of the Licensor
|
11
|
+
### and its affiliates, except as required to comply with Section 4(c) of
|
12
|
+
### the License and to reproduce the content of the NOTICE file.
|
13
|
+
###
|
14
|
+
### You may obtain a copy of the Apache License at
|
15
|
+
###
|
16
|
+
### http://www.apache.org/licenses/LICENSE-2.0
|
17
|
+
###
|
18
|
+
### Unless required by applicable law or agreed to in writing, software
|
19
|
+
### distributed under the Apache License with the above modification is
|
20
|
+
### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
21
|
+
### KIND, either express or implied. See the Apache License for the specific
|
22
|
+
### language governing permissions and limitations under the Apache License.
|
23
|
+
###
|
24
|
+
###
|
25
|
+
|
26
|
+
# the main module
|
27
|
+
module Chook
|
28
|
+
|
29
|
+
# the server app
|
30
|
+
class Server < Sinatra::Base
|
31
|
+
|
32
|
+
# the CustomLogger helper allows us to
|
33
|
+
# use our own Logger instance as the
|
34
|
+
# Sinatra `logger` available in routes vis `set :logger...`
|
35
|
+
helpers Sinatra::CustomLogger
|
36
|
+
|
37
|
+
# This module defines our custom Logger instance from the config settings
|
38
|
+
# and makes it available in the .logger module method,
|
39
|
+
# which is used anywhere outside of a route
|
40
|
+
# (inside of a route, the #logger method is locally available)
|
41
|
+
#
|
42
|
+
# General access to the logger:
|
43
|
+
# from anywhere in Chook, as long as a server is running, the Logger
|
44
|
+
# instance is available at Chook.logger or Chook::Server::Log.logger
|
45
|
+
#
|
46
|
+
#
|
47
|
+
# Logging from inside a route:
|
48
|
+
# inside a Sinatra route, the local `logger` method returnes the
|
49
|
+
# Logger instance.
|
50
|
+
#
|
51
|
+
# Logging from an internal handler:
|
52
|
+
# In an internal WebHook handler, starting with `Chook.event_handler do |event|`
|
53
|
+
# the logger should be accesses via the event's own wrapper: event.logger
|
54
|
+
# Each message will be prepended with the event'd ID
|
55
|
+
#
|
56
|
+
# Logging from an external handler:
|
57
|
+
# from an external handler you can POST a JSON formatted log entry to
|
58
|
+
# http(s)://chookserver/log. The body must be a JSON object with 2 keys:
|
59
|
+
# 'level' and 'message', with non-empty strings.
|
60
|
+
# The level must be one of: fatal, error, warn, info, or debug. Any other
|
61
|
+
# value as the level will always be logged regardless of current logging
|
62
|
+
# level. NOTE: if your server requires authentication, you must provide it
|
63
|
+
# when using this route.
|
64
|
+
#
|
65
|
+
# Here's an example with curl, split to multi-line for clarity:
|
66
|
+
#
|
67
|
+
# curl -H "Content-Type: application/json" \
|
68
|
+
# -X POST \
|
69
|
+
# --data '{"level":"debug", "message":"It Worked"}' \
|
70
|
+
# https://user:passwd@chookserver.myorg.org:443/log
|
71
|
+
#
|
72
|
+
module Log
|
73
|
+
|
74
|
+
# Using an instance of this as the Logger target sends logfile writes
|
75
|
+
# to all registered streams as well as the file
|
76
|
+
class LogFileWithStream < File
|
77
|
+
|
78
|
+
# ServerSent Events data lines always start with this
|
79
|
+
LOGSTREAM_DATA_PFX = 'data:'.freeze
|
80
|
+
|
81
|
+
def write(str)
|
82
|
+
super # writes out to the file
|
83
|
+
flush
|
84
|
+
# send to any active streams
|
85
|
+
Chook::Server::Log.log_streams.keys.each do |active_stream|
|
86
|
+
# ignore streams closed at the client end,
|
87
|
+
# they get removed when a new stream starts
|
88
|
+
# see the route: get '/subscribe_to_log_stream'
|
89
|
+
next if active_stream.closed?
|
90
|
+
|
91
|
+
# send new data to the stream
|
92
|
+
active_stream << "#{LOGSTREAM_DATA_PFX}#{str}\n\n"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end # class
|
96
|
+
|
97
|
+
# mapping of integer levels to symbols
|
98
|
+
LOG_LEVELS = {
|
99
|
+
fatal: Logger::FATAL,
|
100
|
+
error: Logger::ERROR,
|
101
|
+
warn: Logger::WARN,
|
102
|
+
info: Logger::INFO,
|
103
|
+
debug: Logger::DEBUG
|
104
|
+
}.freeze
|
105
|
+
|
106
|
+
# log Streaming
|
107
|
+
# ServerSent Events data lines always start with this
|
108
|
+
LOGSTREAM_DATA_PFX = 'data:'.freeze
|
109
|
+
|
110
|
+
# Send this to the clients at least every LOGSTREAM_KEEPALIVE_MAX secs
|
111
|
+
# even if there's no data for the stream
|
112
|
+
LOGSTREAM_KEEPALIVE_MSG = "#{LOGSTREAM_DATA_PFX} I'm Here!\n\n".freeze
|
113
|
+
LOGSTREAM_KEEPALIVE_MAX = 10
|
114
|
+
|
115
|
+
# the clients will recognize M3_LOG_STREAM_CLOSED and stop trying
|
116
|
+
# to connect via ssh.
|
117
|
+
LOGSTREAM_CLOSED_PFX = "#{LOGSTREAM_DATA_PFX} M3_LOG_STREAM_CLOSED:".freeze
|
118
|
+
|
119
|
+
DEFAULT_FILE = Pathname.new '/var/log/chook-server.log'
|
120
|
+
DEFAULT_MAX_MEGS = 10
|
121
|
+
DEFAULT_TO_KEEP = 10
|
122
|
+
DEFAULT_LEVEL = Logger::INFO
|
123
|
+
|
124
|
+
# set defaults in config
|
125
|
+
Chook.config.log_file ||= DEFAULT_FILE
|
126
|
+
Chook.config.logs_to_keep ||= DEFAULT_TO_KEEP
|
127
|
+
Chook.config.log_max_megs ||= DEFAULT_MAX_MEGS
|
128
|
+
Chook.config.log_level ||= DEFAULT_LEVEL
|
129
|
+
|
130
|
+
# Create the logger,
|
131
|
+
# make the first log entry for this run,
|
132
|
+
# and return it so it can be used by the server
|
133
|
+
# when it does `set :logger, Log.startup(@log_level)`
|
134
|
+
def self.startup(level = Chook.config.log_level)
|
135
|
+
# create the logger using a LogFileWithStream instance
|
136
|
+
@logger =
|
137
|
+
if Chook.config.logs_to_keep && Chook.config.logs_to_keep > 0
|
138
|
+
Logger.new(
|
139
|
+
LogFileWithStream.new(Chook.config.log_file, 'a'),
|
140
|
+
Chook.config.logs_to_keep,
|
141
|
+
(Chook.config.log_max_megs * 1024 * 1024)
|
142
|
+
)
|
143
|
+
else
|
144
|
+
Logger.new(LogFileWithStream.new(Chook.config.log_file, 'a'))
|
145
|
+
end
|
146
|
+
|
147
|
+
# date and line format
|
148
|
+
@logger.datetime_format = '%Y-%m-%d %H:%M:%S'
|
149
|
+
|
150
|
+
@logger.formatter = proc do |severity, datetime, _progname, msg|
|
151
|
+
"#{datetime}: [#{severity}] #{msg}\n"
|
152
|
+
end
|
153
|
+
|
154
|
+
# level
|
155
|
+
level &&= Chook::Procs::STRING_TO_LOG_LEVEL.call level
|
156
|
+
level ||= Chook.config.log_level
|
157
|
+
level ||= DEFAULT_LEVEL
|
158
|
+
@logger.level = level
|
159
|
+
|
160
|
+
# first startup entry
|
161
|
+
@logger.unknown "Chook Server v#{Chook::VERSION} starting up. PID: #{$PROCESS_ID}, Port: #{Chook.config.port}, SSL: #{Chook.config.use_ssl}"
|
162
|
+
|
163
|
+
# if debug, log our config
|
164
|
+
if level == Logger::DEBUG
|
165
|
+
@logger.debug 'Config: '
|
166
|
+
Chook::Configuration::CONF_KEYS.keys.each do |key|
|
167
|
+
@logger.debug " Chook.config.#{key} = #{Chook.config.send key}"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# return the logger, the server uses it as a helper
|
172
|
+
@logger
|
173
|
+
end # log
|
174
|
+
|
175
|
+
# general access to the logger as Chook::Server::Log.logger
|
176
|
+
def self.logger
|
177
|
+
@logger ||= startup
|
178
|
+
end
|
179
|
+
|
180
|
+
# a Hash of registered log streams
|
181
|
+
# streams are keys, valus are their IP addrs
|
182
|
+
# see the `get '/subscribe_to_log_stream'` route
|
183
|
+
#
|
184
|
+
def self.log_streams
|
185
|
+
@log_streams ||= {}
|
186
|
+
end
|
187
|
+
|
188
|
+
def self.clean_log_streams
|
189
|
+
log_streams.delete_if do |stream, ip|
|
190
|
+
if stream.closed?
|
191
|
+
logger.debug "Removing closed log stream for #{ip}"
|
192
|
+
true
|
193
|
+
else
|
194
|
+
false
|
195
|
+
end # if
|
196
|
+
end # delete if
|
197
|
+
end # clean_log_streams
|
198
|
+
|
199
|
+
end # module
|
200
|
+
|
201
|
+
end # server
|
202
|
+
|
203
|
+
# access from everywhere as Chook.logger
|
204
|
+
def self.logger
|
205
|
+
Server::Log.logger
|
206
|
+
end
|
207
|
+
|
208
|
+
# log an exception - multiple log lines
|
209
|
+
# the first being the error message the rest being indented backtrace
|
210
|
+
def self.log_exception(exception)
|
211
|
+
logger.error exception.to_s
|
212
|
+
exception.backtrace.each { |l| logger.error "..#{l}" }
|
213
|
+
end
|
214
|
+
|
215
|
+
end # Chook
|