From d5d7288938c5364cddb311c8920e33523d3f0db2 Mon Sep 17 00:00:00 2001 From: Aravinda VK Date: Mon, 4 Jan 2016 16:21:41 +0530 Subject: [PATCH] First working commit Signed-off-by: Aravinda VK --- .gitignore | 2 + Cargo.toml | 21 ++++++++++ README.md | 33 ++++++++++++++++ src/lib.rs | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 22 +++++++++++ 5 files changed, 187 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 src/lib.rs create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a9d37c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..2743d0c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "logwatcher" +version = "0.1.0" +authors = ["Aravinda VK "] + +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] diff --git a/README.md b/README.md new file mode 100644 index 0000000..ffbb6bf --- /dev/null +++ b/README.md @@ -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); + diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..27ba77c --- /dev/null +++ b/src/lib.rs @@ -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, + finish: bool +} + +impl LogWatcher { + pub fn register(filename: String) -> Result { + 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() { +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..d3ba7bc --- /dev/null +++ b/src/main.rs @@ -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); +}