feat(obs, net): Add Tempo service and enable dual-stack listener (#192)
This commit introduces two key enhancements: the integration of Grafana Tempo for distributed tracing and the implementation of a dual-stack TCP listener for improved network compatibility. - **Observability**: - Adds the `tempo` service to the `docker-compose.yml` observability stack. - Tempo is configured to collect and store traces, integrating with the existing OpenTelemetry setup. - A custom `tempo-entrypoint.sh` script is included to manage volume permissions on startup. - **Networking**: - Modifies `http.rs` to support dual-stack (IPv4/IPv6) connections on a single socket. - By setting the `IPV6_V6ONLY` socket option to `false`, the server can now accept both IPv6 and IPv4-mapped IPv6 traffic, enhancing cross-platform support.
This commit is contained in:
@@ -81,6 +81,7 @@ serde_json.workspace = true
|
||||
serde_urlencoded = { workspace = true }
|
||||
shadow-rs = { workspace = true, features = ["build", "metadata"] }
|
||||
socket2 = { workspace = true }
|
||||
sysctl = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tracing.workspace = true
|
||||
time = { workspace = true, features = ["parsing", "formatting", "serde"] }
|
||||
|
||||
@@ -64,7 +64,37 @@ pub async fn start_http_server(
|
||||
let server_address = server_addr.to_string();
|
||||
|
||||
// The listening address and port are obtained from the parameters
|
||||
let listener = TcpListener::bind(server_address.clone()).await?;
|
||||
// let listener = TcpListener::bind(server_address.clone()).await?;
|
||||
|
||||
// The listening address and port are obtained from the parameters
|
||||
let listener = {
|
||||
let mut server_addr = server_addr;
|
||||
let mut socket = socket2::Socket::new(
|
||||
socket2::Domain::for_address(server_addr),
|
||||
socket2::Type::STREAM,
|
||||
Some(socket2::Protocol::TCP),
|
||||
)?;
|
||||
|
||||
if server_addr.is_ipv6() {
|
||||
if let Err(e) = socket.set_only_v6(false) {
|
||||
warn!("Failed to set IPV6_V6ONLY=false, falling back to IPv4-only: {}", e);
|
||||
// Fallback to a new IPv4 socket if setting dual-stack fails.
|
||||
let ipv4_addr = SocketAddr::new(std::net::Ipv4Addr::UNSPECIFIED.into(), server_addr.port());
|
||||
server_addr = ipv4_addr;
|
||||
socket = socket2::Socket::new(socket2::Domain::IPV4, socket2::Type::STREAM, Some(socket2::Protocol::TCP))?;
|
||||
}
|
||||
}
|
||||
|
||||
// Common setup for both IPv4 and successful dual-stack IPv6
|
||||
let backlog = get_listen_backlog();
|
||||
socket.set_reuse_address(true)?;
|
||||
// Set the socket to non-blocking before passing it to Tokio.
|
||||
socket.set_nonblocking(true)?;
|
||||
socket.bind(&server_addr.into())?;
|
||||
socket.listen(backlog)?;
|
||||
TcpListener::from_std(socket.into())?
|
||||
};
|
||||
|
||||
// Obtain the listener address
|
||||
let local_addr: SocketAddr = listener.local_addr()?;
|
||||
debug!("Listening on: {}", local_addr);
|
||||
@@ -427,3 +457,44 @@ fn check_auth(req: Request<()>) -> std::result::Result<Request<()>, Status> {
|
||||
_ => Err(Status::unauthenticated("No valid auth token")),
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines the listen backlog size.
|
||||
///
|
||||
/// It tries to read the system's maximum connection queue length (`somaxconn`).
|
||||
/// If reading fails, it falls back to a default value (e.g., 1024).
|
||||
/// This makes the backlog size adaptive to the system configuration.
|
||||
fn get_listen_backlog() -> i32 {
|
||||
const DEFAULT_BACKLOG: i32 = 1024;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
// For Linux, read from /proc/sys/net/core/somaxconn
|
||||
match std::fs::read_to_string("/proc/sys/net/core/somaxconn") {
|
||||
Ok(s) => s.trim().parse().unwrap_or(DEFAULT_BACKLOG),
|
||||
Err(_) => DEFAULT_BACKLOG,
|
||||
}
|
||||
}
|
||||
#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
||||
{
|
||||
// For macOS and BSD variants, use sysctl
|
||||
use sysctl::Sysctl;
|
||||
match sysctl::Ctl::new("kern.ipc.somaxconn") {
|
||||
Ok(ctl) => match ctl.value() {
|
||||
Ok(sysctl::CtlValue::Int(val)) => val,
|
||||
_ => DEFAULT_BACKLOG,
|
||||
},
|
||||
Err(_) => DEFAULT_BACKLOG,
|
||||
}
|
||||
}
|
||||
#[cfg(not(any(
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd"
|
||||
)))]
|
||||
{
|
||||
// Fallback for Windows and other operating systems
|
||||
DEFAULT_BACKLOG
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user