-
-
Notifications
You must be signed in to change notification settings - Fork 148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(console): add support for Unix domain sockets #388
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
//! Demonstrates serving the console API over a [Unix domain socket] (UDS) | ||
//! connection, rather than over TCP. | ||
//! | ||
//! Note that this example only works on Unix operating systems that | ||
//! support UDS, such as Linux, BSDs, and macOS. | ||
//! | ||
//! [Unix domain socket]: https://en.wikipedia.org/wiki/Unix_domain_socket | ||
|
||
#[cfg(unix)] | ||
use { | ||
std::time::Duration, | ||
tokio::{fs, task, time}, | ||
tracing::info, | ||
}; | ||
|
||
#[cfg(unix)] | ||
#[tokio::main] | ||
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { | ||
let cwd = fs::canonicalize(".").await?; | ||
let addr = cwd.join("console-server"); | ||
console_subscriber::ConsoleLayer::builder() | ||
.server_addr(&*addr) | ||
.init(); | ||
info!( | ||
"listening for console connections at file://localhost{}", | ||
addr.display() | ||
); | ||
task::Builder::default() | ||
.name("sleepy") | ||
.spawn(async move { time::sleep(Duration::from_secs(90)).await }) | ||
.unwrap() | ||
.await?; | ||
|
||
Ok(()) | ||
} | ||
|
||
#[cfg(not(unix))] | ||
fn main() { | ||
panic!("only supported on Unix platforms") | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
use super::{ConsoleLayer, Server}; | ||
#[cfg(unix)] | ||
use std::path::Path; | ||
use std::{ | ||
net::{SocketAddr, ToSocketAddrs}, | ||
net::{IpAddr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}, | ||
path::PathBuf, | ||
thread, | ||
time::Duration, | ||
|
@@ -32,7 +34,7 @@ pub struct Builder { | |
pub(crate) retention: Duration, | ||
|
||
/// The address on which to serve the RPC server. | ||
pub(super) server_addr: SocketAddr, | ||
pub(super) server_addr: ServerAddr, | ||
|
||
/// If and where to save a recording of the events. | ||
pub(super) recording_path: Option<PathBuf>, | ||
|
@@ -58,7 +60,7 @@ impl Default for Builder { | |
publish_interval: ConsoleLayer::DEFAULT_PUBLISH_INTERVAL, | ||
retention: ConsoleLayer::DEFAULT_RETENTION, | ||
poll_duration_max: ConsoleLayer::DEFAULT_POLL_DURATION_MAX, | ||
server_addr: SocketAddr::new(Server::DEFAULT_IP, Server::DEFAULT_PORT), | ||
server_addr: ServerAddr::Tcp(SocketAddr::new(Server::DEFAULT_IP, Server::DEFAULT_PORT)), | ||
recording_path: None, | ||
filter_env_var: "RUST_LOG".to_string(), | ||
self_trace: false, | ||
|
@@ -137,8 +139,34 @@ impl Builder { | |
/// before falling back on constructing a socket address from those | ||
/// defaults. | ||
/// | ||
/// The socket address can be either a TCP socket address or a | ||
/// [Unix domain socket] (UDS) address. Unix domain sockets are only | ||
/// supported on Unix-compatible operating systems, such as Linux, BSDs, | ||
/// and macOS. | ||
/// | ||
/// Each call to this method will overwrite the previously set value. | ||
/// | ||
/// # Examples | ||
/// | ||
/// Connect to the TCP address `localhost:1234`: | ||
/// | ||
/// ``` | ||
/// # use console_subscriber::Builder; | ||
/// use std::net::Ipv4Addr; | ||
/// let builder = Builder::default().server_addr((Ipv4Addr::LOCALHOST, 1234)); | ||
/// ``` | ||
/// | ||
/// Connect to the UDS address `/tmp/tokio-console`: | ||
/// | ||
/// ``` | ||
/// # use console_subscriber::Builder; | ||
/// use std::path::Path; | ||
/// let builder = Builder::default().server_addr(Path::new("/tmp/tokio-console")); | ||
/// ``` | ||
hawkw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// | ||
/// [environment variable]: `Builder::with_default_env` | ||
pub fn server_addr(self, server_addr: impl Into<SocketAddr>) -> Self { | ||
/// [Unix domain socket]: https://en.wikipedia.org/wiki/Unix_domain_socket | ||
pub fn server_addr(self, server_addr: impl Into<ServerAddr>) -> Self { | ||
hawkw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Self { | ||
server_addr: server_addr.into(), | ||
..self | ||
|
@@ -231,11 +259,14 @@ impl Builder { | |
} | ||
|
||
if let Ok(bind) = std::env::var("TOKIO_CONSOLE_BIND") { | ||
self.server_addr = bind | ||
.to_socket_addrs() | ||
.expect("TOKIO_CONSOLE_BIND must be formatted as HOST:PORT, such as localhost:4321") | ||
.next() | ||
.expect("tokio console could not resolve TOKIO_CONSOLE_BIND"); | ||
self.server_addr = ServerAddr::Tcp( | ||
bind.to_socket_addrs() | ||
.expect( | ||
"TOKIO_CONSOLE_BIND must be formatted as HOST:PORT, such as localhost:4321", | ||
) | ||
.next() | ||
.expect("tokio console could not resolve TOKIO_CONSOLE_BIND"), | ||
); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @hawkw do you think this should support UDS addresses too? E.g., by detecting the presence of a leading /, or the absence of a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, my preference is to have this env var only configure a TCP socket, because it seems unfortunate to have a potential typo in the environment variable silently switch from TCP to UDS when that might not actually be desired. Instead, I think we might want to consider adding a separate environment variable to configure serving over Unix sockets. It would be fine to add that env var in this branch, or in a follow-up PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'll leave that to a different PR, then! |
||
} | ||
|
||
if let Some(interval) = duration_from_env("TOKIO_CONSOLE_PUBLISH_INTERVAL") { | ||
|
@@ -456,6 +487,66 @@ impl Builder { | |
} | ||
} | ||
|
||
/// Specifies the address on which a [`Server`] should listen. | ||
/// | ||
hawkw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// This type is passed as an argument to the [`Builder::server_addr`] | ||
/// method, and may be either a TCP socket address, or a [Unix domain socket] | ||
/// (UDS) address. Unix domain sockets are only supported on Unix-compatible | ||
/// operating systems, such as Linux, BSDs, and macOS. | ||
/// | ||
/// [`Server`]: crate::Server | ||
/// [Unix domain socket]: https://en.wikipedia.org/wiki/Unix_domain_socket | ||
#[derive(Clone, Debug)] | ||
hawkw marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#[non_exhaustive] | ||
pub enum ServerAddr { | ||
/// A TCP address. | ||
Tcp(SocketAddr), | ||
/// A Unix socket address. | ||
#[cfg(unix)] | ||
Unix(PathBuf), | ||
} | ||
|
||
impl From<SocketAddr> for ServerAddr { | ||
fn from(addr: SocketAddr) -> ServerAddr { | ||
ServerAddr::Tcp(addr) | ||
} | ||
} | ||
|
||
impl From<SocketAddrV4> for ServerAddr { | ||
fn from(addr: SocketAddrV4) -> ServerAddr { | ||
ServerAddr::Tcp(addr.into()) | ||
} | ||
} | ||
|
||
impl From<SocketAddrV6> for ServerAddr { | ||
fn from(addr: SocketAddrV6) -> ServerAddr { | ||
ServerAddr::Tcp(addr.into()) | ||
} | ||
} | ||
|
||
impl<I> From<(I, u16)> for ServerAddr | ||
where | ||
I: Into<IpAddr>, | ||
{ | ||
fn from(pieces: (I, u16)) -> ServerAddr { | ||
ServerAddr::Tcp(pieces.into()) | ||
} | ||
} | ||
|
||
#[cfg(unix)] | ||
impl From<PathBuf> for ServerAddr { | ||
fn from(path: PathBuf) -> ServerAddr { | ||
ServerAddr::Unix(path) | ||
} | ||
} | ||
|
||
#[cfg(unix)] | ||
impl<'a> From<&'a Path> for ServerAddr { | ||
fn from(path: &'a Path) -> ServerAddr { | ||
ServerAddr::Unix(path.to_path_buf()) | ||
} | ||
} | ||
|
||
/// Initializes the console [tracing `Subscriber`][sub] and starts the console | ||
/// subscriber [`Server`] on its own background thread. | ||
/// | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this documentation should be updated to state that the provided address can be a TCP address, or (on Unix systems) a UDS address. It would be nice to show examples of both usages in this method's documentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.