///|
pub(all) struct UrlPattern {
pattern : String
count : Int
total_time : Int
total_bytes : Int
} derive(Eq, Debug)
///|
pub fn url_pattern(url : String) -> String {
let path = url_path(url)
let parts = path.split("/").collect()
let mut out = ""
for i = 0; i < parts.length(); i = i + 1 {
if i > 0 {
out = out + "/"
}
let part = parts[i].to_owned()
if part == "" {
out = out + part
} else if looks_numeric(part) {
out = out + ":int"
} else if looks_uuidish(part) {
out = out + ":id"
} else {
out = out + part
}
}
if out == "" {
"/"
} else {
out
}
}
///|
fn looks_numeric(text : String) -> Bool {
text.length() > 0 && text.all(ch => ch >= '0' && ch <= '9')
}
///|
fn looks_uuidish(text : String) -> Bool {
text.length() >= 16 && text.contains("-")
}
///|
pub fn collect_url_patterns(archive : HarArchive) -> Array[UrlPattern] {
let out : Array[UrlPattern] = []
for i = 0; i < archive.log.entries.length(); i = i + 1 {
let entry = archive.log.entries[i]
bump_pattern(
out,
url_pattern(entry.request.url),
entry.time,
entry_bytes(entry),
)
}
out
}
///|
fn bump_pattern(
out : Array[UrlPattern],
pattern : String,
time : Int,
bytes : Int,
) -> Unit {
for i = 0; i < out.length(); i = i + 1 {
if out[i].pattern == pattern {
out[i] = UrlPattern::{
pattern,
count: out[i].count + 1,
total_time: out[i].total_time + time,
total_bytes: out[i].total_bytes + bytes,
}
return
}
}
out.push(UrlPattern::{
pattern,
count: 1,
total_time: time,
total_bytes: bytes,
})
}
///|
pub fn render_url_patterns(patterns : Array[UrlPattern]) -> String {
let mut out = ""
for i = 0; i < patterns.length(); i = i + 1 {
let p = patterns[i]
out = out +
p.pattern +
" count=" +
p.count.to_string() +
" total_ms=" +
p.total_time.to_string() +
" bytes=" +
p.total_bytes.to_string() +
"\n"
}
out
}
///|
pub fn hottest_pattern(patterns : Array[UrlPattern]) -> UrlPattern? {
if patterns.is_empty() {
return None
}
let mut best = patterns[0]
for i = 1; i < patterns.length(); i = i + 1 {
if patterns[i].total_time > best.total_time {
best = patterns[i]
}
}
Some(best)
}
///|
pub fn heaviest_pattern(patterns : Array[UrlPattern]) -> UrlPattern? {
if patterns.is_empty() {
return None
}
let mut best = patterns[0]
for i = 1; i < patterns.length(); i = i + 1 {
if patterns[i].total_bytes > best.total_bytes {
best = patterns[i]
}
}
Some(best)
}