mirror of
https://github.com/YGGverse/htcount.git
synced 2026-03-31 17:15:37 +00:00
implement match_time argument, make some optimizations
This commit is contained in:
parent
c35e07986f
commit
7d0db3f8ec
5 changed files with 36 additions and 12 deletions
|
|
@ -12,4 +12,5 @@ repository = "https://github.com/YGGverse/htcount"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
chrono = "0.4"
|
||||||
clap = { version = "4.5", features = ["derive"] }
|
clap = { version = "4.5", features = ["derive"] }
|
||||||
|
|
|
||||||
16
README.md
16
README.md
|
|
@ -50,19 +50,22 @@ htcount --source /var/log/nginx/access.log\
|
||||||
|
|
||||||
[default: nginx]
|
[default: nginx]
|
||||||
|
|
||||||
--export-json <EXPORT_JSON>
|
--export-json <EXPORT_JSON>
|
||||||
Export results to JSON file (e.g. `/path/to/stats.json`)
|
Export results to JSON file (e.g. `/path/to/stats.json`)
|
||||||
|
|
||||||
--export-svg <EXPORT_SVG>
|
--export-svg <EXPORT_SVG>
|
||||||
Export results to SVG file (e.g. `/path/to/badge.svg`)
|
Export results to SVG file (e.g. `/path/to/badge.svg`)
|
||||||
|
|
||||||
* use `{hits}` / `{hosts}` pattern to replace parsed values
|
* use `{hits}` / `{hosts}` pattern to replace parsed values
|
||||||
|
|
||||||
--template-svg <TEMPLATE_SVG>
|
--template-svg <TEMPLATE_SVG>
|
||||||
Use custom SVG file template with `{hits}` / `{hosts}` placeholders
|
Use custom SVG file template with `{hits}` / `{hosts}` placeholders
|
||||||
|
|
||||||
[default: default/counter.svg]
|
[default: default/counter.svg]
|
||||||
|
|
||||||
|
-m, --match-time <MATCH_TIME>
|
||||||
|
Filter records match time pattern (e.g. `%d/%b/%Y`)
|
||||||
|
|
||||||
-c, --capacity <CAPACITY>
|
-c, --capacity <CAPACITY>
|
||||||
Expected memory index capacity
|
Expected memory index capacity
|
||||||
|
|
||||||
|
|
@ -86,7 +89,6 @@ htcount --source /var/log/nginx/access.log\
|
||||||
Print version
|
Print version
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### systemd
|
### systemd
|
||||||
|
|
||||||
``` /etc/systemd/system/htcount.service
|
``` /etc/systemd/system/htcount.service
|
||||||
|
|
@ -101,8 +103,9 @@ Type=simple
|
||||||
ExecStart=/usr/local/bin/htcount --source /var/log/nginx/access.log\
|
ExecStart=/usr/local/bin/htcount --source /var/log/nginx/access.log\
|
||||||
--export-svg /var/www/htcount/visitors.svg\
|
--export-svg /var/www/htcount/visitors.svg\
|
||||||
--template-svg /path/to/default/template.svg\
|
--template-svg /path/to/default/template.svg\
|
||||||
--ignore-host 127.0.0.1
|
--ignore-host 127.0.0.1\
|
||||||
--ignore-host 127.0.0.2
|
--ignore-host 127.0.0.2\
|
||||||
|
--match-time %d/%b/%Y\
|
||||||
--update 3600\
|
--update 3600\
|
||||||
--debug n
|
--debug n
|
||||||
StandardOutput=null
|
StandardOutput=null
|
||||||
|
|
@ -114,6 +117,7 @@ WantedBy=multi-user.target
|
||||||
* make sure `/var/www/htcount` exists
|
* make sure `/var/www/htcount` exists
|
||||||
* replace `/path/to/default/template.svg` with your value
|
* replace `/path/to/default/template.svg` with your value
|
||||||
* use `ignore-host` to skip local host requests
|
* use `ignore-host` to skip local host requests
|
||||||
|
* `match-time %d/%b/%Y` today records only
|
||||||
|
|
||||||
* `systemctl daemon-reload` - update configuration
|
* `systemctl daemon-reload` - update configuration
|
||||||
* `systemctl enable` - launch on system startup
|
* `systemctl enable` - launch on system startup
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,10 @@ pub struct Argument {
|
||||||
#[arg(long, default_value_t = String::from("default/counter.svg"))]
|
#[arg(long, default_value_t = String::from("default/counter.svg"))]
|
||||||
pub template_svg: String,
|
pub template_svg: String,
|
||||||
|
|
||||||
|
/// Filter records match time pattern (e.g. `%d/%b/%Y`)
|
||||||
|
#[arg(short, long)]
|
||||||
|
pub match_time: Option<String>,
|
||||||
|
|
||||||
/// Expected memory index capacity
|
/// Expected memory index capacity
|
||||||
#[arg(short, long, default_value_t = 100)]
|
#[arg(short, long, default_value_t = 100)]
|
||||||
pub capacity: usize,
|
pub capacity: usize,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
pub fn info(message: String) {
|
pub fn info(message: &str) {
|
||||||
println!("[{}] [info] {message}", now())
|
println!("[{}] [info] {message}", now())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
25
src/main.rs
25
src/main.rs
|
|
@ -15,6 +15,10 @@ fn main() -> anyhow::Result<()> {
|
||||||
argument::Argument::parse()
|
argument::Argument::parse()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let match_time = argument
|
||||||
|
.match_time
|
||||||
|
.map(|ref t| chrono::Local::now().format(t).to_string());
|
||||||
|
|
||||||
// parse some arguments once
|
// parse some arguments once
|
||||||
let is_debug_i = argument.debug.contains("i");
|
let is_debug_i = argument.debug.contains("i");
|
||||||
let is_debug_d = argument.debug.contains("d");
|
let is_debug_d = argument.debug.contains("d");
|
||||||
|
|
@ -24,12 +28,12 @@ fn main() -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_debug_i {
|
if is_debug_i {
|
||||||
debug::info("Crawler started".into());
|
debug::info("Crawler started");
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if is_debug_i {
|
if is_debug_i {
|
||||||
debug::info("Index queue begin...".into());
|
debug::info("Index queue begin...");
|
||||||
}
|
}
|
||||||
|
|
||||||
let file = File::open(&argument.source)?;
|
let file = File::open(&argument.source)?;
|
||||||
|
|
@ -38,7 +42,18 @@ fn main() -> anyhow::Result<()> {
|
||||||
let mut index: HashMap<String, usize> = HashMap::with_capacity(argument.capacity);
|
let mut index: HashMap<String, usize> = HashMap::with_capacity(argument.capacity);
|
||||||
|
|
||||||
'l: for line in reader.lines() {
|
'l: for line in reader.lines() {
|
||||||
let host = line?
|
let l = line?;
|
||||||
|
|
||||||
|
if let Some(ref t) = match_time {
|
||||||
|
if !l.contains(t) {
|
||||||
|
if is_debug_d {
|
||||||
|
debug::info(&format!("Record time mismatch time filter {t}"))
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let host = l
|
||||||
.split_whitespace()
|
.split_whitespace()
|
||||||
.next()
|
.next()
|
||||||
.map(|s| s.into())
|
.map(|s| s.into())
|
||||||
|
|
@ -47,7 +62,7 @@ fn main() -> anyhow::Result<()> {
|
||||||
for h in &argument.ignore_host {
|
for h in &argument.ignore_host {
|
||||||
if h == &host {
|
if h == &host {
|
||||||
if is_debug_d {
|
if is_debug_d {
|
||||||
debug::info(format!("Host `{h}` ignored by settings"))
|
debug::info(&format!("Host `{h}` ignored by settings"))
|
||||||
}
|
}
|
||||||
continue 'l;
|
continue 'l;
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +75,7 @@ fn main() -> anyhow::Result<()> {
|
||||||
let hits: usize = index.values().sum();
|
let hits: usize = index.values().sum();
|
||||||
|
|
||||||
if is_debug_i {
|
if is_debug_i {
|
||||||
debug::info(format!(
|
debug::info(&format!(
|
||||||
"Index queue completed:\n{}\n\thosts: {} / hits: {}, await {} seconds to continue...",
|
"Index queue completed:\n{}\n\thosts: {} / hits: {}, await {} seconds to continue...",
|
||||||
if is_debug_d {
|
if is_debug_d {
|
||||||
let mut b = Vec::with_capacity(hosts);
|
let mut b = Vec::with_capacity(hosts);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue