[comment]: # aside:5

[comment]: # ({f2a0429f-ebcec779})
# Enviar datos al servidor o proxy de Zabbix

[zabbix\_utils](https://github.com/zabbix/python-zabbix-utils/blob/main/README.md) le permite enviar valores de item a un [item trapper](/manual/config/items/itemtypes/trapper) en el servidor o proxy de Zabbix (de forma similar a [Zabbix sender](/manual/concepts/sender)).

Puede enviar un único valor, varios valores o incluso dirigirse a varios clústeres de Zabbix.

Los datos pueden enviarse en modo síncrono o asíncrono:

-   En modo síncrono, su script de Python envía valores y espera una respuesta antes de continuar; esto es adecuado para operaciones simples, secuenciales y predecibles.
-   En modo asíncrono, el script envía valores sin esperar cada respuesta, lo que permite que otras operaciones continúen en paralelo; esto es más eficiente para solicitudes lentas o grandes lotes de datos.

Los ejemplos de esta página se centran en el modo síncrono, aunque el [modo asíncrono](#asynchronous-mode) sigue patrones similares.
Hay ejemplos adicionales disponibles en el repositorio de GitHub de [zabbix_utils](https://github.com/zabbix/python-zabbix-utils/tree/main/examples).

[comment]: # ({/f2a0429f-ebcec779})

[comment]: # ({33a3626c-2b58225a})
#### Importar

Para utilizar zabbix\_utils para enviar valores de item, importe la clase `Sender` en su script:

```python
from zabbix_utils import Sender
```

Para enviar múltiples valores, también puede importar la clase `ItemValue`:

```python
from zabbix_utils import Sender, ItemValue
```

[comment]: # ({/33a3626c-2b58225a})

[comment]: # ({6215a382-248fa427})
#### Enviar un único valor

Para enviar el valor de un item:

1. Cree una instancia de `Sender`, especificando la dirección IP y el puerto de su Zabbix server o proxy.
2. Llame al método `send_value()` en la instancia de `Sender` utilizando el siguiente formato:

```python
sender_instance.send_value('host', 'item.key', 'value', optional_timestamp, optional_nanoseconds)
```

Por ejemplo, para enviar `1` al item trapper `service.status` en el host `Linux server`:

```python
sender = Sender(server='127.0.0.1', port=10051)
response = sender.send_value('Linux server', 'service.status', 1)
```

[comment]: # ({/6215a382-248fa427})

[comment]: # ({ba5ab006-8c41d6ba})
##### Usar una IP no predeterminada

Si el servidor que ejecuta su script tiene varias direcciones IP, puede especificar una `source_ip` para que el `Sender` la utilice al enviar valores al servidor o proxy de Zabbix:

```python
sender = Sender(
    server='127.0.0.1',
    port=10051,
    source_ip='10.10.7.1'
)
```

[comment]: # ({/ba5ab006-8c41d6ba})

[comment]: # ({bff53bf5-de824c12})
##### Usando timeout

Puede establecer un `timeout` de respuesta para el `Sender` para controlar cuánto tiempo debe esperar su script una respuesta del server o proxy de Zabbix antes de rendirse:

```python
sender = Sender(
    server='127.0.0.1',
    port=10051,
    timeout=30
)
```

[comment]: # ({/bff53bf5-de824c12})

[comment]: # ({04ae72fb-62dd1793})
##### Usar el archivo de configuración del agent

Puede hacer que zabbix\_utils lea los parámetros [`Server`](/manual/appendix/config/zabbix_agentd#server) o [`ServerActive`](/manual/appendix/config/zabbix_agentd#serveractive) de un archivo de configuración local del agent de Zabbix o del agent 2.
En tales casos, no es necesario especificar los parámetros de conexión al crear una instancia de `Sender`:

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

::: noteimportant
Si `ServerActive` contiene uno o más clústeres de Zabbix con varias instancias de server, `Sender` envía los datos al primer server disponible en cada clúster.
Si `ServerActive` no está configurado, se utiliza la dirección de `Server` con el puerto por defecto (10051).
:::

[comment]: # ({/04ae72fb-62dd1793})

[comment]: # ({f95d47a7-a8b30296})
##### Usando cifrado

El `Sender` no incluye soporte de cifrado incorporado, pero puede proporcionarlo creando un wrapper usando librerías de terceros:

```python
def psk_wrapper(sock, tls):
    # ...
    # Implementación de un wrapper TLS PSK para el socket
    # ...

sender = Sender(
    server='127.0.0.1',
    port=10051,
    socket_wrapper=psk_wrapper
)
```

[comment]: # ({/f95d47a7-a8b30296})

[comment]: # ({e0a8b11b-b6a3d94d})
##### Respuesta para un solo valor

La respuesta devuelta por el server o proxy de Zabbix es procesada por la biblioteca y devuelta como un objeto `TrapperResponse`:

```python
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
```

[comment]: # ({/e0a8b11b-b6a3d94d})

[comment]: # ({d5faab4e-9eeea215})
##### Modo asíncrono

El modo asíncrono permite que tu script de Python envíe valores sin esperar una respuesta del servidor o proxy de Zabbix.
Esto puede hacer que tu script sea más eficiente cuando necesita enviar muchos valores o cuando algunos valores tardan mucho en enviarse.

Al utilizar el modo asíncrono, hay algunas diferencias importantes en comparación con el modo síncrono:

-   Importa el módulo `asyncio` de Python (primero debes [instalar](/devel/python/install) las dependencias requeridas).
-   Importa `AsyncSender` en lugar de `Sender`.
-   Escribe tu código dentro de una función `async`.
-   Usa `await` al llamar al método `send_value()`.

Por ejemplo, para enviar un solo valor utilizando el modo asíncrono:

```python
# 1. Importa asyncio para el modo asíncrono y AsyncSender desde zabbix_utils:
import asyncio
from zabbix_utils import AsyncSender

# 2. Define la función principal async donde se ejecutarán todas las operaciones de envío de datos (deben usar await):
async def main():
    sender = AsyncSender(server='127.0.0.1', port=10051)
    response = await sender.send_value('Linux server', 'service.status', 1)

    # 3. Imprime la respuesta devuelta por el servidor o proxy de Zabbix:
    print(response)

# 4. Ejecuta la función async main() usando el bucle de eventos de asyncio:
asyncio.run(main())
```

[comment]: # ({/d5faab4e-9eeea215})

[comment]: # ({b845706b-34e0ff6d})
#### Enviar múltiples valores

Para enviar múltiples valores:

1. Prepare un array de objetos `ItemValue`, cada uno utilizando el mismo formato que el método [`send_value()`](#send-single-value).
2. Cree una instancia de `Sender`, especificando la dirección IP y el puerto de su Zabbix server o proxy.
3. Llame al método `send()` (en lugar de `send_value()`) en la instancia de `Sender`, especificando el array de objetos con los valores a enviar.

Por ejemplo, para enviar cinco valores a diferentes hosts:

```python
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)
```

[comment]: # ({/b845706b-34e0ff6d})

[comment]: # ({c0410a6d-5848e96f})
##### Usar un tamaño de fragmento personalizado

Si necesita enviar más valores de los que un item trapper puede aceptar en una sola solicitud, puede dividirlos en fragmentos.

Por defecto, el tamaño del fragmento es de 250 valores.
Puede cambiarlo estableciendo el parámetro `chunk_size` al crear una instancia de `Sender`.

Por ejemplo, para enviar cinco valores en tres fragmentos (2-2-1), establezca el parámetro `chunk_size` en `2`:

```python
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)
```

[comment]: # ({/c0410a6d-5848e96f})

[comment]: # ({b06724dd-5a0b5783})
##### Enviar valores a varios clústeres de Zabbix

Para enviar valores a varios clústeres de Zabbix:

1. Prepare una matriz de clústeres de Zabbix. Si un clúster tiene varios nodos, el valor se enviará al primer nodo **disponible** de cada clúster.
2. Cree un `Sender`, especificando su matriz de clústeres de Zabbix.
3. Llame al método `send_value()` en la instancia de `Sender` utilizando el mismo formato que el método [`send_value()`](#send-single-value).

Por ejemplo, para enviar un valor al primer nodo disponible en cada clúster:

```python
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)
```

[comment]: # ({/b06724dd-5a0b5783})

[comment]: # ({2c3cc8b2-d7964287})
##### Respuesta para múltiples valores

Por defecto, `Sender` devuelve un resultado agregado del envío de valores a través de todos los hosts o clústeres:

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

Si necesita información más detallada, puede inspeccionar los resultados de cada clúster y cada chunk utilizando el atributo `response.details`:

```python
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
```

[comment]: # ({/2c3cc8b2-d7964287})
