@@ -15,6 +15,7 @@ import (
15
15
"math/rand"
16
16
"net"
17
17
"os"
18
+ "sort"
18
19
"strconv"
19
20
"strings"
20
21
"sync"
@@ -87,6 +88,7 @@ type Stats struct {
87
88
unhandledCount uint32
88
89
noresultsCount uint32
89
90
startTime time.Time
91
+ durations sync.Map
90
92
}
91
93
92
94
func startResolver (resolverHosts []string ) (rw * ResolveWrapper , err error ) {
@@ -151,6 +153,7 @@ func (rw *ResolveWrapper) Wait() {
151
153
152
154
func oneResolverStdlib (index int , ch <- chan Item , wg * sync.WaitGroup , stats * Stats ) {
153
155
defer wg .Done ()
156
+ start := time .Now ()
154
157
res := & net.Resolver {}
155
158
for {
156
159
item , ok := <- ch
@@ -159,6 +162,7 @@ func oneResolverStdlib(index int, ch <-chan Item, wg *sync.WaitGroup, stats *Sta
159
162
}
160
163
resolveStdlib (index , res , item , stats )
161
164
}
165
+ stats .durations .Store ("stdlib" , time .Now ().Sub (start ))
162
166
}
163
167
164
168
func adminResolver (index int , inbound <- chan Item , chList []chan <- Item , wg * sync.WaitGroup ) {
@@ -181,6 +185,7 @@ func adminResolver(index int, inbound <-chan Item, chList []chan<- Item, wg *syn
181
185
182
186
func oneResolverPerTarget (resIndex int , ch <- chan Item , wg * sync.WaitGroup , resolverName string , stats * Stats ) {
183
187
defer wg .Done ()
188
+ start := time .Now ()
184
189
rc := & RecClient {
185
190
client : dns.Client {
186
191
Timeout : DNS_TIMEOUT ,
@@ -195,6 +200,7 @@ func oneResolverPerTarget(resIndex int, ch <-chan Item, wg *sync.WaitGroup, reso
195
200
}
196
201
resolvePerTarget (resIndex , rc , item , stats )
197
202
}
203
+ stats .durations .Store (resolverName , time .Now ().Sub (start ))
198
204
}
199
205
200
206
func resolveStdlib (index int , res * net.Resolver , item Item , stats * Stats ) {
@@ -545,11 +551,31 @@ func (rw *ResolveWrapper) PrintSummary() {
545
551
log .Printf ("Summary: %v for %d requests %s, taking %d queries%s" ,
546
552
duration , requested , targetRepr ,
547
553
queries , statsRepr )
554
+
555
+ // We actually time always, it's simpler than making the time conditional
556
+ // and the overhead is low. So really it's "report that we timed".
557
+ if opts .TimeResolvers {
558
+ // it's servers else 1, Go has no ternary, just add 1
559
+ names := make ([]string , 0 , servers + 1 )
560
+ durations := make (map [string ]time.Duration , servers + 1 )
561
+ rw .stats .durations .Range (func (i , v interface {}) bool {
562
+ n := i .(string )
563
+ d := v .(time.Duration )
564
+ names = append (names , n )
565
+ durations [n ] = d
566
+ return true
567
+ })
568
+ sort .Strings (names ) // do I have a convenient IPsort/HOSTsort around?
569
+ for _ , name := range names {
570
+ log .Printf (" [%7s] %s" , durations [name ].Round (time .Millisecond ), name )
571
+ }
572
+ }
548
573
}
549
574
550
575
var opts struct {
551
- ProgressOnly bool
552
- ConfigFile string
576
+ ProgressOnly bool
577
+ TimeResolvers bool
578
+ ConfigFile string
553
579
}
554
580
555
581
type progressT struct {
@@ -571,6 +597,7 @@ func registerFlags() {
571
597
572
598
flag .BoolVar (& opts .ProgressOnly , "progress" , false , "show progress & summary only" )
573
599
flag .BoolVar (& opts .ProgressOnly , "p" , false , "show progress & summary only" )
600
+ flag .BoolVar (& opts .TimeResolvers , "time-resolvers" , false , "show summary times per resolver" )
574
601
flag .StringVar (& opts .ConfigFile , "config" , defaultConfig , "file with DNS entries to resolve" )
575
602
}
576
603
0 commit comments