First working commit
Signed-off-by: Aravinda VK <mail@aravindavk.in>
This commit is contained in:
commit
d5d7288938
5 changed files with 187 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
target
|
||||
Cargo.lock
|
||||
21
Cargo.toml
Normal file
21
Cargo.toml
Normal 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
33
README.md
Normal 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
109
src/lib.rs
Normal 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
22
src/main.rs
Normal 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);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue