Compare commits

...

10 commits

Author SHA1 Message Date
Aravinda Vishwanathapura
3ff858cef9
Updated README page to reflect latest changes
Signed-off-by: Aravinda Vishwanathapura <mail@aravindavk.in>
2020-08-21 12:42:11 +05:30
Aravinda Vishwanathapura
49b988cdb0
Format fixes (#9)
```
cargo fmt --all -- --check
```

Signed-off-by: Aravinda Vishwanathapura <mail@aravindavk.in>
2020-08-21 12:31:50 +05:30
Kyle Wood
811f7783ab
Allow any generic Path as input to register (#7)
* Allow any generic Path as input to register

Previously only String was allowed, which can be annoying for clients
which already have a PathBuf or Path object. The generic type
AsRef<Path> is the standard for APIs which have file path parameters, as
it works across both owned and un-owned paths. Also, AsRef<Path> allows
Strings and OS specific strings to be used directly as well.

The filename parameter itself is only used for calling File::open(),
which itself also takes in an AsRef<Path> as input.

Signed-off-by: Kyle Wood <https://github.com/DemonWav>
2020-08-21 12:21:41 +05:30
noyez
6f8f9bd75d
Change closure from Fn to FnMut. (#5)
* Using FnMut, so works
* Using FnMut for watch() and reopen_if_log_rotated()
* adding fn to force reopen
* adding actions to closure

Co-authored-by: noyez <brad@bkn.local>
Co-authored-by: noyez <brad@bkn.localdomain>
Co-authored-by: Bradley Noyes <b@noyes.dev>
2020-08-21 12:12:11 +05:30
Aravinda VK
7c288c8d1e
Merge pull request #6 from romibuzi/formatting
Formatting with rustfmt
2018-11-29 17:49:58 +05:30
Romain Ardiet
e83d3b67bb Highlight code blocks inside Readme 2018-11-29 12:07:22 +01:00
Romain Ardiet
ab587c98e4 Apply and configure rustfmt in the project 2018-11-29 12:07:09 +01:00
Aravinda VK
e19805f872 Merge pull request #3 from KenanSulayman/master
Use closures
2016-11-13 11:52:37 +05:30
Kenan Sulayman
c08f460021
Use closures 2016-11-04 02:24:17 +01:00
Aravinda VK
f475dc2746 Added .travis.yml file and Build status
Signed-off-by: Aravinda VK <mail@aravindavk.in>
2016-01-04 16:35:44 +05:30
5 changed files with 91 additions and 63 deletions

10
.travis.yml Normal file
View file

@ -0,0 +1,10 @@
language: rust
before_script:
- rustup component add rustfmt-preview
script:
- cargo fmt --all -- --check
- cargo build
- cargo test

View file

@ -1,6 +1,6 @@
[package] [package]
name = "logwatcher" name = "logwatcher"
version = "0.1.0" version = "0.1.1"
authors = ["Aravinda VK <mail@aravindavk.in>"] authors = ["Aravinda VK <mail@aravindavk.in>"]
description = "A lib to watch log files for new Changes, just like tail -f" description = "A lib to watch log files for new Changes, just like tail -f"

View file

@ -1,5 +1,7 @@
# Log Watcher # Log Watcher
[![Build Status](https://travis-ci.org/aravindavk/logwatcher.svg?branch=master)](https://travis-ci.org/aravindavk/logwatcher)
A [Rust](https://www.rust-lang.org/) library to watch the log files. A [Rust](https://www.rust-lang.org/) library to watch the log files.
Note: Tested only in Linux Note: Tested only in Linux
@ -12,22 +14,25 @@ Note: Tested only in Linux
First, add the following to your `Cargo.toml` First, add the following to your `Cargo.toml`
```toml
[dependencies] [dependencies]
logwatcher = "0.1" logwatcher = "0.1"
```
Add to your code, Add to your code,
```rust
extern crate logwatcher; extern crate logwatcher;
use logwatcher::LogWatcher; use logwatcher::LogWatcher;
```
Create a callback function, which accepts String as input Register the logwatcher, pass a closure and watch it!
fn parse_line(line: String) {
println!("Line {}", line);
}
Register the logwatcher and watch it!
```rust
let mut log_watcher = LogWatcher::register("/var/log/check.log".to_string()).unwrap(); let mut log_watcher = LogWatcher::register("/var/log/check.log".to_string()).unwrap();
log_watcher.watch(parse_line);
log_watcher.watch(&mut move |line: String| {
println!("Line {}", line);
LogWatcherAction::None
});
```

View file

@ -1,46 +1,57 @@
use std::fs::File; use std::fs::File;
use std::io::SeekFrom;
use std::io::BufReader;
use std::io::prelude::*;
use std::io; use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::ErrorKind;
use std::io::SeekFrom;
use std::os::unix::fs::MetadataExt;
use std::path::Path;
use std::thread::sleep; use std::thread::sleep;
use std::time::Duration; use std::time::Duration;
use std::os::unix::fs::MetadataExt;
use std::io::ErrorKind; pub enum LogWatcherAction {
None,
SeekToEnd,
}
pub struct LogWatcher { pub struct LogWatcher {
filename: String, filename: String,
inode: u64, inode: u64,
pos: u64, pos: u64,
reader: BufReader<File>, reader: BufReader<File>,
finish: bool finish: bool,
} }
impl LogWatcher { impl LogWatcher {
pub fn register(filename: String) -> Result<LogWatcher, io::Error> { pub fn register<P: AsRef<Path>>(filename: P) -> Result<LogWatcher, io::Error> {
let f = match File::open(filename.clone()) { let f = match File::open(&filename) {
Ok(x) => x, Ok(x) => x,
Err(err) => return Err(err) Err(err) => return Err(err),
}; };
let metadata = match f.metadata() { let metadata = match f.metadata() {
Ok(x) => x, Ok(x) => x,
Err(err) => return Err(err) Err(err) => return Err(err),
}; };
let mut reader = BufReader::new(f); let mut reader = BufReader::new(f);
let pos = metadata.len(); let pos = metadata.len();
reader.seek(SeekFrom::Start(pos)).unwrap(); reader.seek(SeekFrom::Start(pos)).unwrap();
Ok(LogWatcher{filename: filename, Ok(LogWatcher {
filename: filename.as_ref().to_string_lossy().to_string(),
inode: metadata.ino(), inode: metadata.ino(),
pos: pos, pos: pos,
reader: reader, reader: reader,
finish: false}) finish: false,
})
} }
fn reopen_if_log_rotated(&mut self, callback: fn (line: String)){ fn reopen_if_log_rotated<F: ?Sized>(&mut self, callback: &mut F)
where
F: FnMut(String) -> LogWatcherAction,
{
loop { loop {
match File::open(self.filename.clone()) { match File::open(&self.filename) {
Ok(x) => { Ok(x) => {
let f = x; let f = x;
let metadata = match f.metadata() { let metadata = match f.metadata() {
@ -58,12 +69,11 @@ impl LogWatcher {
self.reader = BufReader::new(f); self.reader = BufReader::new(f);
self.pos = 0; self.pos = 0;
self.inode = metadata.ino(); self.inode = metadata.ino();
} } else {
else{
sleep(Duration::new(1, 0)); sleep(Duration::new(1, 0));
} }
break; break;
}, }
Err(err) => { Err(err) => {
if err.kind() == ErrorKind::NotFound { if err.kind() == ErrorKind::NotFound {
sleep(Duration::new(1, 0)); sleep(Duration::new(1, 0));
@ -74,7 +84,10 @@ impl LogWatcher {
} }
} }
pub fn watch(&mut self, callback: fn (line: String)) { pub fn watch<F: ?Sized>(&mut self, callback: &mut F)
where
F: FnMut(String) -> LogWatcherAction,
{
loop { loop {
let mut line = String::new(); let mut line = String::new();
let resp = self.reader.read_line(&mut line); let resp = self.reader.read_line(&mut line);
@ -83,18 +96,23 @@ impl LogWatcher {
if len > 0 { if len > 0 {
self.pos += len as u64; self.pos += len as u64;
self.reader.seek(SeekFrom::Start(self.pos)).unwrap(); self.reader.seek(SeekFrom::Start(self.pos)).unwrap();
callback(line.replace("\n", "")); match callback(line.replace("\n", "")) {
LogWatcherAction::SeekToEnd => {
println!("SeekToEnd");
self.reader.seek(SeekFrom::End(0)).unwrap();
}
LogWatcherAction::None => {}
}
line.clear(); line.clear();
} else { } else {
if self.finish { if self.finish {
break; break;
} } else {
else{
self.reopen_if_log_rotated(callback); self.reopen_if_log_rotated(callback);
self.reader.seek(SeekFrom::Start(self.pos)).unwrap(); self.reader.seek(SeekFrom::Start(self.pos)).unwrap();
} }
} }
}, }
Err(err) => { Err(err) => {
println!("{}", err); println!("{}", err);
} }
@ -102,8 +120,3 @@ impl LogWatcher {
} }
} }
} }
#[test]
fn it_works() {
}

View file

@ -2,12 +2,7 @@ use std::env::args;
use std::process::exit; use std::process::exit;
extern crate logwatcher; extern crate logwatcher;
use logwatcher::LogWatcher; use logwatcher::{LogWatcher, LogWatcherAction};
fn parse_line(line: String) {
println!("Line {}", line);
}
fn main() { fn main() {
let filename = match args().nth(1) { let filename = match args().nth(1) {
@ -17,6 +12,11 @@ fn main(){
exit(1); exit(1);
} }
}; };
let mut log_watcher = LogWatcher::register(filename).unwrap(); let mut log_watcher = LogWatcher::register(filename).unwrap();
log_watcher.watch(parse_line);
log_watcher.watch(&mut move |line: String| {
println!("Line {}", line);
LogWatcherAction::None
});
} }