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]
name = "logwatcher"
version = "0.1.0"
version = "0.1.1"
authors = ["Aravinda VK <mail@aravindavk.in>"]
description = "A lib to watch log files for new Changes, just like tail -f"

View file

@ -1,5 +1,7 @@
# 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.
Note: Tested only in Linux
@ -12,22 +14,25 @@ Note: Tested only in Linux
First, add the following to your `Cargo.toml`
[dependencies]
logwatcher = "0.1"
```toml
[dependencies]
logwatcher = "0.1"
```
Add to your code,
extern crate logwatcher;
use logwatcher::LogWatcher;
```rust
extern crate 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) {
```rust
let mut log_watcher = LogWatcher::register("/var/log/check.log".to_string()).unwrap();
log_watcher.watch(&mut move |line: String| {
println!("Line {}", line);
}
Register the logwatcher and watch it!
let mut log_watcher = LogWatcher::register("/var/log/check.log".to_string()).unwrap();
log_watcher.watch(parse_line);
LogWatcherAction::None
});
```

View file

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

View file

@ -2,14 +2,9 @@ use std::env::args;
use std::process::exit;
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) {
Some(x) => x,
None => {
@ -17,6 +12,11 @@ fn main(){
exit(1);
}
};
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
});
}