Skip to content

Commit 284003e

Browse files
Allow the MsgFormat3164 to be changed when using the SyslogBuilder.
1 parent 420e9a3 commit 284003e

File tree

2 files changed

+71
-8
lines changed

2 files changed

+71
-8
lines changed

lib.rs

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ impl<B: Write, F: MsgFormat3164> Streamer3164<B, F> {
116116
}
117117
}
118118

119-
impl<B: Write> Drain for Streamer3164<B> {
119+
impl<B: Write, F: MsgFormat3164> Drain for Streamer3164<B, F> {
120120
type Err = syslog::Error;
121121
type Ok = ();
122122

@@ -509,7 +509,7 @@ impl Default for SyslogKind {
509509
}
510510
}
511511

512-
/// Builder pattern for constructing a syslog
512+
/// Builder pattern for constructing a syslog drain that uses RFC 3164 (BSD) style.
513513
///
514514
/// All settings have default values. `SyslogBuilder::new().start()` will give you a sensibly configured log drain, but you might especially want to customize the `facility`.
515515
///
@@ -519,30 +519,47 @@ impl Default for SyslogKind {
519519
/// * Level: all
520520
/// * Transport (Unix-like platforms): Unix socket `/dev/log` or `/var/run/log`
521521
/// * Transport (other platforms): UDP to 127.0.0.1:514
522+
/// * Message format: [`BasicMsgFormat3164`]
522523
/// * Process name: the file name portion of [`std::env::current_exe()`]
523524
/// * PID: [`std::process::id()`]
524525
/// * Hostname: [`hostname::get()`]
525526
///
527+
/// [`BasicMsgFormat3164`]: struct.BasicMsgFormat3164.html
526528
/// [`std::env::current_exe()`]: https://doc.rust-lang.org/std/env/fn.current_exe.html
527529
/// [`std::process::id()`]: https://doc.rust-lang.org/std/process/fn.id.html
528530
/// [`hostname::get()`]: https://docs.rs/hostname/0.3.0/hostname/fn.get.html
529-
#[derive(Clone, Debug, Default)]
530-
pub struct SyslogBuilder {
531+
#[derive(Clone, Debug)]
532+
pub struct SyslogBuilder<F: MsgFormat3164 = BasicMsgFormat3164> {
531533
facility: Option<syslog::Facility>,
532534
hostname: Option<String>,
533535
level: Option<Level>,
534536
logkind: SyslogKind,
537+
msg_format: F,
535538
pid: Option<i32>,
536539
process: Option<String>,
537540
}
541+
impl Default for SyslogBuilder {
542+
fn default() -> Self {
543+
SyslogBuilder {
544+
facility: None,
545+
hostname: None,
546+
level: None,
547+
logkind: SyslogKind::default(),
548+
msg_format: BasicMsgFormat3164,
549+
pid: None,
550+
process: None,
551+
}
552+
}
553+
}
538554
impl SyslogBuilder {
539555
/// Build a default logger
540556
///
541557
/// By default this will attempt to connect to (in order)
542558
pub fn new() -> SyslogBuilder {
543559
Self::default()
544560
}
545-
561+
}
562+
impl<F: MsgFormat3164> SyslogBuilder<F> {
546563
/// Set syslog Facility
547564
///
548565
/// The default facility, as per [POSIX], is `LOG_USER`.
@@ -579,6 +596,20 @@ impl SyslogBuilder {
579596
self
580597
}
581598

599+
/// Set the `MsgFormat3164` to use for formatting key-value pairs in log messages.
600+
pub fn msg_format<F2: MsgFormat3164>(self, msg_format: F2) -> SyslogBuilder<F2> {
601+
// This changes the `F` type parameter of this `SyslogBuilder`, so we can't just change the `msg_format` field. We have to make a whole new `SyslogBuilder` with the new `msg_format`.
602+
SyslogBuilder {
603+
facility: self.facility,
604+
hostname: self.hostname,
605+
level: self.level,
606+
logkind: self.logkind,
607+
msg_format,
608+
pid: self.pid,
609+
process: self.process,
610+
}
611+
}
612+
582613
/// Remote UDP syslogging
583614
pub fn udp(self, local: SocketAddr, host: SocketAddr) -> Self {
584615
let mut s = self;
@@ -607,7 +638,7 @@ impl SyslogBuilder {
607638
/// Start running
608639
///
609640
/// This method wraps the created `Streamer3164` in a `Mutex`. (For an explanation of why, see the `Streamer3164` documentation.) To get a `Streamer3164` without a `Mutex` wrapper, use the `start_single_threaded` method instead.
610-
pub fn start(self) -> syslog::Result<Mutex<Streamer3164<syslog::LoggerBackend>>> {
641+
pub fn start(self) -> syslog::Result<Mutex<Streamer3164<syslog::LoggerBackend, F>>> {
611642
self.start_single_threaded().map(|streamer| Mutex::new(streamer))
612643
}
613644

@@ -616,7 +647,7 @@ impl SyslogBuilder {
616647
/// Use this if you plan to use [slog-async] or some other synchronization mechanism. Otherwise, use the `start` method instead.
617648
///
618649
/// [slog-async]: https://docs.rs/slog-async/2/slog_async/index.html
619-
pub fn start_single_threaded(self) -> syslog::Result<Streamer3164<syslog::LoggerBackend>> {
650+
pub fn start_single_threaded(self) -> syslog::Result<Streamer3164<syslog::LoggerBackend, F>> {
620651
let formatter = syslog::Formatter3164 {
621652
facility: self.facility.unwrap_or(Facility::LOG_USER),
622653
hostname: match self.hostname {
@@ -651,7 +682,7 @@ impl SyslogBuilder {
651682
} => syslog::udp(formatter, local, host)?,
652683
SyslogKind::Tcp { server } => syslog::tcp(formatter, server)?,
653684
};
654-
Ok(Streamer3164::new(log))
685+
Ok(Streamer3164::new(log).with_msg_format(self.msg_format))
655686
}
656687
}
657688

tests/test.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,35 @@ fn integration_test_with_builder() {
143143
assert!(s.starts_with("<14>"));
144144
assert!(s.ends_with("test-hostname test-app[123]: Hello, world! [key=\"value\" key2=\"value2\"]"));
145145
}
146+
147+
#[test]
148+
fn integration_test_with_builder_and_msg_format() {
149+
let server = TestServer::new();
150+
151+
{
152+
// Set up a logger.
153+
let drain = SyslogBuilder::new()
154+
.hostname("test-hostname")
155+
.process("test-app")
156+
.pid(123)
157+
.udp(server.client_addr, server.server_addr)
158+
.msg_format(NullMsgFormat3164)
159+
.start()
160+
.expect("couldn't create syslog logger");
161+
162+
let logger = Logger::root_typed(drain.fuse(), o!("key" => "value"));
163+
164+
// Log a test message.
165+
info!(logger, "Hello, world!"; "key2" => "value2");
166+
}
167+
168+
// Get the logs received by the server thread.
169+
let logs = server.finish();
170+
171+
// Check that the logs were correct.
172+
assert_eq!(logs.len(), 1);
173+
174+
let s = String::from_utf8(logs[0].to_vec()).expect("log packet contains invalid UTF-8");
175+
assert!(s.starts_with("<14>"));
176+
assert!(s.ends_with("test-hostname test-app[123]: Hello, world!"));
177+
}

0 commit comments

Comments
 (0)