Skip to content
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

add counters for negative and error DNS responses #232

Merged
merged 1 commit into from
Apr 21, 2024
Merged
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
11 changes: 1 addition & 10 deletions cmd/benchmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"sync"
"time"

"github.com/HdrHistogram/hdrhistogram-go"
"github.com/fatih/color"
"github.com/miekg/dns"
"github.com/quic-go/quic-go/http3"
Expand Down Expand Up @@ -343,16 +342,8 @@ func (b *Benchmark) Run(ctx context.Context) ([]*ResultStats, error) {
var wg sync.WaitGroup
var w uint32
for w = 0; w < b.Concurrency; w++ {
st := &ResultStats{Hist: hdrhistogram.New(b.HistMin.Nanoseconds(), b.HistMax.Nanoseconds(), b.HistPre)}
st := newResultStats(b)
stats[w] = st
if b.Rcodes {
st.Codes = make(map[int]int64)
}
st.Qtypes = make(map[string]int64)
if b.useDoH {
st.DoHStatusCodes = make(map[int]int64)
}
st.Counters = &Counters{}

var err error
wg.Add(1)
Expand Down
17 changes: 8 additions & 9 deletions cmd/jsonreporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ type histogramPoint struct {

type jsonResult struct {
TotalRequests int64 `json:"totalRequests"`
TotalSuccessCodes int64 `json:"totalSuccessCodes"`
TotalErrors int64 `json:"totalErrors"`
TotalSuccessResponses int64 `json:"totalSuccessResponses"`
TotalNegativeResponses int64 `json:"totalNegativeResponses"`
TotalErrorResponses int64 `json:"totalErrorResponses"`
TotalIOErrors int64 `json:"totalIOErrors"`
TotalIDmismatch int64 `json:"TotalIDmismatch"`
TotalTruncatedResponses int64 `json:"totalTruncatedResponses"`
ResponseRcodes map[string]int64 `json:"responseRcodes,omitempty"`
Expand All @@ -44,11 +46,6 @@ type jsonResult struct {
}

func (s *jsonReporter) print(params reportParameters) error {
sumerrs := int64(0)
for _, v := range params.topErrs.m {
sumerrs += int64(v)
}

codeTotalsMapped := make(map[string]int64)
if params.benchmark.Rcodes {
for k, v := range params.codeTotals {
Expand Down Expand Up @@ -86,8 +83,10 @@ func (s *jsonReporter) print(params reportParameters) error {

result := jsonResult{
TotalRequests: params.totalCounters.Total,
TotalSuccessCodes: params.totalCounters.Success,
TotalErrors: sumerrs,
TotalSuccessResponses: params.totalCounters.Success,
TotalNegativeResponses: params.totalCounters.Negative,
TotalErrorResponses: params.totalCounters.Error,
TotalIOErrors: params.totalCounters.IOError,
TotalIDmismatch: params.totalCounters.IDmismatch,
TotalTruncatedResponses: params.totalCounters.Truncated,
QueriesPerSecond: math.Round(float64(params.totalCounters.Total)/params.benchmarkDuration.Seconds()*100) / 100,
Expand Down
2 changes: 2 additions & 0 deletions cmd/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ func (b *Benchmark) PrintReport(w io.Writer, stats []*ResultStats, benchStart ti
Total: totalCounters.Total + s.Counters.Total,
IOError: totalCounters.IOError + s.Counters.IOError,
Success: totalCounters.Success + s.Counters.Success,
Negative: totalCounters.Negative + s.Counters.Negative,
Error: totalCounters.Error + s.Counters.Error,
IDmismatch: totalCounters.IDmismatch + s.Counters.IDmismatch,
Truncated: totalCounters.Truncated + s.Counters.Truncated,
}
Expand Down
36 changes: 22 additions & 14 deletions cmd/report_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ func ExampleBenchmark_PrintReport() {
b.PrintReport(os.Stdout, []*ResultStats{&rs}, time.Now(), time.Second)

// Output: Total requests: 1
// Read/Write errors: 3
// ID mismatch errors: 6
// DNS success codes: 4
// Read/Write errors: 6
// ID mismatch errors: 10
// DNS success responses: 4
// DNS negative responses: 8
// DNS error responses: 9
// Truncated responses: 7
//
// DNS response codes:
Expand Down Expand Up @@ -55,9 +57,11 @@ func ExampleBenchmark_PrintReport_dnssec() {
b.PrintReport(os.Stdout, []*ResultStats{&rs}, time.Now(), time.Second)

// Output: Total requests: 1
// Read/Write errors: 3
// ID mismatch errors: 6
// DNS success codes: 4
// Read/Write errors: 6
// ID mismatch errors: 10
// DNS success responses: 4
// DNS negative responses: 8
// DNS error responses: 9
// Truncated responses: 7
//
// DNS response codes:
Expand Down Expand Up @@ -98,9 +102,11 @@ func ExampleBenchmark_PrintReport_doh() {
b.PrintReport(os.Stdout, []*ResultStats{&rs}, time.Now(), time.Second)

// Output: Total requests: 1
// Read/Write errors: 3
// ID mismatch errors: 6
// DNS success codes: 4
// Read/Write errors: 6
// ID mismatch errors: 10
// DNS success responses: 4
// DNS negative responses: 8
// DNS error responses: 9
// Truncated responses: 7
//
// DNS response codes:
Expand Down Expand Up @@ -141,7 +147,7 @@ func ExampleBenchmark_PrintReport_json() {

b.PrintReport(os.Stdout, []*ResultStats{&rs}, time.Now(), time.Second)

// Output: {"totalRequests":1,"totalSuccessCodes":4,"totalErrors":6,"TotalIDmismatch":6,"totalTruncatedResponses":7,"responseRcodes":{"NOERROR":2},"questionTypes":{"A":2},"queriesPerSecond":1,"benchmarkDurationSeconds":1,"latencyStats":{"minMs":0,"meanMs":0,"stdMs":0,"maxMs":0,"p99Ms":0,"p95Ms":0,"p90Ms":0,"p75Ms":0,"p50Ms":0},"latencyDistribution":[{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1}]}
// Output: {"totalRequests":1,"totalSuccessResponses":4,"totalNegativeResponses":8,"totalErrorResponses":9,"totalIOErrors":6,"TotalIDmismatch":10,"totalTruncatedResponses":7,"responseRcodes":{"NOERROR":2},"questionTypes":{"A":2},"queriesPerSecond":1,"benchmarkDurationSeconds":1,"latencyStats":{"minMs":0,"meanMs":0,"stdMs":0,"maxMs":0,"p99Ms":0,"p95Ms":0,"p90Ms":0,"p75Ms":0,"p50Ms":0},"latencyDistribution":[{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1}]}
}

func ExampleBenchmark_PrintReport_json_dnssec() {
Expand All @@ -154,7 +160,7 @@ func ExampleBenchmark_PrintReport_json_dnssec() {

b.PrintReport(os.Stdout, []*ResultStats{&rs}, time.Now(), time.Second)

// Output: {"totalRequests":1,"totalSuccessCodes":4,"totalErrors":6,"TotalIDmismatch":6,"totalTruncatedResponses":7,"responseRcodes":{"NOERROR":2},"questionTypes":{"A":2},"queriesPerSecond":1,"benchmarkDurationSeconds":1,"latencyStats":{"minMs":0,"meanMs":0,"stdMs":0,"maxMs":0,"p99Ms":0,"p95Ms":0,"p90Ms":0,"p75Ms":0,"p50Ms":0},"latencyDistribution":[{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1}],"totalDNSSECSecuredDomains":1}
// Output: {"totalRequests":1,"totalSuccessResponses":4,"totalNegativeResponses":8,"totalErrorResponses":9,"totalIOErrors":6,"TotalIDmismatch":10,"totalTruncatedResponses":7,"responseRcodes":{"NOERROR":2},"questionTypes":{"A":2},"queriesPerSecond":1,"benchmarkDurationSeconds":1,"latencyStats":{"minMs":0,"meanMs":0,"stdMs":0,"maxMs":0,"p99Ms":0,"p95Ms":0,"p90Ms":0,"p75Ms":0,"p50Ms":0},"latencyDistribution":[{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1}],"totalDNSSECSecuredDomains":1}
}

func ExampleBenchmark_PrintReport_json_doh() {
Expand All @@ -168,7 +174,7 @@ func ExampleBenchmark_PrintReport_json_doh() {

b.PrintReport(os.Stdout, []*ResultStats{&rs}, time.Now(), time.Second)

// Output: {"totalRequests":1,"totalSuccessCodes":4,"totalErrors":6,"TotalIDmismatch":6,"totalTruncatedResponses":7,"responseRcodes":{"NOERROR":2},"questionTypes":{"A":2},"queriesPerSecond":1,"benchmarkDurationSeconds":1,"latencyStats":{"minMs":0,"meanMs":0,"stdMs":0,"maxMs":0,"p99Ms":0,"p95Ms":0,"p90Ms":0,"p75Ms":0,"p50Ms":0},"latencyDistribution":[{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1}],"dohHTTPResponseStatusCodes":{"200":2}}
// Output: {"totalRequests":1,"totalSuccessResponses":4,"totalNegativeResponses":8,"totalErrorResponses":9,"totalIOErrors":6,"TotalIDmismatch":10,"totalTruncatedResponses":7,"responseRcodes":{"NOERROR":2},"questionTypes":{"A":2},"queriesPerSecond":1,"benchmarkDurationSeconds":1,"latencyStats":{"minMs":0,"meanMs":0,"stdMs":0,"maxMs":0,"p99Ms":0,"p95Ms":0,"p90Ms":0,"p75Ms":0,"p50Ms":0},"latencyDistribution":[{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":0},{"latencyMs":0,"count":1}],"dohHTTPResponseStatusCodes":{"200":2}}
}

func ExampleBenchmark_PrintReport_server_dns_errors() {
Expand Down Expand Up @@ -223,10 +229,12 @@ func testReportData() (Benchmark, ResultStats) {
Timings: []Datapoint{d1, d2},
Counters: &Counters{
Total: 1,
IOError: 3,
IOError: 6,
Success: 4,
IDmismatch: 6,
IDmismatch: 10,
Truncated: 7,
Negative: 8,
Error: 9,
},
Errors: []ErrorDatapoint{
{Start: time.Unix(0, 0), Err: errors.New("test2")},
Expand Down
44 changes: 39 additions & 5 deletions cmd/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,20 @@ import (

// Counters represents various counters of benchmark results.
type Counters struct {
Total int64
IOError int64
Success int64
// Total is counter of all requests.
Total int64
// IOError is counter of all requests for which there was no answer.
IOError int64
// Success is counter of all responses which were successful (NOERROR, but not NODATA!).
Success int64
// Negative is counter of all responses which were negative (NODATA/NXDOMAIN).
Negative int64
// Error is counter of all responses which were not negative (NODATA/NXDOMAIN) or success (NOERROR response).
Error int64
// IDmismatch is counter of all responses which ID mismatched the request ID.
IDmismatch int64
Truncated int64
// Truncated is counter of all responses which had truncated flag.
Truncated int64
}

// Datapoint one datapoint of benchmark (single DNS request).
Expand Down Expand Up @@ -43,6 +52,19 @@ type ResultStats struct {
DoHStatusCodes map[int]int64
}

func newResultStats(b *Benchmark) *ResultStats {
st := &ResultStats{Hist: hdrhistogram.New(b.HistMin.Nanoseconds(), b.HistMax.Nanoseconds(), b.HistPre)}
if b.Rcodes {
st.Codes = make(map[int]int64)
}
st.Qtypes = make(map[string]int64)
if b.useDoH {
st.DoHStatusCodes = make(map[int]int64)
}
st.Counters = &Counters{}
return st
}

func (rs *ResultStats) record(req *dns.Msg, resp *dns.Msg, err error, time time.Time, duration time.Duration) {
rs.Counters.Total++

Expand Down Expand Up @@ -75,7 +97,19 @@ func (rs *ResultStats) record(req *dns.Msg, resp *dns.Msg, err error, time time.
rs.Counters.IDmismatch++
return
}
rs.Counters.Success++
if len(resp.Answer) == 0 {
// NODATA negative response
rs.Counters.Negative++
} else {
rs.Counters.Success++
}
}
if resp.Rcode == dns.RcodeNameError {
rs.Counters.Negative++
}
if resp.Rcode != dns.RcodeSuccess && resp.Rcode != dns.RcodeNameError {
// assume every rcode not NOERROR or NXDOMAIN is error
rs.Counters.Error++
}

if rs.Codes != nil {
Expand Down
Loading
Loading