* stats: use uint32 or uint64 integer values, not int

This commit is contained in:
Simon Zolin 2019-09-10 17:59:10 +03:00
parent 8a2aa57e24
commit 04e2566e9e
7 changed files with 97 additions and 96 deletions

View File

@ -496,7 +496,7 @@ func (s *Server) updateStats(d *proxy.DNSContext, elapsed time.Duration, res dns
case *net.TCPAddr: case *net.TCPAddr:
e.Client = addr.IP e.Client = addr.IP
} }
e.Time = uint(elapsed / 1000) e.Time = uint32(elapsed / 1000)
switch res.Reason { switch res.Reason {
case dnsfilter.NotFilteredNotFound: case dnsfilter.NotFilteredNotFound:

View File

@ -110,7 +110,7 @@ type dnsConfig struct {
Port int `yaml:"port"` Port int `yaml:"port"`
// time interval for statistics (in days) // time interval for statistics (in days)
StatsInterval uint `yaml:"statistics_interval"` StatsInterval uint32 `yaml:"statistics_interval"`
dnsforward.FilteringConfig `yaml:",inline"` dnsforward.FilteringConfig `yaml:",inline"`

View File

@ -9,7 +9,7 @@ import (
) )
type statsConfig struct { type statsConfig struct {
Interval uint `json:"interval"` Interval uint32 `json:"interval"`
} }
// Get stats configuration // Get stats configuration
@ -89,6 +89,6 @@ func RegisterStatsHandlers() {
httpRegister(http.MethodGet, "/control/stats_info", handleStatsInfo) httpRegister(http.MethodGet, "/control/stats_info", handleStatsInfo)
} }
func checkStatsInterval(i uint) bool { func checkStatsInterval(i uint32) bool {
return i == 1 || i == 7 || i == 30 || i == 90 return i == 1 || i == 7 || i == 30 || i == 90
} }

View File

@ -35,7 +35,8 @@ func initDNSServer(baseDir string) {
log.Fatalf("Cannot create DNS data dir at %s: %s", baseDir, err) log.Fatalf("Cannot create DNS data dir at %s: %s", baseDir, err)
} }
config.stats, err = stats.New(filepath.Join(baseDir, "stats.db"), int(config.DNS.StatsInterval), nil) statsDBFilename := filepath.Join(baseDir, "stats.db")
config.stats, err = stats.New(statsDBFilename, config.DNS.StatsInterval, nil)
if err != nil { if err != nil {
log.Fatal("Couldn't initialize statistics module") log.Fatal("Couldn't initialize statistics module")
} }

View File

@ -6,13 +6,13 @@ import (
"net" "net"
) )
type unitIDCallback func() int type unitIDCallback func() uint32
// New - create object // New - create object
// filename: DB file name // filename: DB file name
// limit: time limit (in days) // limit: time limit (in days)
// unitID: user function to get the current unit ID. If nil, the current time hour is used. // unitID: user function to get the current unit ID. If nil, the current time hour is used.
func New(filename string, limit int, unitID unitIDCallback) (Stats, error) { func New(filename string, limit uint32, unitID unitIDCallback) (Stats, error) {
return createObject(filename, limit, unitID) return createObject(filename, limit, unitID)
} }
@ -64,5 +64,5 @@ type Entry struct {
Domain string Domain string
Client net.IP Client net.IP
Result Result Result Result
Time uint // processing time (msec) Time uint32 // processing time (msec)
} }

View File

