tracing_gelf/connection/
mod.rs

1mod tcp;
2mod udp;
3
4use std::{io, net::SocketAddr};
5
6use bytes::Bytes;
7use tokio::net::{lookup_host, ToSocketAddrs};
8use tokio_stream::wrappers::ReceiverStream;
9use tracing_core::subscriber::NoSubscriber;
10use tracing_futures::WithSubscriber;
11
12pub use tcp::*;
13pub use udp::*;
14
15/// A sequence of [errors](std::io::Error) which occurred during a connection attempt.
16///
17/// These are paired with a [`SocketAddr`] because the connection attempt might fail multiple times
18/// during DNS resolution.
19#[derive(Debug)]
20pub struct ConnectionErrors(pub Vec<(SocketAddr, io::Error)>);
21
22/// Provides an interface for connecting (and reconnecting) to Graylog. Without an established
23/// connection logs will not be sent. Messages logged without an established connection will sit in
24/// the buffer until they can be drained.
25#[derive(Debug)]
26#[must_use]
27pub struct ConnectionHandle<A, Conn> {
28    pub(crate) addr: A,
29    pub(crate) receiver: ReceiverStream<Bytes>,
30    pub(crate) conn: Conn,
31}
32
33impl<A, Conn> ConnectionHandle<A, Conn> {
34    /// Returns the connection address.
35    pub fn address(&self) -> &A {
36        &self.addr
37    }
38}
39
40impl<A> ConnectionHandle<A, TcpConnection>
41where
42    A: ToSocketAddrs,
43{
44    /// Connects to Graylog via TCP using the address provided.
45    ///
46    /// This will perform DNS resolution and attempt to connect to each [`SocketAddr`] provided.
47    pub async fn connect(&mut self) -> ConnectionErrors {
48        // Do a DNS lookup if `addr` is a hostname
49        let addrs = lookup_host(&self.addr).await.into_iter().flatten();
50
51        // Loop through the IP addresses that the hostname resolved to
52        let mut errors = Vec::new();
53        for addr in addrs {
54            let fut = self
55                .conn
56                .handle(addr, &mut self.receiver)
57                .with_subscriber(NoSubscriber::default());
58            if let Err(err) = fut.await {
59                errors.push((addr, err));
60            }
61        }
62        ConnectionErrors(errors)
63    }
64}
65
66#[cfg(feature = "rustls-tls")]
67impl<A> ConnectionHandle<A, TlsConnection>
68where
69    A: ToSocketAddrs,
70{
71    /// Connects to Graylog via TLS using the address provided.
72    ///
73    /// This will perform DNS resolution and attempt to connect to each [`SocketAddr`] provided.
74    pub async fn connect(&mut self) -> ConnectionErrors {
75        // Do a DNS lookup if `addr` is a hostname
76        let addrs = lookup_host(&self.addr).await.into_iter().flatten();
77
78        // Loop through the IP addresses that the hostname resolved to
79        let mut errors = Vec::new();
80        for addr in addrs {
81            let fut = self
82                .conn
83                .handle(addr, &mut self.receiver)
84                .with_subscriber(NoSubscriber::default());
85            if let Err(err) = fut.await {
86                errors.push((addr, err));
87            }
88        }
89        ConnectionErrors(errors)
90    }
91}
92
93impl<A> ConnectionHandle<A, UdpConnection>
94where
95    A: ToSocketAddrs,
96{
97    /// Connects to Graylog via UDP using the address provided.
98    ///
99    /// This will perform DNS resolution and attempt to connect to each [`SocketAddr`] provided.
100    pub async fn connect(&mut self) -> ConnectionErrors {
101        // Do a DNS lookup if `addr` is a hostname
102        let addrs = lookup_host(&self.addr).await.into_iter().flatten();
103
104        // Loop through the IP addresses that the hostname resolved to
105        let mut errors = Vec::new();
106        for addr in addrs {
107            let fut = self
108                .conn
109                .handle(addr, &mut self.receiver)
110                .with_subscriber(NoSubscriber::default());
111            if let Err(err) = fut.await {
112                errors.push((addr, err));
113            }
114        }
115        ConnectionErrors(errors)
116    }
117}