web - meetbill/shinken GitHub Wiki
注册插件
[call stack]:
<frame 0>:/home/meetbill/shinken/http_daemon.py, line:349 func: logger.debug_trace("Registering")
<frame 1>:/home/meetbill/shinken/satellite.py, line:898 func: self.uri2 = self.http_daemon.register(self.interface)
<frame 2>:/home/meetbill/shinken/satellite.py, line:1127 func: self.do_post_daemon_init()
<frame 3>:/home/meetbill/bin/shinken-poller, line:91 func: daemon.main()
<frame 4>:/home/meetbill/bin/shinken-poller, line:99 func: main()
satellite.py:896:do_post_daemon_init
# Do this satellite (poller or reactionner) post "daemonize" init:
# we must register our interfaces for 3 possible callers: arbiter,
# schedulers or brokers.
def do_post_daemon_init(self):
# And we register them
self.uri2 = self.http_daemon.register(self.interface)
self.uri3 = self.http_daemon.register(self.brok_interface)
self.uri4 = self.http_daemon.register(self.scheduler_interface)
self.uri5 = self.http_daemon.register(self.istats)
# self.s = Queue() # Global Master -> Slave
# We can open the Queue for fork AFTER
self.q_by_mod['fork'] = {}
# Under Android, we do not have multiprocessing lib
# so use standard Queue threads things
# but in multiprocess, we are also using a Queue(). It's just
# not the same
if is_android:
self.returns_queue = Queue()
else:
self.returns_queue = self.manager.Queue()
# For multiprocess things, we should not have
# socket timeouts.
import socket
socket.setdefaulttimeout(None)
注册插件:shinken/http_daemon.py
def register(self, obj):
methods = inspect.getmembers(obj, predicate=inspect.ismethod)
merge = [fname for (fname, f) in methods if fname in self.registered_fun_names]
if merge != []:
methods_in = [m.__name__ for m in obj.__class__.__dict__.values() if inspect.isfunction(m)]
methods = [m for m in methods if m[0] in methods_in]
print "picking only bound methods of class and not parents"
print "List to register :%s" % methods
for (fname, f) in methods:
if fname.startswith('_'):
continue
# Get the args of the function to catch them in the queries
argspec = inspect.getargspec(f)
args = argspec.args
varargs = argspec.varargs
keywords = argspec.keywords
defaults = argspec.defaults
# If we got some defauts, save arg=value so we can lookup
# for them after
if defaults:
default_args = zip(argspec.args[-len(argspec.defaults):], argspec.defaults)
_d = {}
for (argname, defavalue) in default_args:
_d[argname] = defavalue
self.registered_fun_defaults[fname] = _d
# remove useless self in args, because we alredy got a bonded method f
if 'self' in args:
args.remove('self')
print "Registering", fname, args, obj
logger.debug_trace("Registering")
self.registered_fun_names.append(fname)
self.registered_fun[fname] = (f)
# WARNING : we MUST do a 2 levels function here, or the f_wrapper
# will be uniq and so will link to the last function again
# and again
def register_callback(fname, args, f, obj, lock):
def f_wrapper():
t0 = time.time()
args_time = aqu_lock_time = calling_time = json_time = 0
need_lock = getattr(f, 'need_lock', True)
# Warning : put the bottle.response set inside the wrapper
# because outside it will break bottle
d = {}
method = getattr(f, 'method', 'get').lower()
for aname in args:
v = None
if method == 'post':
v = bottle.request.forms.get(aname, None)
# Post args are zlibed and cPickled (but in
# safemode)
if v is not None:
v = zlib.decompress(v)
v = SafeUnpickler.loads(v)
elif method == 'get':
v = bottle.request.GET.get(aname, None)
if v is None:
# Maybe we got a default value?
default_args = self.registered_fun_defaults.get(fname, {})
if aname not in default_args:
raise Exception('Missing argument %s' % aname)
v = default_args[aname]
d[aname] = v
t1 = time.time()
args_time = t1 - t0
if need_lock:
logger.debug("HTTP: calling lock for %s", fname)
lock.acquire()
t2 = time.time()
aqu_lock_time = t2 - t1
try:
ret = f(**d)
# Always call the lock release if need
finally:
# Ok now we can release the lock
if need_lock:
lock.release()
t3 = time.time()
calling_time = t3 - t2
encode = getattr(f, 'encode', 'json').lower()
j = json.dumps(ret)
t4 = time.time()
json_time = t4 - t3
global_time = t4 - t0
logger.debug("Debug perf: %s [args:%s] [aqu_lock:%s]"
"[calling:%s] [json:%s] [global:%s]",
fname, args_time, aqu_lock_time, calling_time, json_time,
global_time)
lst = [('args', args_time), ('aqulock', aqu_lock_time),
('calling', calling_time), ('json', json_time),
('global', global_time)]
# increase the stats timers
for (k, _t) in lst:
statsmgr.timing('http.%s.%s' % (fname, k), _t, 'perf')
return j
# Ok now really put the route in place
bottle.route('/' + fname, callback=f_wrapper, method=getattr(f, 'method', 'get').upper())
# and the name with - instead of _ if need
fname_dash = fname.replace('_', '-')
if fname_dash != fname:
bottle.route('/' + fname_dash, callback=f_wrapper, method=getattr(f, 'method', 'get').upper())
register_callback(fname, args, f, obj, self.lock)
# Add a simple / page
def slash():
return "OK"
bottle.route('/', callback=slash)