Skip to content

Commit 28bcd7e

Browse files
authored
Merge pull request #17 from lucab/to-upstream/journal-matches
journal: add support for match filters
2 parents c57e00d + 84cc2ee commit 28bcd7e

File tree

2 files changed

+66
-5
lines changed

2 files changed

+66
-5
lines changed

src/journal.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use log::{self, Log, LogRecord, LogLocation, LogLevelFilter, SetLoggerError};
33
use std::{fmt, io, ptr, result};
44
use std::collections::BTreeMap;
55
use std::io::ErrorKind::InvalidData;
6+
use std::os::raw::c_void;
67
use ffi::array_to_iovecs;
78
use ffi::id128::sd_id128_t;
89
use ffi::journal as ffi;
@@ -152,7 +153,7 @@ impl Journal {
152153

153154
/// Read the next record from the journal. Returns `Ok(None)` if there
154155
/// are no more records to read.
155-
pub fn next_record(&self) -> Result<Option<JournalRecord>> {
156+
pub fn next_record(&mut self) -> Result<Option<JournalRecord>> {
156157
if sd_try!(ffi::sd_journal_next(self.j)) == 0 {
157158
return Ok(None);
158159
}
@@ -178,7 +179,7 @@ impl Journal {
178179

179180
/// Seek to a specific position in journal. On success, returns a cursor
180181
/// to the current entry.
181-
pub fn seek(&self, seek: JournalSeek) -> Result<String> {
182+
pub fn seek(&mut self, seek: JournalSeek) -> Result<String> {
182183
match seek {
183184
JournalSeek::Head => sd_try!(ffi::sd_journal_seek_head(self.j)),
184185
JournalSeek::Current => 0,
@@ -225,6 +226,38 @@ impl Journal {
225226
sd_try!(ffi::sd_journal_get_realtime_usec(self.j, &mut timestamp_us));
226227
Ok(system_time_from_realtime_usec(timestamp_us))
227228
}
229+
230+
/// Adds a match by which to filter the entries of the journal.
231+
/// If a match is applied, only entries with this field set will be iterated.
232+
pub fn match_add<T: Into<Vec<u8>>>(&mut self, key: &str, val: T) -> Result<&mut Journal> {
233+
let mut filter = Vec::<u8>::from(key);
234+
filter.push('=' as u8);
235+
filter.extend(val.into());
236+
let data = filter.as_ptr() as *const c_void;
237+
let datalen = filter.len() as size_t;
238+
sd_try!(ffi::sd_journal_add_match(self.j, data, datalen));
239+
Ok(self)
240+
}
241+
242+
/// Inserts a disjunction (i.e. logical OR) in the match list.
243+
pub fn match_or(&mut self) -> Result<&mut Journal> {
244+
sd_try!(ffi::sd_journal_add_disjunction(self.j));
245+
Ok(self)
246+
}
247+
248+
/// Inserts a conjunction (i.e. logical AND) in the match list.
249+
pub fn match_and(&mut self) -> Result<&mut Journal> {
250+
sd_try!(ffi::sd_journal_add_conjunction(self.j));
251+
Ok(self)
252+
}
253+
254+
/// Flushes all matches, disjunction and conjunction terms.
255+
/// After this call all filtering is removed and all entries in
256+
/// the journal will be iterated again.
257+
pub fn match_flush(&mut self) -> Result<&mut Journal> {
258+
unsafe { ffi::sd_journal_flush_matches(self.j) };
259+
Ok(self)
260+
}
228261
}
229262

230263
impl Drop for Journal {

tests/journal.rs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ fn cursor() {
3535
return;
3636
}
3737

38-
let j = journal::Journal::open(journal::JournalFiles::All, false, false).unwrap();
38+
let mut j = journal::Journal::open(journal::JournalFiles::All, false, false).unwrap();
3939
log!(log::LogLevel::Info, "rust-systemd test_seek entry");
4040
assert!(j.seek(journal::JournalSeek::Head).is_ok());
4141
let _s = j.cursor().unwrap();
@@ -47,7 +47,7 @@ fn ts() {
4747
return;
4848
}
4949

50-
let j = journal::Journal::open(journal::JournalFiles::All, false, false).unwrap();
50+
let mut j = journal::Journal::open(journal::JournalFiles::All, false, false).unwrap();
5151
log!(log::LogLevel::Info, "rust-systemd test_seek entry");
5252
assert!(j.seek(journal::JournalSeek::Head).is_ok());
5353
let _s = j.timestamp().unwrap();
@@ -56,7 +56,7 @@ fn ts() {
5656

5757
#[test]
5858
fn test_seek() {
59-
let j = journal::Journal::open(journal::JournalFiles::All, false, false).unwrap();
59+
let mut j = journal::Journal::open(journal::JournalFiles::All, false, false).unwrap();
6060
if ! have_journal() {
6161
return;
6262
}
@@ -71,3 +71,31 @@ fn test_seek() {
7171
assert!(j.seek(journal::JournalSeek::Tail).is_ok());
7272
assert!(j.next_record().is_ok());
7373
}
74+
75+
#[test]
76+
fn test_simple_match() {
77+
if ! have_journal() {
78+
return;
79+
}
80+
let key = "RUST_TEST_MARKER";
81+
let value = "RUST_SYSTEMD_SIMPLE_MATCH";
82+
let msg = "MESSAGE=rust-systemd test_match";
83+
let filter = format!("{}={}", key, value);
84+
let mut j = journal::Journal::open(journal::JournalFiles::All, false, false).unwrap();
85+
86+
// check for positive matches
87+
assert!(j.seek(journal::JournalSeek::Tail).is_ok());
88+
journal::send(&[&filter, &msg]);
89+
assert!(j.match_flush().unwrap().match_add(key, value).is_ok());
90+
let r = j.next_record().unwrap();
91+
assert!(r.is_some());
92+
let entry = r.unwrap();
93+
let entryval = entry.get(key);
94+
assert!(entryval.is_some());
95+
assert_eq!(entryval.unwrap(), value);
96+
97+
// check for negative matches
98+
assert!(j.seek(journal::JournalSeek::Tail).is_ok());
99+
journal::send(&[&msg]);
100+
assert!(j.next_record().unwrap().is_none());
101+
}

0 commit comments

Comments
 (0)