Skip to content

Expand --nstimes option #421

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 10, 2025
Merged
Changes from 1 commit
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
Next Next commit
Expand --nstimes option
- Extend to all queried name servers: this means that non-queried name servers objects will not appear, with the exception of name servers of the child or parent zone
- Add classification of name servers ("child", "parent", "other"). Note that name servers shared by the child and parent zone will appear in both categories.
- Add number of queries sent per name server
- Add grand total row for query times and query count
- Refactoring
tgreenx committed Jun 10, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit a7bef93413bf4a920a60afd2c4b9d905efc0001f
104 changes: 86 additions & 18 deletions lib/Zonemaster/CLI.pm
Original file line number Diff line number Diff line change
@@ -643,38 +643,106 @@ sub run {

if ( $opt_nstimes ) {
my $zone = Zonemaster::Engine->zone( $domain );
my $max = max map { length( "$_" ) } ( @{ $zone->ns }, q{Server} );
my %all_nss = %{ Zonemaster::Engine::Nameserver::object_cache };
my @zone_nss = @{ $zone->ns };
my @parent_nss = @{ $zone->parent->ns };
my @nss;

foreach my $keys ( keys %all_nss ) {
foreach my $val ( values %{ $all_nss{$keys} } ) {
push @nss, $val if scalar @{ $val->times } > 0;
}
}

my %nss_filter;
@nss_filter{ ( @zone_nss, @parent_nss ) } = ();
my @filtered_nss = grep { ! exists $nss_filter{$_} } @nss;

if ( $opt_json ) {
my @times = ();
foreach my $ns ( @{ $zone->ns } ) {
push @times,
{
'ns' => $ns->string,
'max' => 1000 * $ns->max_time,
'min' => 1000 * $ns->min_time,
'avg' => 1000 * $ns->average_time,
'stddev' => 1000 * $ns->stddev_time,
'median' => 1000 * $ns->median_time,
'total' => 1000 * $ns->sum_time
};
my ( @times, @items ) = ();

sub json_nstimes {
my ( $ns ) = @_;
return {
'ns' => $ns->string,
'max' => 1000 * $ns->max_time,
'min' => 1000 * $ns->min_time,
'avg' => 1000 * $ns->average_time,
'stddev' => 1000 * $ns->stddev_time,
'median' => 1000 * $ns->median_time,
'total' => 1000 * $ns->sum_time,
'count' => scalar @{ $ns->times } };
}

foreach my $ns ( sort @zone_nss ) {
push @items, json_nstimes( $ns );
}
push @times, { 'zone' => \@items } if scalar @items;
@items = ();

foreach my $ns ( sort @parent_nss ) {
push @items, json_nstimes( $ns );
}
push @times, { 'parent' => \@items } if scalar @items;
@items = ();

foreach my $ns ( sort @filtered_nss ) {
push @items, json_nstimes( $ns );
}
push @times, { 'other' => \@items } if scalar @items;

$json_output->{nstimes} = \@times;
}
else {
my $max = max map { length( "$_" ) } ( uniq ( @zone_nss, @parent_nss, @nss ), q{Server} );
print "\n";
printf "%${max}s %s\n", 'Server', ' Max Min Avg Stddev Median Total';
printf "%${max}s %s\n", '=' x $max, ' ======== ======== ======== ======== ======== =========';
printf __("%${max}s %s\n"), 'Server', ' Max Min Avg Stddev Median Total Count';
printf "%${max}s %s\n", '=' x $max, ' ======== ======== ======== ======== ======== ========= =========';

my $total_queries_count = 0;
my $total_queries_times = 0;
my %nss_already_processed;

sub print_nstimes {
my ( $ns, $max, $total_queries_count, $total_queries_times, %nss_already_processed ) = @_;

foreach my $ns ( @{ $zone->ns } ) {
printf "%${max}s ", $ns->string;
printf "%9.2f ", 1000 * $ns->max_time;
printf "%8.2f ", 1000 * $ns->min_time;
printf "%8.2f ", 1000 * $ns->average_time;
printf "%8.2f ", 1000 * $ns->stddev_time;
printf "%8.2f ", 1000 * $ns->median_time;
printf "%9.2f\n", 1000 * $ns->sum_time;
printf "%9.2f ", 1000 * $ns->sum_time;
printf "%9d\n", scalar @{ $ns->times };
$total_queries_count += scalar @{ $ns->times } unless $nss_already_processed{$ns};
$total_queries_times += ( 1000 * $ns->sum_time ) unless $nss_already_processed{$ns};

return $total_queries_count, $total_queries_times, %nss_already_processed;
Copy link
Member

Choose a reason for hiding this comment

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

Isn't it better to move this summation out from print_nstimes and into its own loop?

}

printf __("%s %s\n"), 'Child', '-' x ( ( $max - length 'Child' ) - 1 );
foreach my $ns ( sort @zone_nss ) {
( $total_queries_count, $total_queries_times, %nss_already_processed ) =
print_nstimes( $ns, $max, $total_queries_count, $total_queries_times, %nss_already_processed );
$nss_already_processed{$ns} = 1;
}

printf __("%s %s\n"), 'Parent', '-' x ( ( $max - length 'Parent' ) - 1 );
foreach my $ns ( sort @parent_nss ) {
( $total_queries_count, $total_queries_times, %nss_already_processed ) =
print_nstimes( $ns, $max, $total_queries_count, $total_queries_times, %nss_already_processed );
$nss_already_processed{$ns} = 1;
}

printf __("%s %s\n"), 'Other', '-' x ( ( $max - length 'Other' ) - 1 );
foreach my $ns ( sort @filtered_nss ) {
( $total_queries_count, $total_queries_times, %nss_already_processed ) =
print_nstimes( $ns, $max, $total_queries_count, $total_queries_times, %nss_already_processed );
$nss_already_processed{$ns} = 1;
}

printf "%${max}s %s\n", '=' x $max, ' ======== ======== ======== ======== ======== ========= =========';
printf __("%${max}s %55.2f %9s\n"), 'Total', $total_queries_times, $total_queries_count;
}
} ## end if ( $opt_nstimes )

@@ -685,7 +753,7 @@ sub run {
$json_output->{elapsed} = $last->timestamp;
}
else {
printf "Total test run time: %0.1f seconds.\n", $last->timestamp;
printf "\nTotal test run time: %0.1f seconds.\n", $last->timestamp;
}
}

4 changes: 2 additions & 2 deletions script/zonemaster-cli
Original file line number Diff line number Diff line change
@@ -302,8 +302,8 @@ level that were logged during the run, as well as a count of each message tag.

=item B<--[no-]nstimes>

Print a summary, at the end of a run, of the times (in milliseconds) the zone's
name servers took to answer.
Print a summary, at the end of a run, of the times (in milliseconds) the name servers
took to answer, as well as the number of sent queries.
(default: disabled)

=item B<--[no-]elapsed>