@ -11,7 +11,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func UIntArrayEquals(a []uint, b []uint) bool { func UIntArrayEquals(a []uint64, b []uint64) bool {
if len(a) != len(b) { if len(a) != len(b) {
return false return false
} }
@ -43,32 +43,32 @@ func TestStats(t *testing.T) {
s.Update(e) s.Update(e)
d := s.GetData(Hours) d := s.GetData(Hours)
a := []uint{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2} a := []uint64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}
assert.True(t, UIntArrayEquals(d["dns_queries"].([]uint), a)) assert.True(t, UIntArrayEquals(d["dns_queries"].([]uint64), a))
a = []uint{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} a = []uint64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
assert.True(t, UIntArrayEquals(d["blocked_filtering"].([]uint), a)) assert.True(t, UIntArrayEquals(d["blocked_filtering"].([]uint64), a))
a = []uint{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} a = []uint64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
assert.True(t, UIntArrayEquals(d["replaced_safebrowsing"].([]uint), a)) assert.True(t, UIntArrayEquals(d["replaced_safebrowsing"].([]uint64), a))
a = []uint{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} a = []uint64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
assert.True(t, UIntArrayEquals(d["replaced_parental"].([]uint), a)) assert.True(t, UIntArrayEquals(d["replaced_parental"].([]uint64), a))
m := d["top_queried_domains"].([]map[string]uint) m := d["top_queried_domains"].([]map[string]uint64)
assert.True(t, m[0]["domain"] == 1) assert.True(t, m[0]["domain"] == 1)
m = d["top_blocked_domains"].([]map[string]uint) m = d["top_blocked_domains"].([]map[string]uint64)
assert.True(t, m[0]["domain"] == 1) assert.True(t, m[0]["domain"] == 1)
m = d["top_clients"].([]map[string]uint) m = d["top_clients"].([]map[string]uint64)
assert.True(t, m[0]["127.0.0.1"] == 2) assert.True(t, m[0]["127.0.0.1"] == 2)
assert.True(t, d["num_dns_queries"].(uint) == 2) assert.True(t, d["num_dns_queries"].(uint64) == 2)
assert.True(t, d["num_blocked_filtering"].(uint) == 1) assert.True(t, d["num_blocked_filtering"].(uint64) == 1)
assert.True(t, d["num_replaced_safebrowsing"].(uint) == 0) assert.True(t, d["num_replaced_safebrowsing"].(uint64) == 0)
assert.True(t, d["num_replaced_safesearch"].(uint) == 0) assert.True(t, d["num_replaced_safesearch"].(uint64) == 0)
assert.True(t, d["num_replaced_parental"].(uint) == 0) assert.True(t, d["num_replaced_parental"].(uint64) == 0)
assert.True(t, d["avg_processing_time"].(float64) == 0.123456) assert.True(t, d["avg_processing_time"].(float64) == 0.123456)
s.Clear() s.Clear()
@ -79,9 +79,9 @@ func TestStats(t *testing.T) {
func TestLargeNumbers(t *testing.T) { func TestLargeNumbers(t *testing.T) {
var hour int32 var hour int32
hour = 1 hour = 1
newID := func() int { newID := func() uint32 {
// use "atomic" to make Go race detector happy // use "atomic" to make Go race detector happy
return int(atomic.LoadInt32(&hour)) return uint32(atomic.LoadInt32(&hour))
} }
// log.SetLevel(log.DEBUG) // log.SetLevel(log.DEBUG)
@ -108,7 +108,7 @@ func TestLargeNumbers(t *testing.T) {
} }
d := s.GetData(Hours) d := s.GetData(Hours)
assert.True(t, d["num_dns_queries"].(uint) == uint(int(hour)*n)) assert.True(t, d["num_dns_queries"].(uint64) == uint64(int(hour)*n))
s.Close() s.Close()
os.Remove(fn) os.Remove(fn)

View File

@ -21,7 +21,7 @@ const (
// statsCtx - global context // statsCtx - global context
type statsCtx struct { type statsCtx struct {
limit int // maximum time we need to keep data for (in hours) limit uint32 // maximum time we need to keep data for (in hours)
filename string // database file name filename string // database file name
unitID unitIDCallback // user function which returns the current unit ID unitID unitIDCallback // user function which returns the current unit ID
db *bolt.DB db *bolt.DB
@ -32,37 +32,37 @@ type statsCtx struct {
// data for 1 time unit // data for 1 time unit
type unit struct { type unit struct {
id int // unit ID. Default: absolute hour since Jan 1, 1970 id uint32 // unit ID. Default: absolute hour since Jan 1, 1970
nTotal int // total requests nTotal uint64 // total requests
nResult []int // number of requests per one result nResult []uint64 // number of requests per one result
timeSum int // sum of processing time of all requests (usec) timeSum uint64 // sum of processing time of all requests (usec)
// top: // top:
domains map[string]int // number of requests per domain domains map[string]uint64 // number of requests per domain
blockedDomains map[string]int // number of blocked requests per domain blockedDomains map[string]uint64 // number of blocked requests per domain
clients map[string]int // number of requests per client clients map[string]uint64 // number of requests per client
} }
// name-count pair // name-count pair
type countPair struct { type countPair struct {
Name string Name string
Count uint Count uint64
} }
// structure for storing data in file // structure for storing data in file
type unitDB struct { type unitDB struct {
NTotal uint NTotal uint64
NResult []uint NResult []uint64
Domains []countPair Domains []countPair
BlockedDomains []countPair BlockedDomains []countPair
Clients []countPair Clients []countPair
TimeAvg uint // usec TimeAvg uint32 // usec
} }
func createObject(filename string, limitDays int, unitID unitIDCallback) (*statsCtx, error) { func createObject(filename string, limitDays uint32, unitID unitIDCallback) (*statsCtx, error) {
s := statsCtx{} s := statsCtx{}
s.limit = limitDays * 24 s.limit = limitDays * 24
s.filename = filename s.filename = filename
@ -83,7 +83,7 @@ func createObject(filename string, limitDays int, unitID unitIDCallback) (*stats
firstID := id - s.limit - 1 firstID := id - s.limit - 1
unitDel := 0 unitDel := 0
forEachBkt := func(name []byte, b *bolt.Bucket) error { forEachBkt := func(name []byte, b *bolt.Bucket) error {
id := btoi(name) id := uint32(btoi(name))
if id < firstID { if id < firstID {
err := tx.DeleteBucket(name) err := tx.DeleteBucket(name)
if err != nil { if err != nil {
@ -142,17 +142,17 @@ func (s *statsCtx) swapUnit(new *unit) *unit {
} }
// Get unit ID for the current hour // Get unit ID for the current hour
func newUnitID() int { func newUnitID() uint32 {
return int(time.Now().Unix() / (60 * 60)) return uint32(time.Now().Unix() / (60 * 60))
} }
// Initialize a unit // Initialize a unit
func (s *statsCtx) initUnit(u *unit, id int) { func (s *statsCtx) initUnit(u *unit, id uint32) {
u.id = id u.id = id
u.nResult = make([]int, rLast) u.nResult = make([]uint64, rLast)
u.domains = make(map[string]int) u.domains = make(map[string]uint64)
u.blockedDomains = make(map[string]int) u.blockedDomains = make(map[string]uint64)
u.clients = make(map[string]int) u.clients = make(map[string]uint64)
} }
// Open a DB transaction // Open a DB transaction
@ -182,20 +182,20 @@ func (s *statsCtx) commitTxn(tx *bolt.Tx) {
} }
// Get unit name // Get unit name
func unitName(id int) []byte { func unitName(id uint32) []byte {
return itob(id) return itob(uint64(id))
} }
// Convert integer to 8-byte array (big endian) // Convert integer to 8-byte array (big endian)
func itob(v int) []byte { func itob(v uint64) []byte {
b := make([]byte, 8) b := make([]byte, 8)
binary.BigEndian.PutUint64(b, uint64(v)) binary.BigEndian.PutUint64(b, v)
return b return b
} }
// Convert 8-byte array (big endian) to integer // Convert 8-byte array (big endian) to integer
func btoi(b []byte) int { func btoi(b []byte) uint64 {
return int(binary.BigEndian.Uint64(b)) return binary.BigEndian.Uint64(b)
} }
// Flush the current unit to DB and delete an old unit when a new hour is started // Flush the current unit to DB and delete an old unit when a new hour is started
@ -235,7 +235,7 @@ func (s *statsCtx) periodicFlush() {
} }
// Delete unit's data from file // Delete unit's data from file
func (s *statsCtx) deleteUnit(tx *bolt.Tx, id int) bool { func (s *statsCtx) deleteUnit(tx *bolt.Tx, id uint32) bool {
err := tx.DeleteBucket(unitName(id)) err := tx.DeleteBucket(unitName(id))
if err != nil { if err != nil {
log.Tracef("bolt DeleteBucket: %s", err) log.Tracef("bolt DeleteBucket: %s", err)
@ -245,12 +245,12 @@ func (s *statsCtx) deleteUnit(tx *bolt.Tx, id int) bool {
return true return true
} }
func convertMapToArray(m map[string]int, max int) []countPair { func convertMapToArray(m map[string]uint64, max int) []countPair {
a := []countPair{} a := []countPair{}
for k, v := range m { for k, v := range m {
pair := countPair{} pair := countPair{}
pair.Name = k pair.Name = k
pair.Count = uint(v) pair.Count = v
a = append(a, pair) a = append(a, pair)
} }
less := func(i, j int) bool { less := func(i, j int) bool {
@ -266,22 +266,22 @@ func convertMapToArray(m map[string]int, max int) []countPair {
return a[:max] return a[:max]
} }
func convertArrayToMap(a []countPair) map[string]int { func convertArrayToMap(a []countPair) map[string]uint64 {
m := map[string]int{} m := map[string]uint64{}
for _, it := range a { for _, it := range a {
m[it.Name] = int(it.Count) m[it.Name] = it.Count
} }
return m return m
} }
func serialize(u *unit) *unitDB { func serialize(u *unit) *unitDB {
udb := unitDB{} udb := unitDB{}
udb.NTotal = uint(u.nTotal) udb.NTotal = u.nTotal
for _, it := range u.nResult { for _, it := range u.nResult {
udb.NResult = append(udb.NResult, uint(it)) udb.NResult = append(udb.NResult, it)
} }
if u.nTotal != 0 { if u.nTotal != 0 {
udb.TimeAvg = uint(u.timeSum / u.nTotal) udb.TimeAvg = uint32(u.timeSum / u.nTotal)
} }
udb.Domains = convertMapToArray(u.domains, maxDomains) udb.Domains = convertMapToArray(u.domains, maxDomains)
udb.BlockedDomains = convertMapToArray(u.blockedDomains, maxDomains) udb.BlockedDomains = convertMapToArray(u.blockedDomains, maxDomains)
@ -290,17 +290,17 @@ func serialize(u *unit) *unitDB {
} }
func deserialize(u *unit, udb *unitDB) { func deserialize(u *unit, udb *unitDB) {
u.nTotal = int(udb.NTotal) u.nTotal = udb.NTotal
for _, it := range udb.NResult { for _, it := range udb.NResult {
u.nResult = append(u.nResult, int(it)) u.nResult = append(u.nResult, int(it))
} }
u.domains = convertArrayToMap(udb.Domains) u.domains = convertArrayToMap(udb.Domains)
u.blockedDomains = convertArrayToMap(udb.BlockedDomains) u.blockedDomains = convertArrayToMap(udb.BlockedDomains)
u.clients = convertArrayToMap(udb.Clients) u.clients = convertArrayToMap(udb.Clients)
u.timeSum = int(udb.TimeAvg) * u.nTotal u.timeSum = uint64(udb.TimeAvg) * u.nTotal
} }
func (s *statsCtx) flushUnitToDB(tx *bolt.Tx, id int, udb *unitDB) bool { func (s *statsCtx) flushUnitToDB(tx *bolt.Tx, id uint32, udb *unitDB) bool {
log.Tracef("Flushing unit %d", id) log.Tracef("Flushing unit %d", id)
bkt, err := tx.CreateBucketIfNotExists(unitName(id)) bkt, err := tx.CreateBucketIfNotExists(unitName(id))
@ -326,7 +326,7 @@ func (s *statsCtx) flushUnitToDB(tx *bolt.Tx, id int, udb *unitDB) bool {
return true return true
} }
func (s *statsCtx) loadUnitFromDB(tx *bolt.Tx, id int) *unitDB { func (s *statsCtx) loadUnitFromDB(tx *bolt.Tx, id uint32) *unitDB {
bkt := tx.Bucket(unitName(id)) bkt := tx.Bucket(unitName(id))
if bkt == nil { if bkt == nil {
return nil return nil
@ -347,10 +347,10 @@ func (s *statsCtx) loadUnitFromDB(tx *bolt.Tx, id int) *unitDB {
return &udb return &udb
} }
func convertTopArray(a []countPair) []map[string]uint { func convertTopArray(a []countPair) []map[string]uint64 {
m := []map[string]uint{} m := []map[string]uint64{}
for _, it := range a { for _, it := range a {
ent := map[string]uint{} ent := map[string]uint64{}
ent[it.Name] = it.Count ent[it.Name] = it.Count
m = append(m, ent) m = append(m, ent)
} }
@ -361,7 +361,7 @@ func (s *statsCtx) Configure(limit int) {
if limit < 0 { if limit < 0 {
return return
} }
s.limit = limit * 24 s.limit = uint32(limit) * 24
log.Debug("Stats: set limit: %d", limit) log.Debug("Stats: set limit: %d", limit)
} }
@ -433,7 +433,7 @@ func (s *statsCtx) Update(e Entry) {
} }
u.clients[client]++ u.clients[client]++
u.timeSum += int(e.Time) u.timeSum += uint64(e.Time)
u.nTotal++ u.nTotal++
s.unitLock.Unlock() s.unitLock.Unlock()
} }
@ -481,7 +481,7 @@ func (s *statsCtx) GetData(timeUnit TimeUnit) map[string]interface{} {
u := s.loadUnitFromDB(tx, i) u := s.loadUnitFromDB(tx, i)
if u == nil { if u == nil {
u = &unitDB{} u = &unitDB{}
u.NResult = make([]uint, rLast) u.NResult = make([]uint64, rLast)
} }
units = append(units, u) units = append(units, u)
} }
@ -497,7 +497,7 @@ func (s *statsCtx) GetData(timeUnit TimeUnit) map[string]interface{} {
} }
units = append(units, cu) units = append(units, cu)
if len(units) != s.limit { if len(units) != int(s.limit) {
log.Fatalf("len(units) != s.limit: %d %d", len(units), s.limit) log.Fatalf("len(units) != s.limit: %d %d", len(units), s.limit)
} }
@ -506,16 +506,16 @@ func (s *statsCtx) GetData(timeUnit TimeUnit) map[string]interface{} {
// 720 hours may span 31 days, so we skip data for the first day in this case // 720 hours may span 31 days, so we skip data for the first day in this case
firstDayID := (firstID + 24 - 1) / 24 * 24 // align_ceil(24) firstDayID := (firstID + 24 - 1) / 24 * 24 // align_ceil(24)
a := []uint{} a := []uint64{}
if timeUnit == Hours { if timeUnit == Hours {
for _, u := range units { for _, u := range units {
a = append(a, u.NTotal) a = append(a, u.NTotal)
} }
} else { } else {
var sum uint var sum uint64
id := firstDayID id := firstDayID
nextDayID := firstDayID + 24 nextDayID := firstDayID + 24
for i := firstDayID - firstID; i != len(units); i++ { for i := firstDayID - firstID; int(i) != len(units); i++ {
sum += units[i].NTotal sum += units[i].NTotal
if id == nextDayID { if id == nextDayID {
a = append(a, sum) a = append(a, sum)
@ -527,22 +527,22 @@ func (s *statsCtx) GetData(timeUnit TimeUnit) map[string]interface{} {
if id < nextDayID { if id < nextDayID {
a = append(a, sum) a = append(a, sum)
} }
if len(a) != s.limit/24 { if len(a) != int(s.limit/24) {
log.Fatalf("len(a) != s.limit: %d %d", len(a), s.limit) log.Fatalf("len(a) != s.limit: %d %d", len(a), s.limit)
} }
} }
d["dns_queries"] = a d["dns_queries"] = a
a = []uint{} a = []uint64{}
if timeUnit == Hours { if timeUnit == Hours {
for _, u := range units { for _, u := range units {
a = append(a, u.NResult[RFiltered]) a = append(a, u.NResult[RFiltered])
} }
} else { } else {
var sum uint var sum uint64
id := firstDayID id := firstDayID
nextDayID := firstDayID + 24 nextDayID := firstDayID + 24
for i := firstDayID - firstID; i != len(units); i++ { for i := firstDayID - firstID; int(i) != len(units); i++ {
sum += units[i].NResult[RFiltered] sum += units[i].NResult[RFiltered]
if id == nextDayID { if id == nextDayID {
a = append(a, sum) a = append(a, sum)
@ -557,16 +557,16 @@ func (s *statsCtx) GetData(timeUnit TimeUnit) map[string]interface{} {
} }
d["blocked_filtering"] = a d["blocked_filtering"] = a
a = []uint{} a = []uint64{}
if timeUnit == Hours { if timeUnit == Hours {
for _, u := range units { for _, u := range units {
a = append(a, u.NResult[RSafeBrowsing]) a = append(a, u.NResult[RSafeBrowsing])
} }
} else { } else {
var sum uint var sum uint64
id := firstDayID id := firstDayID
nextDayID := firstDayID + 24 nextDayID := firstDayID + 24
for i := firstDayID - firstID; i != len(units); i++ { for i := firstDayID - firstID; int(i) != len(units); i++ {
sum += units[i].NResult[RSafeBrowsing] sum += units[i].NResult[RSafeBrowsing]
if id == nextDayID { if id == nextDayID {
a = append(a, sum) a = append(a, sum)
@ -581,16 +581,16 @@ func (s *statsCtx) GetData(timeUnit TimeUnit) map[string]interface{} {
} }
d["replaced_safebrowsing"] = a d["replaced_safebrowsing"] = a
a = []uint{} a = []uint64{}
if timeUnit == Hours { if timeUnit == Hours {
for _, u := range units { for _, u := range units {
a = append(a, u.NResult[RParental]) a = append(a, u.NResult[RParental])
} }
} else { } else {
var sum uint var sum uint64
id := firstDayID id := firstDayID
nextDayID := firstDayID + 24 nextDayID := firstDayID + 24
for i := firstDayID - firstID; i != len(units); i++ { for i := firstDayID - firstID; int(i) != len(units); i++ {
sum += units[i].NResult[RParental] sum += units[i].NResult[RParental]
if id == nextDayID { if id == nextDayID {
a = append(a, sum) a = append(a, sum)
@ -607,28 +607,28 @@ func (s *statsCtx) GetData(timeUnit TimeUnit) map[string]interface{} {
// top counters: // top counters:
m := map[string]int{} m := map[string]uint64{}
for _, u := range units { for _, u := range units {
for _, it := range u.Domains { for _, it := range u.Domains {
m[it.Name] += int(it.Count) m[it.Name] += it.Count
} }
} }
a2 := convertMapToArray(m, maxDomains) a2 := convertMapToArray(m, maxDomains)
d["top_queried_domains"] = convertTopArray(a2) d["top_queried_domains"] = convertTopArray(a2)
m = map[string]int{} m = map[string]uint64{}
for _, u := range units { for _, u := range units {
for _, it := range u.BlockedDomains { for _, it := range u.BlockedDomains {
m[it.Name] += int(it.Count) m[it.Name] += it.Count
} }
} }
a2 = convertMapToArray(m, maxDomains) a2 = convertMapToArray(m, maxDomains)
d["top_blocked_domains"] = convertTopArray(a2) d["top_blocked_domains"] = convertTopArray(a2)
m = map[string]int{} m = map[string]uint64{}
for _, u := range units { for _, u := range units {
for _, it := range u.Clients { for _, it := range u.Clients {
m[it.Name] += int(it.Count) m[it.Name] += it.Count
} }
} }
a2 = convertMapToArray(m, maxClients) a2 = convertMapToArray(m, maxClients)
@ -637,8 +637,8 @@ func (s *statsCtx) GetData(timeUnit TimeUnit) map[string]interface{} {
// total counters: // total counters:
sum := unitDB{} sum := unitDB{}
sum.NResult = make([]uint64, rLast)
timeN := 0 timeN := 0
sum.NResult = make([]uint, rLast)
for _, u := range units { for _, u := range units {
sum.NTotal += u.NTotal sum.NTotal += u.NTotal
sum.TimeAvg += u.TimeAvg sum.TimeAvg += u.TimeAvg
@ -659,7 +659,7 @@ func (s *statsCtx) GetData(timeUnit TimeUnit) map[string]interface{} {
avgTime := float64(0) avgTime := float64(0)
if timeN != 0 { if timeN != 0 {
avgTime = float64(sum.TimeAvg/uint(timeN)) / 1000000 avgTime = float64(sum.TimeAvg/uint32(timeN)) / 1000000
} }
d["avg_processing_time"] = avgTime d["avg_processing_time"] = avgTime