Consumer Custom Handlers
This document explains how consumer custom handlers work, what handlers are provided, and how to implement and deploy an additional custom handler.
Purpose
Custom handlers allow the consumer to process provider ServerToAgent.custom_message payloads by capability FQDN (reverse-DNS string).
The handler pipeline is capability-driven:
- provider sends
custom_message.capability - consumer resolves a handler class registered for that capability
- consumer executes handler logic and optional custom response
Main runtime components
- Handler interfaces:
consumer/src/opamp_consumer/custom_handlers/handler_interface.py - Discovery/registry:
consumer/src/opamp_consumer/custom_handlers/registry.py - Consumer message path:
consumer/src/opamp_consumer/client_server_message_mixin.py - Capability publication path:
consumer/src/opamp_consumer/abstract_client.py
Key configuration switch:
consumer.allow_custom_capabilitiesmust betruefor discovery and execution.
When disabled, handler discovery is skipped and custom capability handling is not active.
Built-in handlers
ChatOpsCommand
- File:
consumer/src/opamp_consumer/custom_handlers/chatops_command.py - Capability:
org.mp3monster.opamp_provider.chatopcommand - Behavior:
- parses custom payload JSON
- reads optional
tagandattributes - issues local HTTP POST to ChatOps endpoint (
localhost:<chat_ops_port>) - returns failure
CustomMessagepayload if endpoint response is non-2xx
ShutdownCommand
- File:
consumer/src/opamp_consumer/custom_handlers/shutdowncommand.py - Capability:
org.mp3monster.opamp_provider.command_shutdown_agent - Behavior:
- disables heartbeat
- sends disconnect
- terminates agent process
- exits process
NullCommand
- File:
consumer/src/opamp_consumer/custom_handlers/nullcommand.py - Capability:
org.mp3monster.opamp_provider.nullcommand - Behavior:
- parses optional
dummyValuefield - logs message details
- no further action (no-op validation path)
- parses optional
How discovery works
build_factory_lookup(...) scans the handler folder for .py files, imports classes that inherit CustomMessageHandlerInterface, and creates an FQDN -> class map.
Default folder per client implementation:
- Fluent Bit client:
consumer/src/opamp_consumer/custom_handlers - Fluentd client:
consumer/src/opamp_consumer/custom_handlers - Simulator client:
consumer/src/opamp_consumer/custom_handlers
Folder selection is provided by get_custom_handler_folder() in each concrete client.
Handler lifecycle
- consumer starts and builds handler lookup
- inbound custom message arrives
- consumer resolves handler by
custom_message.capability set_custom_message_handler(...)stores payloadexecute(...):- decodes payload
- extracts optional
action - calls
handle_message(...) - calls
execute_action(...)
- if
execute_action(...)returnsCustomMessage, consumer sends it upstream
Implementing a new custom handler
1. Create a handler file
Add a module under:
consumer/src/opamp_consumer/custom_handlers/<your_handler>.py
Subclass CustomMessageHandlerInterface and implement:
get_fqdn(self) -> strset_client_data(self, data)handle_message(self, message: str, message_type: str) -> Noneexecute_action(self, action: str, opamp_client) -> opamp_pb2.CustomMessage | None
2. Keep capability name exact
get_fqdn() must exactly match provider custom_message.capability.
If the capability string differs, routing fails and no handler will be used.
3. Handle payload parsing defensively
- treat payload as untrusted input
- guard JSON parsing (
json.JSONDecodeError) - validate required fields and types
- fail closed where destructive actions are possible
4. Optional response payload
If handler needs to report result/failure upstream:
- build and return
opamp_pb2.CustomMessagefromexecute_action(...) - return
Nonefor no response
The shared execute path sends returned custom response automatically.
5. Enable custom capabilities
Set in consumer config:
{
"consumer": {
"allow_custom_capabilities": true
}
}
6. Deploy and restart consumer
Handler discovery occurs at startup, so restart the consumer process after adding/updating handler modules.
Deployment checklist
- Add handler module in
custom_handlersfolder. - Confirm provider emits matching capability FQDN.
- Set
allow_custom_capabilities=true. - Restart consumer.
- Validate with provider command flow.
- Check consumer logs for discovery and execution events.
Testing guidance
Recommended tests:
- discovery test (
build_factory_lookupcontains expected FQDN) - creation test (
create_handlerreturns class instance) - payload parsing tests (valid + invalid JSON)
- action execution tests (success/failure paths)
- optional response message test when
execute_actionreturnsCustomMessage
Related examples:
consumer/tests/test_custom_handlers_chatops.pyconsumer/tests/test_custom_handlers_shutdown.pyconsumer/tests/test_custom_handlers_nullcommand.pyconsumer/tests/test_custom_handlers_registry.py
Notes on provider-side setup
Consumer handlers are one side of the custom command path. Provider command object/capability setup is documented in:
docs/dev/adding_your_own_custom_action.md
OpAMP