github.com/m-lab/tcp-info@v1.9.0/collector/collector_linux.go (about) 1 // Package collector repeatedly queries the netlink socket to discover 2 // measurement data about open TCP connections and sends that data down a 3 // channel. 4 package collector 5 6 import ( 7 "context" 8 "log" 9 "syscall" 10 "time" 11 12 "github.com/m-lab/tcp-info/metrics" 13 14 "github.com/m-lab/tcp-info/netlink" 15 "github.com/m-lab/tcp-info/saver" 16 ) 17 18 var ( 19 errCount = 0 20 localCount = 0 21 ) 22 23 // collectDefaultNamespace collects all AF_INET6 and AF_INET connection stats, and sends them 24 // to svr. 25 func collectDefaultNamespace(svr chan<- netlink.MessageBlock, skipLocal bool) (int, int) { 26 // Preallocate space for up to 500 connections. We may want to adjust this upwards if profiling 27 // indicates a lot of reallocation. 28 buffer := netlink.MessageBlock{} 29 30 remoteCount := 0 31 res6, err := OneType(syscall.AF_INET6) 32 buffer.V6Time = time.Now() 33 if err != nil { 34 // Properly handle errors 35 // TODO add metric 36 log.Println(err) 37 } else { 38 buffer.V6Messages = res6 39 } 40 res4, err := OneType(syscall.AF_INET) 41 buffer.V4Time = time.Now() 42 if err != nil { 43 // Properly handle errors 44 // TODO add metric 45 log.Println(err) 46 } else { 47 buffer.V4Messages = res4 48 } 49 50 // Submit full set of message to the marshalling service. 51 svr <- buffer 52 53 return len(res4) + len(res6), remoteCount 54 } 55 56 // Run the collector, either for the specified number of loops, or, if the 57 // number specified is infinite, run forever. 58 func Run(ctx context.Context, reps int, svrChan chan<- netlink.MessageBlock, cl saver.CacheLogger, skipLocal bool) (localCount, errCount int) { 59 totalCount := 0 60 remoteCount := 0 61 loops := 0 62 63 // TODO - make this interval programmable. 64 ticker := time.NewTicker(10 * time.Millisecond) 65 defer ticker.Stop() 66 67 lastCollectionTime := time.Now().Add(-10 * time.Millisecond) 68 69 for loops = 0; (reps == 0 || loops < reps) && (ctx.Err() == nil); loops++ { 70 total, remote := collectDefaultNamespace(svrChan, skipLocal) 71 totalCount += total 72 remoteCount += remote 73 // print stats roughly once per minute. 74 if loops%6000 == 0 { 75 cl.LogCacheStats(localCount, errCount) 76 } 77 78 now := time.Now() 79 interval := now.Sub(lastCollectionTime) 80 lastCollectionTime = now 81 metrics.PollingHistogram.Observe(interval.Seconds()) 82 83 // Wait for next tick. 84 <-ticker.C 85 } 86 87 if loops > 0 { 88 log.Println(totalCount, "sockets", remoteCount, "remotes", totalCount/loops, "per iteration") 89 } 90 return localCount, errCount 91 }