How do you do monitoring?


#1

From @dAnjou on Wed Apr 15 2015 15:26:06 GMT+0000 (UTC)

Is there anything like Flower for Celery, or is this not comparable? Or maybe you have a special setup of external tools?


Copied from original issue: https://github.com/nameko/nameko/issues/243


#2

From @mattbennett on Thu Apr 16 2015 15:52:14 GMT+0000 (UTC)

This is a great question that we don’t touch on in the docs (but should).

Short answer:

Nameko does’t dictate any particular tool. At onefinestay we log exceptions to sentry, timing stats to graphite and entrypoint invocation (service and method name, arguments, call stack, success/error status, result bytes, response time etc.) to elasticsearch/logstash. This is a really powerful setup for debugging across multiple services.

Each of these loggers are service dependencies, and we intend to open source each of them as community extensions.

Longer answer:

One of the nice things about nameko’s dependency injection pattern is the integration with the worker lifecycle. DependencyProvider extensions are notified when workers are setup, torn down, and generate a result. A trivial logging dependency might look like:

class LoggingDependency(DependencyProvider):

    def __init__(self):
        self.timestamps = WeakKeyDictionary()

    def worker_setup(self, worker_ctx):

        self.timestamps[worker_ctx] = datetime.datetime.now()

        service_name = worker_ctx.service_name
        method_name = worker_ctx.entrypoint.method_name

        log.info("Worker %s.%s starting", service_name, method_name)

    def worker_result(self, worker_ctx, result=None, exc_info=None):

        service_name = worker_ctx.service_name
        method_name = worker_ctx.entrypoint.method_name

        if exc_info is None:
            status = "completed"
        else:
            status = "errored"

        now = datetime.datetime.now()
        worker_started = self.timestamps.pop(worker_ctx)
        elapsed = (now - worker_started).seconds

        log.info("Worker %s.%s %s after %ss",
                 service_name, method_name, status, elapsed)

Then you can add it to your service in a nicely decoupled way:

class Service(object):
    name = "myservice"

    logger = LoggingDependency()  # << just add this line

    @rpc
    def method(self, arg):
        ...

#3

From @dAnjou on Thu Apr 16 2015 16:20:11 GMT+0000 (UTC)

Really nice answer, thank you very much!