web - meetbill/shinken GitHub Wiki

web 插件化

注册插件

[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)

⚠️ **GitHub.com Fallback** ⚠️