Usage¶
Base service class¶
from nameko.rpc import rpc
from nameko_chassis.service import Service
class MyService(Service):
name = "my_service"
@rpc
def my_method(self):
try:
do_something()
except Exception:
self.sentry.captureException()
Note
If the RPC method raises an unhandled exception, nameko-sentry will automatically capture it to Sentry. The example above demonstrates the case when one wants to access the client manually.
Distributed tracing¶
Since nameko-chassis 2.0, we provide an opinionated setup of OpenTelemetry.
Your services will export traces over HTTP to an endpoint defined in
OTEL_EXPORTER_OTLP_ENDPOINT
environment variable. However, you need to
call instrumentors yourself, for example:
from nameko_chassis.service import Service
from nameko_opentelemetry import NamekoInstrumentor
from opentelemetry.instrumentation.logging import LoggingInstrumentor
LoggingInstrumentor().instrument()
NamekoInstrumentor().instrument(
send_headers=True,
send_request_payloads=True,
send_response_payloads=True,
max_truncate_length=1000,
)
class MyService(Service):
name = "my_service"
Note
We chose HTTP over GRPC due to incompatibilities between eventlet and grpc with regards to asynchronous runtime.
Backdoor debugging¶
nameko-chassis.debug
includes helpers for introspecting running services
with nameko backdoor feature. For example if your service exposes backdoor
on port 12345:
$ rlwrap nc -v localhost 12345
Connection to localhost 12345 port [tcp/*] succeeded!
Python 3.8.8 (default, Mar 23 2021, 11:02:14)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from nameko_chassis.debug import debug_runner
>>> debug_runner(runner)
╭──────────────────────────── sleeping_http_service ───────────────────────────╮
│ 19 entrypoints │
│ 15 dependencies │
│ running 1/10 worker threads │
│ ╭────────────────── Thread #0: SleepingHttpService.sleep ──────────────────╮ │
│ │ │ │
│ │ Args: ["<Request 'http://127.0.0.1:8000/sleep/500' [GET]>"] │ │
│ │ Kwargs: {'duration': '500'} │ │
│ │ Context data: {'X-B3-ParentSpanId': '1058ef878ab0fe32'} │ │
│ │ │ │
│ │ Traceback: │ │
│ │ File │ │
│ │ "/home/zbigniewsiciarz/v/sleephttp/lib/python3.8/site-packages/eventlet… │ │
│ │ line 221, in main │ │
│ │ result = function(*args, **kwargs) │ │
│ │ File │ │
│ │ "/home/zbigniewsiciarz/v/sleephttp/lib/python3.8/site-packages/nameko/c… │ │
│ │ line 392, in _run_worker │ │
│ │ result = method(*worker_ctx.args, **worker_ctx.kwargs) │ │
│ │ File "./app/service.py", line 73, in sleep │ │
│ │ time.sleep(duration) │ │
│ │ File │ │
│ │ "/home/zbigniewsiciarz/v/sleephttp/lib/python3.8/site-packages/eventlet… │ │
│ │ line 36, in sleep │ │
│ │ hub.switch() │ │
│ │ File │ │
│ │ "/home/zbigniewsiciarz/v/sleephttp/lib/python3.8/site-packages/eventlet… │ │
│ │ line 313, in switch │ │
│ │ return self.greenlet.switch() │ │
│ │ │ │
│ ╰──────────────────────────────────────────────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────╯
Note
Pretty printing like in the above example requires rich.