Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions src/aggregators/connections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,24 +156,34 @@ impl Aggregator for ConnectionsAggregator {
);
println!("Total connection failures: {}", self.connection_failures);
println!("Connections by host:");
for (host, count) in &self.connections_by_host {
let mut entries: Vec<_> = self.connections_by_host.iter().collect();
entries.sort_by(|a, b| b.1.cmp(a.1));
for (host, count) in entries {
println!(" {count:>6} {host}");
}
println!("Connections by database:");
for (db, count) in &self.connections_by_database {
let mut entries: Vec<_> = self.connections_by_database.iter().collect();
entries.sort_by(|a, b| b.1.cmp(a.1));
for (db, count) in entries {
println!(" {count:>6} {db}");
}
println!("Connections by user:");
for (user, count) in &self.connections_by_user {
let mut entries: Vec<_> = self.connections_by_user.iter().collect();
entries.sort_by(|a, b| b.1.cmp(a.1));
for (user, count) in entries {
println!(" {count:>6} {user}");
}
println!("Connections by application name:");
for (appname, count) in &self.connections_by_appname {
let mut entries: Vec<_> = self.connections_by_appname.iter().collect();
entries.sort_by(|a, b| b.1.cmp(a.1));
for (appname, count) in entries {
println!(" {count:>6} {appname}");
}
println!("Connections by time bucket:");
for (appname, count) in &self.connection_attempts_by_time_bucket {
println!(" {count:>6} {appname}");
let mut entries: Vec<_> = self.connection_attempts_by_time_bucket.iter().collect();
entries.sort_by(|a, b| b.1.cmp(a.1));
for (bucket, count) in entries {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Connections by time bucket:" would need some kind of "top" limit still not to overflow the viewport for large logfiles (20 time slots maybe?). Looks good otherwise! @gintsgints

Image

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine three options here:

  • leave this to user to pipe output to more
  • implement option --limit for top command
  • rework this to be TUI application (like TOP :) )

println!(" {count:>6} {bucket}");
}
}

Expand Down
53 changes: 53 additions & 0 deletions tests/connections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,56 @@ fn simple_connection_aggregate() -> Result<(), Box<dyn std::error::Error>> {

Ok(())
}

#[test]
fn connections_output_sorted_by_count() -> Result<(), Box<dyn std::error::Error>> {
let output = Command::new(cargo::cargo_bin!("pgweasel"))
.args(["conn", "./tests/files/connections.log"])
.output()?;

assert!(output.status.success());
let stdout = String::from_utf8(output.stdout)?;

let count_sorted_sections = [
"Connections by host:",
"Connections by database:",
"Connections by user:",
"Connections by application name:",
"Connections by time bucket:",
];

for section in count_sorted_sections {
let section_start = stdout
.find(section)
.unwrap_or_else(|| panic!("Section '{section}' not found"));
let after_header = &stdout[section_start + section.len()..];
let section_end = after_header
.find("\nConnections by ")
.unwrap_or(after_header.len());
let section_text = &after_header[..section_end];

let counts: Vec<u16> = section_text
.lines()
.filter_map(|line| {
let trimmed = line.trim();
if trimmed.is_empty() {
return None;
}
trimmed.split_whitespace().next()?.parse::<u16>().ok()
})
.collect();

assert!(
counts.len() > 1,
"Section '{section}' should have more than one entry for sorting to matter"
);
for i in 1..counts.len() {
assert!(
counts[i - 1] >= counts[i],
"Section '{section}' not sorted descending: {counts:?}"
);
}
}

Ok(())
}
File renamed without changes.