*** Wartungsfenster jeden ersten Mittwoch vormittag im Monat ***

Skip to content
Snippets Groups Projects
Commit 262b9b47 authored by Moser, Maximilian's avatar Moser, Maximilian
Browse files

Update rust reporting implementation

parent 30384db2
No related branches found
No related tags found
1 merge request!4Add Rust implementation to log parsing
......@@ -119,6 +119,12 @@ dependencies = [
"syn",
]
[[package]]
name = "either"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]]
name = "iana-time-zone"
version = "0.1.53"
......@@ -143,6 +149,15 @@ dependencies = [
"cxx-build",
]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "js-sys"
version = "0.3.61"
......@@ -187,7 +202,9 @@ name = "nginx-parser"
version = "0.1.0"
dependencies = [
"chrono",
"itertools",
"regex",
"urlencoding",
]
[[package]]
......@@ -299,6 +316,12 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "urlencoding"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
......
......@@ -7,4 +7,6 @@ edition = "2021"
[dependencies]
chrono = "0.4.23"
itertools = "0.10.5"
regex = "1.7.1"
urlencoding = "2.1.2"
use chrono::DateTime;
use chrono::{DateTime, FixedOffset};
use itertools::Itertools;
use regex::Regex;
use std::collections::HashMap;
use std::io::{self, BufRead};
struct RecordInteraction {
views: i32,
exports: i32,
file_downloads: HashMap<String, i32>,
}
impl RecordInteraction {
fn zero() -> Self {
RecordInteraction {
views: 0,
exports: 0,
file_downloads: HashMap::new(),
}
}
}
fn main() {
// TODO: argument parsing
let recid_prefix = "";
let file_download_regex =
Regex::new(r"GET /records/(\w+\-\w+)/files/(.*?)(\?download=1|\s)").unwrap();
Regex::new(r"GET /records/(\w+\-\w+)/files/(.*?)(\?download=1|\?preview=\d|\s)").unwrap();
let export_regex = Regex::new(r"GET /records/(\w+\-\w+)/export/").unwrap();
let landing_page_regex = Regex::new(r"GET /records/(\w+\-\w+)\s").unwrap();
let timestamp_regex =
Regex::new(r"\[(\d{2}/\w{3}/\d{4}:\d{2}:\d{2}:\d{2}\s+.?\d{0,4})\]").unwrap();
let mut record_views = HashMap::new();
let mut file_downloads = HashMap::new();
let mut record_exports = HashMap::new();
let mut record_interactions = HashMap::new();
let mut start_timestamp: Option<DateTime<FixedOffset>> = None;
let mut end_timestamp: Option<DateTime<FixedOffset>> = None;
for line in io::stdin().lock().lines() {
let line = line.unwrap();
......@@ -27,6 +45,10 @@ fn main() {
if timestamp_regex.is_match(&line) {
let capture = timestamp_regex.captures(&line).unwrap();
timestamp = DateTime::parse_from_str(&capture[1], "%d/%b/%Y:%H:%M:%S %z").unwrap();
end_timestamp = Some(timestamp);
if start_timestamp == None {
start_timestamp = Some(timestamp);
}
} else {
continue;
}
......@@ -36,30 +58,53 @@ fn main() {
let cap = landing_page_regex.captures(&line).unwrap();
let recid = &cap[1];
let entry = record_views.entry(String::from(recid)).or_insert(0);
*entry += 1;
let entry = record_interactions
.entry(String::from(recid))
.or_insert(RecordInteraction::zero());
entry.views += 1;
} else if file_download_regex.is_match(&line) {
let cap = file_download_regex.captures(&line).unwrap();
let recid = &cap[1];
let file = &cap[2];
let entry = file_downloads
.entry((String::from(recid), String::from(file)))
.or_insert(0);
*entry += 1;
let file = urlencoding::decode(&cap[2]).unwrap();
let entry = record_interactions
.entry(String::from(recid))
.or_insert(RecordInteraction::zero());
let count = entry.file_downloads.entry(String::from(file)).or_insert(0);
*count += 1;
} else if export_regex.is_match(&line) {
let cap = export_regex.captures(&line).unwrap();
let recid = &cap[1];
let entry = record_exports.entry(String::from(recid)).or_insert(0);
*entry += 1;
let entry = record_interactions
.entry(String::from(recid))
.or_insert(RecordInteraction::zero());
entry.exports += 1;
}
}
// TODO: sort & pretty-print the results
println!("record views: {:?}", record_views);
println!("file downloads: {:?}", file_downloads);
println!("record exports: {:?}", record_exports);
let start = match start_timestamp {
Some(timestamp) => timestamp.to_rfc3339(),
None => panic!("No proper logs could be parsed!"),
};
let end = end_timestamp.unwrap().to_rfc3339();
println!("Start: {}", start);
println!("End: {}", end);
println!("======={}", "=".repeat(end.len()));
// print the results
for recid in record_interactions.keys().sorted() {
let interactions = &record_interactions[recid];
println!(
"\n{}{} - {} views, {} exports",
recid_prefix, recid, interactions.views, interactions.exports
);
for file in interactions.file_downloads.keys().sorted() {
println!(
"\t{}: {} downloads",
file, interactions.file_downloads[file]
);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment