gRPC Channelz
grpcio-channelz provides the implementation for gRPC's Channelz service, offering live debugging and introspection capabilities for gRPC channels, subchannels, and calls. It extends the core grpcio library functionality. The current version, 1.80.0, typically aligns with the grpcio release cycle, providing continuous updates and bug fixes.
Common errors
-
ModuleNotFoundError: No module named 'grpcio_channelz.proto.channelz_pb2'
cause The `grpcio-channelz` package, which contains the Protobuf-generated client stubs and messages, is not installed.fixInstall the package using `pip install grpcio-channelz` (and typically `grpcio` as well). -
AttributeError: module 'grpc' has no attribute 'experimental'
cause Either `grpcio` is an older version that predates the `experimental` module, or `grpcio-channelz` is not installed, which provides the underlying implementation that `grpc.experimental.channelz` relies on to become available.fixEnsure both `grpcio` (>=1.48.x is a good baseline) and `grpcio-channelz` are installed: `pip install --upgrade grpcio grpcio-channelz`. -
grpc._channel._MultiThreadedRendezvous: <_MultiThreadedRendezvous object at 0x...>: StatusCode.UNIMPLEMENTED details="unknown service grpc.channelz.v1.Channelz"
cause The gRPC server has not correctly enabled or registered the Channelz service, or the `grpcio-channelz` package is missing on the server-side.fixOn the server-side, ensure `import grpc.experimental.channelz` is present in your server application code and that `grpcio-channelz` is installed in the server's environment. Simply importing it typically registers the service.
Warnings
- gotcha The `grpcio-channelz` package itself primarily provides the Protobuf definitions and service implementation, but you interact with Channelz on the server-side through `grpc.experimental.channelz` from the main `grpcio` library. It's a common confusion point that installing `grpcio-channelz` doesn't expose its own direct Python API for server enablement.
- gotcha Enabling Channelz introduces a slight performance overhead due to the collection of runtime metrics and state. Additionally, Channelz exposes internal system details that should be secured and not exposed to untrusted parties in production environments without proper authentication and authorization.
- deprecated The `channelz` module was long considered `experimental` within gRPC. While the import path `grpc.experimental.channelz` remains, its stability has improved significantly. However, users should still be aware that APIs marked 'experimental' might evolve faster than stable APIs.
Install
-
pip install grpcio grpcio-channelz
Imports
- channelz
import grpc.experimental.channelz
- ChannelzStub
from grpc.channelz_pb2_grpc import ChannelzStub
from grpcio_channelz.proto.channelz_pb2_grpc import ChannelzStub
- GetTopChannelsRequest
from grpc.channelz_pb2 import GetTopChannelsRequest
from grpcio_channelz.proto.channelz_pb2 import GetTopChannelsRequest
Quickstart
import grpc
import grpc.experimental.channelz
from concurrent import futures
# For client-side querying
from grpcio_channelz.proto.channelz_pb2 import GetTopChannelsRequest
from grpcio_channelz.proto.channelz_pb2_grpc import ChannelzStub
# --- Server-side: Enable Channelz (simple import is often enough) ---
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
# Simply importing grpc.experimental.channelz registers the service.
# You could explicitly add it if needed, but for basic setup, import is enough.
# grpc.experimental.channelz.add_server_channelz_stub(server) # Not strictly necessary if imported
server.add_insecure_port('[::]:50051')
server.start()
print("Server started on port 50051. Channelz enabled.")
return server
# --- Client-side: Query Channelz ---
def query_channelz(server_address='localhost:50051'):
with grpc.insecure_channel(server_address) as channel:
stub = ChannelzStub(channel)
try:
# Query for top channels
response = stub.GetTopChannels(GetTopChannelsRequest(started_channel_id=0, max_results=10))
print("\n--- Channelz Top Channels ---")
for channel_info in response.channel: # Use .channel, not .top_channel
print(f"ID: {channel_info.ref.channel_id}, State: {channel_info.data.state.state}, Target: {channel_info.data.target}")
except grpc.RpcError as e:
print(f"Error querying Channelz: {e.code().name} - {e.details()}")
if __name__ == '__main__':
server = serve()
# Allow some time for server to start and channels to register
import time
time.sleep(2)
# Make a dummy call to ensure a channel is created and visible to channelz
with grpc.insecure_channel('localhost:50051') as client_channel:
try:
# Just connect, no actual rpc needed to create a channel
grpc.channel_ready_future(client_channel).wait(timeout=1)
print("Dummy client connection made to register a channel.")
except grpc.FutureTimeoutError:
print("Dummy client connection timed out, but channel might still be visible.")
query_channelz()
server.stop(0) # Stop server gracefully