@@ -68,22 +68,13 @@ var Expv = struct {
6868 RouterCacheHits * expvar.Int
6969 RouterCacheRate expvar.Func
7070 RouterIPNetCall * expvar.Int
71- RouterIPNetTime * expvar. Float
71+ RouterIPNetTime * ExpvarAverage
7272}{
7373 RouterCacheCall : expvar .NewInt ("RouterCache.Call" ),
7474 RouterCacheHits : expvar .NewInt ("RouterCache.Hits" ),
75- RouterCacheRate : func () expvar.Func {
76- f := expvar .Func (func () any {
77- hits := expvar .Get ("RouterCache.Hits" ).(* expvar.Int ).Value ()
78- call := expvar .Get ("RouterCache.Call" ).(* expvar.Int ).Value ()
79- doa .Doa (hits <= call )
80- return float64 (hits ) / float64 (max (1 , call ))
81- })
82- expvar .Publish ("RouterCache.Rate" , f )
83- return f
84- }(),
75+ RouterCacheRate : NewExpvarRate ("RouterCache.Rate" , "RouterCache.Hits" , "RouterCache.Call" ),
8576 RouterIPNetCall : expvar .NewInt ("RouterIPNet.Call" ),
86- RouterIPNetTime : expvar . NewFloat ("RouterIPNet.Time" ),
77+ RouterIPNetTime : NewExpvarAverage ("RouterIPNet.Time" , 64 ),
8778}
8879
8980// ResolverDns returns a DNS resolver.
@@ -771,9 +762,7 @@ func (r *RouterIPNet) Road(ctx *Context, host string) Road {
771762 Expv .RouterIPNetCall .Add (1 )
772763 t := time .Now ()
773764 l , err := net .DefaultResolver .LookupIPAddr (context .Background (), host )
774- s := time .Since (t ).Seconds ()
775- // This is not strictly concurrency-safe, but it won't have much impact on the data.
776- Expv .RouterIPNetTime .Add ((s - Expv .RouterIPNetTime .Value ()) / 64 )
765+ Expv .RouterIPNetTime .Add (time .Since (t ).Seconds ())
777766 return l , err
778767 }()
779768 if err != nil {
@@ -1069,6 +1058,37 @@ func Dial(network string, address string) (net.Conn, error) {
10691058 return d .Dial (network , address )
10701059}
10711060
1061+ // ExpvarAverage is a structure to maintain a running average using expvar.Float.
1062+ type ExpvarAverage struct {
1063+ F * expvar.Float
1064+ L float64
1065+ }
1066+
1067+ // Adds a new value to the running average. This is not strictly concurrency-safe, but it won't have much impact on the
1068+ // data.
1069+ func (e * ExpvarAverage ) Add (value float64 ) {
1070+ e .F .Add ((value - e .F .Value ()) / e .L )
1071+ }
1072+
1073+ // NewExpvarAverage creates and initializes a new ExpvarAverage instance.
1074+ func NewExpvarAverage (name string , length int ) * ExpvarAverage {
1075+ return & ExpvarAverage {
1076+ F : expvar .NewFloat (name ),
1077+ L : float64 (length ),
1078+ }
1079+ }
1080+
1081+ // NewExpvarRate creates a new expvar.Func that calculates the ratio of two expvar.Int metrics.
1082+ func NewExpvarRate (name string , n string , d string ) expvar.Func {
1083+ f := expvar .Func (func () any {
1084+ v := expvar .Get (n ).(* expvar.Int ).Value ()
1085+ w := expvar .Get (d ).(* expvar.Int ).Value ()
1086+ return float64 (v ) / float64 (max (1 , w ))
1087+ })
1088+ expvar .Publish (name , f )
1089+ return f
1090+ }
1091+
10721092// GravityReader wraps an io.Reader with RC4 crypto.
10731093func GravityReader (r io.Reader , k []byte ) io.Reader {
10741094 cr := doa .Try (rc4 .NewCipher (k ))
0 commit comments