First working commit

Signed-off-by: Aravinda VK <mail@aravindavk.in>
This commit is contained in:
Aravinda VK 2016-01-04 16:21:41 +05:30
commit d5d7288938
5 changed files with 187 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
target
Cargo.lock

21
Cargo.toml Normal file
View file

@ -0,0 +1,21 @@
[package]
name = "logwatcher"
version = "0.1.0"
authors = ["Aravinda VK <mail@aravindavk.in>"]
description = "A lib to watch log files for new Changes, just like tail -f"
documentation = "https://github.com/aravindavk/logwatcher"
homepage = "https://github.com/aravindavk/logwatcher"
repository = "https://github.com/aravindavk/logwatcher"
readme = "README.md"
keywords = ["log", "watcher", "tail"]
license = "MIT/Apache-2.0"
[lib]
name = "logwatcher"
crate-type = ["rlib"]
[dependencies]

33
README.md Normal file
View file

@ -0,0 +1,33 @@
# Log Watcher
A [Rust](https://www.rust-lang.org/) library to watch the log files.
Note: Tested only in Linux
### Features:
1. Automatically reloads log file when log rotated
2. Calls callback function when new line to parse
### Usage
First, add the following to your `Cargo.toml`
[dependencies]
logwatcher = "0.1"
Add to your code,
extern crate logwatcher;
use logwatcher::LogWatcher;
Create a callback function, which accepts String as input
fn parse_line(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);

109
src/lib.rs Normal file
View file

@ -0,0 +1,109 @@
use std::fs::File;
use std::io::SeekFrom;
use std::io::BufReader;
use std::io::prelude::*;
use std::io;
use std::thread::sleep;
use std::time::Duration;
use std::os::unix::fs::MetadataExt;
use std::io::ErrorKind;
pub struct LogWatcher{
filename: String,
inode: u64,
pos: u64,
reader: BufReader<File>,
finish: bool
}
impl LogWatcher {
pub fn register(filename: String) -> Result<LogWatcher, io::Error> {
let f = match File::open(filename.clone()) {
Ok(x) => x,
Err(err) => return Err(err)
};
let metadata = match f.metadata() {
Ok(x) => x,
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,
inode: metadata.ino(),
pos: pos,
reader: reader,
finish: false})
}
fn reopen_if_log_rotated(&mut self, callback: fn (line: String)){
loop {
match File::open(self.filename.clone()) {
Ok(x) => {
let f = x;
let metadata = match f.metadata() {
Ok(m) => m,
Err(_) => {
sleep(Duration::new(1, 0));
continue;
}
};
if metadata.ino() != self.inode{
self.finish = true;
self.watch(callback);
self.finish = false;
println!("reloading log file");
self.reader = BufReader::new(f);
self.pos = 0;
self.inode = metadata.ino();
}
else{
sleep(Duration::new(1, 0));
}
break;
},
Err(err) => {
if err.kind() == ErrorKind::NotFound{
sleep(Duration::new(1, 0));
continue;
}
}
};
}
}
pub fn watch(&mut self, callback: fn (line: String)) {
loop{
let mut line = String::new();
let resp = self.reader.read_line(&mut line);
match resp{
Ok(len) => {
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;
}
else{
self.reopen_if_log_rotated(callback);
self.reader.seek(SeekFrom::Start(self.pos)).unwrap();
}
}
},
Err(err) => {
println!("{}", err);
}
}
}
}
}
#[test]
fn it_works() {
}

22
src/main.rs Normal file
View file

@ -0,0 +1,22 @@
use std::env::args;
use std::process::exit;
extern crate logwatcher;
use logwatcher::LogWatcher;
fn parse_line(line: String) {
println!("Line {}", line);
}
fn main(){
let filename = match args().nth(1) {
Some(x) => x,
None => {
println!("File name required");
exit(1);
}
};
let mut log_watcher = LogWatcher::register(filename).unwrap();
log_watcher.watch(parse_line);
}