Send data to Zabbix server or proxy

zabbix_utils lets you send item values to a trapper item on Zabbix server or proxy (similarly to Zabbix sender).

You can send a single value, multiple values, or even target multiple Zabbix clusters.

Data can be sent in synchronous or asynchronous mode:

  • In synchronous mode, your Python script sends values and waits for a response before continuing; this is suitable for simple, sequential, and predictable operations.
  • In asynchronous mode, the script sends values without waiting for each response, allowing other operations to proceed in parallel; this is more efficient for slow requests or large batches of data.

The examples on this page focus on synchronous mode, though asynchronous mode follows similar patterns. Additional examples are available in the zabbix_utils GitHub repository.

Import

To use zabbix_utils for sending item values, import the Sender class in your script:

from zabbix_utils import Sender

For sending multiple values, you may also import the ItemValue class:

from zabbix_utils import Sender, ItemValue

Send single value

To send an item value:

  1. Create a Sender instance, specifying the IP address and port of your Zabbix server or proxy.
  2. Call the send_value() method on the Sender instance using the following format:
sender_instance.send_value('host', 'item.key', 'value', optional_timestamp, optional_nanoseconds)

For example, to send 1 to the service.status trapper item on the Linux server host:

sender = Sender(server='127.0.0.1', port=10051)
       response = sender.send_value('Linux server', 'service.status', 1)
Using non-default IP

If the server running your script has multiple IP addresses, you can specify a source_ip for the Sender to use when sending values to Zabbix server or proxy:

sender = Sender(
           server='127.0.0.1',
           port=10051,
           source_ip='10.10.7.1'
       )
Using timeout

You can set a response timeout for the Sender to control how long your script should wait for a response from Zabbix server or proxy before giving up:

sender = Sender(
           server='127.0.0.1',
           port=10051,
           timeout=30
       )
Using agent configuration file

You can let zabbix_utils read the Server or ServerActive parameters from a local Zabbix agent or agent 2 configuration file. In such cases, you don't need to specify connection parameters when creating a Sender instance:

sender = Sender(
           use_config=True,
           config_path='/etc/zabbix/zabbix_agent2.conf'
       )

If ServerActive contains one or more Zabbix clusters with multiple server instances, Sender sends data to the first available server in each cluster. If ServerActive is not set, the address from Server with the default port (10051) is used.

Using encryption

The Sender does not include built-in encryption support, but you can provide it by creating a wrapper using third-party libraries:

def psk_wrapper(sock, tls):
           # ...
           # Implementation of TLS PSK wrapper for the socket
           # ...
       
       sender = Sender(
           server='127.0.0.1',
           port=10051,
           socket_wrapper=psk_wrapper
       )
Response for single value

The response returned by Zabbix server or proxy is processed by the library and returned as a TrapperResponse object:

print(response)
       # {"processed": 1, "failed": 0, "total": 1, "time": "0.000123", "chunk": 1}
       
       print(response.processed)
       # 1
       
       print(response.failed)
       # 0
       
       print(response.total)
       # 1
Asynchronous mode

Asynchronous mode lets your Python script send values without waiting for a response from Zabbix server or proxy. This can make your script more efficient when it needs to send many values or when some values take a long time send.

When using asynchronous mode, there are a few important differences compared to synchronous mode:

  • Import Python's asyncio module (you must first install the required dependencies).
  • Import AsyncSender instead of Sender.
  • Write your code inside an async function.
  • Use await when calling the send_value() method.

For example, to send a single value using asynchronous mode:

# 1. Import asyncio for asynchronous mode, and AsyncSender from zabbix_utils:
       import asyncio
       from zabbix_utils import AsyncSender
       
       # 2. Define the main async function where all data sending operations (must await) will be executed:
       async def main():
           sender = AsyncSender(server='127.0.0.1', port=10051)
           response = await sender.send_value('Linux server', 'service.status', 1)
       
           # 3. Print the response returned by Zabbix server or proxy:
           print(response)
       
       # 4. Run the async main() function using asyncio's event loop:
       asyncio.run(main())

Send multiple values

To send multiple values:

  1. Prepare an array of ItemValue objects, each using the same format as the send_value() method.
  2. Create a Sender instance, specifying the IP address and port of your Zabbix server or proxy.
  3. Call the send() method (instead of send_value()) on the Sender instance, specifying the array of objects with values to send.

For example, to send five values to different hosts:

items = [
           ItemValue('server-de', 'service.status', 'up', 1770887205, 100),
           ItemValue('server-fr', 'service.status', 'up', 1770887205, 100),
           ItemValue('server-uk', 'service.status', 'up', 1770887205, 100),
           ItemValue('server-nl', 'service.status', 'up', 1770887205, 100),
           ItemValue('server-pl', 'service.status', 'up', 1770887205, 100),
       ]
       
       sender = Sender(server='127.0.0.1', port=10051)
       response = sender.send(items)
Using custom chunk size

If you need to send more values than a trapper item can accept in a single request, you can split them into chunks.

By default, the chunk size is 250 values. You can change it by setting the chunk_size parameter when creating a Sender instance.

For example, to send five values in three chunks (2-2-1), set the chunk_size parameter to 2:

items = [
           ItemValue('server-de', 'service.status', 'up'),
           ItemValue('server-fr', 'service.status', 'up'),
           ItemValue('server-uk', 'service.status', 'up'),
           ItemValue('server-nl', 'service.status', 'up'),
           ItemValue('server-pl', 'service.status', 'up'),
       ]
       
       sender = Sender(server='127.0.0.1', port=10051, chunk_size=2)
       response = sender.send(items)
Send values to multiple Zabbix clusters

To send values to multiple Zabbix clusters:

  1. Prepare an array of Zabbix clusters. If a cluster has multiple nodes, the value will be sent to the first available node of each cluster.
  2. Create a Sender, specifying your array of Zabbix clusters.
  3. Call the send_value() method on the Sender instance using the same format as the send_value() method.

For example, to send send a value to the first available node in each cluster:

zabbix_clusters = [
           ['zabbix.cluster1.node1', 'zabbix.cluster1.node2:10051'],
           ['zabbix.cluster2.node1:10051', 'zabbix.cluster2.node2', 'zabbix.cluster2.node3']
       ]
       
       sender = Sender(clusters=zabbix_clusters)
       response = sender.send_value('Linux server', 'service.status', 1)
Response for multiple values

By default, Sender returns an aggregated result of sending values across all hosts or clusters:

print(response)
       # {"processed": 2, "failed": 0, "total": 2, "time": "0.000108", "chunk": 2}

If you need more detailed information, you can inspect the results for each cluster and each chunk using the response.details attribute:

print(response)
       # {"processed": 2, "failed": 0, "total": 2, "time": "0.000108", "chunk": 2}
       
       if response.failed == 0:
           print(f"Value sent successfully in {response.time}")
       else:
           print(response.details)
           # {
           #     127.0.0.1:10051: [
           #         {
           #             "processed": 1,
           #             "failed": 0,
           #             "total": 1,
           #             "time": "0.000051",
           #             "chunk": 1
           #         }
           #     ],
           #     zabbix.example.local:10051: [
           #         {
           #             "processed": 1,
           #             "failed": 0,
           #             "total": 1,
           #             "time": "0.000057",
           #             "chunk": 1
           #         }
           #     ]
           # }
       
           for node, chunks in response.details.items():
               for resp in chunks:
                   print(f"Processed {resp.processed} of {resp.total} at {node.address}:{node.port}")
                   # Processed 1 of 1 at 127.0.0.1:10051
                   # Processed 1 of 1 at zabbix.example.local:10051