[comment]: # aside:5

[comment]: # ({f2a0429f-ebcec779})
# Inviare dati al server o al proxy Zabbix

[zabbix\_utils](https://github.com/zabbix/python-zabbix-utils/blob/main/README.md) consente di inviare valori di item a un [item trapper](/manual/config/items/itemtypes/trapper) sul server o proxy Zabbix (in modo simile a [Zabbix sender](/manual/concepts/sender)).

È possibile inviare un singolo valore, più valori o persino indirizzare più cluster Zabbix.

I dati possono essere inviati in modalità sincrona o asincrona:

-   In modalità sincrona, lo script Python invia i valori e attende una risposta prima di continuare; questa modalità è adatta per operazioni semplici, sequenziali e prevedibili.
-   In modalità asincrona, lo script invia i valori senza attendere ogni risposta, consentendo ad altre operazioni di procedere in parallelo; questa modalità è più efficiente per richieste lente o grandi quantità di dati.

Gli esempi in questa pagina si concentrano sulla modalità sincrona, sebbene la [modalità asincrona](#asynchronous-mode) segua schemi simili.
Ulteriori esempi sono disponibili nel repository GitHub [zabbix_utils](https://github.com/zabbix/python-zabbix-utils/tree/main/examples).

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

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

Per utilizzare zabbix\_utils per l'invio dei valori degli item, importa la classe `Sender` nel tuo script:

```python
from zabbix_utils import Sender
```

Per inviare più valori, puoi anche importare la classe `ItemValue`:

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

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

[comment]: # ({6215a382-248fa427})
#### Inviare un singolo valore

Per inviare un valore di un item:

1. Creare un'istanza di `Sender`, specificando l'indirizzo IP e la porta del server o proxy Zabbix.
2. Chiamare il metodo `send_value()` sull'istanza `Sender` utilizzando il seguente formato:

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

Ad esempio, per inviare `1` al trapper item `service.status` del 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})
##### Utilizzo di un IP non predefinito

Se il server che esegue lo script dispone di più indirizzi IP, è possibile specificare un `source_ip` che `Sender` utilizzerà durante l'invio dei valori al server o al proxy Zabbix:

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

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

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

Puoi impostare un `timeout` di risposta per `Sender` per controllare per quanto tempo il tuo script deve attendere una risposta dal server o dal proxy Zabbix prima di interrompere il tentativo:

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

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

[comment]: # ({04ae72fb-62dd1793})
##### Utilizzo del file di configurazione dell'agent

Puoi fare in modo che zabbix\_utils legga i parametri [`Server`](/manual/appendix/config/zabbix_agentd#server) o [`ServerActive`](/manual/appendix/config/zabbix_agentd#serveractive) da un file di configurazione locale di Zabbix agent o agent 2.
In questi casi, non è necessario specificare i parametri di connessione quando si crea un'istanza di `Sender`:

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

::: noteimportant
Se `ServerActive` contiene uno o più cluster Zabbix con più istanze server, `Sender` invia i dati al primo server disponibile in ciascun cluster.
Se `ServerActive` non è impostato, viene utilizzato l'indirizzo di `Server` con la porta predefinita (10051).
:::

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

[comment]: # ({f95d47a7-a8b30296})
##### Utilizzo della crittografia

`Sender` non include il supporto integrato per la crittografia, ma è possibile fornirlo creando un wrapper tramite librerie di terze parti:

```python
def psk_wrapper(sock, tls):
    # ...
    # Implementazione del wrapper TLS PSK per il socket
    # ...

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

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

[comment]: # ({e0a8b11b-b6a3d94d})
##### Risposta per valore singolo

La risposta restituita da Zabbix server o proxy viene elaborata dalla libreria e restituita come oggetto `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})
##### Modalità asincrona

La modalità asincrona consente al tuo script Python di inviare valori senza attendere una risposta dal server o dal proxy Zabbix.
Questo può rendere lo script più efficiente quando deve inviare molti valori o quando alcuni valori richiedono molto tempo per essere inviati.

Quando si utilizza la modalità asincrona, ci sono alcune differenze importanti rispetto alla modalità sincrona:

-   Importa il modulo `asyncio` di Python (devi prima [installare](/devel/python/install) le dipendenze richieste).
-   Importa `AsyncSender` invece di `Sender`.
-   Scrivi il codice all'interno di una funzione `async`.
-   Usa `await` quando chiami il metodo `send_value()`.

Ad esempio, per inviare un singolo valore utilizzando la modalità asincrona:

```python
# 1. Importa asyncio per la modalità asincrona e AsyncSender da zabbix_utils:
import asyncio
from zabbix_utils import AsyncSender

# 2. Definisci la funzione async principale in cui verranno eseguite tutte le operazioni di invio dei dati (è necessario usare await):
async def main():
    sender = AsyncSender(server='127.0.0.1', port=10051)
    response = await sender.send_value('Linux server', 'service.status', 1)

    # 3. Stampa la risposta restituita dal server o dal proxy Zabbix:
    print(response)

# 4. Esegui la funzione async main() utilizzando il ciclo di eventi di asyncio:
asyncio.run(main())
```

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

[comment]: # ({b845706b-34e0ff6d})
#### Inviare più valori

Per inviare più valori:

1. Preparare un array di oggetti `ItemValue`, ciascuno utilizzando lo stesso formato del metodo [`send_value()`](#send-single-value).
2. Creare un'istanza di `Sender`, specificando l'indirizzo IP e la porta del proprio server o proxy Zabbix.
3. Chiamare il metodo `send()` (invece di `send_value()`) sull'istanza `Sender`, specificando l'array di oggetti con i valori da inviare.

Ad esempio, per inviare cinque valori a host diversi:

```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})
##### Utilizzo di una dimensione personalizzata dei blocchi

Se devi inviare più valori di quanti un item trapper possa accettare in una singola richiesta, puoi suddividerli in blocchi.

Per impostazione predefinita, la dimensione del blocco è di 250 valori.
Puoi modificarla impostando il parametro `chunk_size` durante la creazione di un'istanza di `Sender`.

Ad esempio, per inviare cinque valori in tre blocchi (2-2-1), imposta il parametro `chunk_size` su `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})
##### Inviare valori a più cluster Zabbix

Per inviare valori a più cluster Zabbix:

1. Preparare un array di cluster Zabbix. Se un cluster ha più nodi, il valore verrà inviato al primo nodo **disponibile** di ciascun cluster.
2. Creare un `Sender`, specificando il proprio array di cluster Zabbix.
3. Chiamare il metodo `send_value()` sull'istanza `Sender` utilizzando lo stesso formato del metodo [`send_value()`](#send-single-value).

Ad esempio, per inviare un valore al primo nodo disponibile in ciascun cluster:

```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})
##### Risposta per più valori

Per impostazione predefinita, `Sender` restituisce un risultato aggregato dell'invio dei valori tra tutti gli host o cluster:

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

Se hai bisogno di informazioni più dettagliate, puoi esaminare i risultati per ciascun cluster e ciascun chunk utilizzando l'attributo `response.details`:

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

if response.failed == 0:
    print(f"Valore inviato con successo 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"Elaborati {resp.processed} di {resp.total} su {node.address}:{node.port}")
            # Elaborati 1 di 1 su 127.0.0.1:10051
            # Elaborati 1 di 1 su zabbix.example.local:10051
```

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