From 7914d855d1b43ce3808c35cd70dd7cca53044314 Mon Sep 17 00:00:00 2001 From: jterryhao Date: Wed, 3 Mar 2021 17:40:30 -0500 Subject: [PATCH 1/3] Add WithinLimit Counter Signed-off-by: Jia Hao --- src/config/config.go | 1 + src/config/config_impl.go | 1 + src/limiter/base_limiter.go | 1 + test/config/config_test.go | 19 +++++++++++++++++++ test/limiter/base_limiter_test.go | 1 + test/memcached/cache_impl_test.go | 22 ++++++++++++++++++++++ test/redis/fixed_cache_impl_test.go | 18 ++++++++++++++++++ 7 files changed, 63 insertions(+) diff --git a/src/config/config.go b/src/config/config.go index 43ffbfa1..8ee14535 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -20,6 +20,7 @@ type RateLimitStats struct { OverLimit stats.Counter NearLimit stats.Counter OverLimitWithLocalCache stats.Counter + WithinLimit stats.Counter } // Wrapper for an individual rate limit config entry which includes the defined limit and stats. diff --git a/src/config/config_impl.go b/src/config/config_impl.go index e19b5ce0..b5118f5e 100644 --- a/src/config/config_impl.go +++ b/src/config/config_impl.go @@ -63,6 +63,7 @@ func newRateLimitStats(statsScope stats.Scope, key string) RateLimitStats { ret.OverLimit = statsScope.NewCounter(key + ".over_limit") ret.NearLimit = statsScope.NewCounter(key + ".near_limit") ret.OverLimitWithLocalCache = statsScope.NewCounter(key + ".over_limit_with_local_cache") + ret.WithinLimit = statsScope.NewCounter(key + ".within_limit") return ret } diff --git a/src/limiter/base_limiter.go b/src/limiter/base_limiter.go index 4a9aec1d..44c2633e 100644 --- a/src/limiter/base_limiter.go +++ b/src/limiter/base_limiter.go @@ -110,6 +110,7 @@ func (this *BaseRateLimiter) GetResponseDescriptorStatus(key string, limitInfo * // The limit is OK but we additionally want to know if we are near the limit. checkNearLimitThreshold(limitInfo, hitsAddend) + limitInfo.limit.Stats.WithinLimit.Add(uint64(hitsAddend)) } return responseDescriptorStatus } diff --git a/test/config/config_test.go b/test/config/config_test.go index 96638165..4a244bce 100644 --- a/test/config/config_test.go +++ b/test/config/config_test.go @@ -65,11 +65,13 @@ func TestBasicConfig(t *testing.T) { rl.Stats.TotalHits.Inc() rl.Stats.OverLimit.Inc() rl.Stats.NearLimit.Inc() + rl.Stats.WithinLimit.Inc() assert.EqualValues(5, rl.Limit.RequestsPerUnit) assert.Equal(pb.RateLimitResponse_RateLimit_SECOND, rl.Limit.Unit) assert.EqualValues(1, stats.NewCounter("test-domain.key1_value1.subkey1.total_hits").Value()) assert.EqualValues(1, stats.NewCounter("test-domain.key1_value1.subkey1.over_limit").Value()) assert.EqualValues(1, stats.NewCounter("test-domain.key1_value1.subkey1.near_limit").Value()) + assert.EqualValues(1, stats.NewCounter("test-domain.key1_value1.subkey1.within_limit").Value()) rl = rlConfig.GetLimit( nil, "test-domain", @@ -79,6 +81,7 @@ func TestBasicConfig(t *testing.T) { rl.Stats.TotalHits.Inc() rl.Stats.OverLimit.Inc() rl.Stats.NearLimit.Inc() + rl.Stats.WithinLimit.Inc() assert.EqualValues(10, rl.Limit.RequestsPerUnit) assert.Equal(pb.RateLimitResponse_RateLimit_SECOND, rl.Limit.Unit) assert.EqualValues( @@ -87,6 +90,8 @@ func TestBasicConfig(t *testing.T) { 1, stats.NewCounter("test-domain.key1_value1.subkey1_subvalue1.over_limit").Value()) assert.EqualValues( 1, stats.NewCounter("test-domain.key1_value1.subkey1_subvalue1.near_limit").Value()) + assert.EqualValues( + 1, stats.NewCounter("test-domain.key1_value1.subkey1_subvalue1.within_limit").Value()) rl = rlConfig.GetLimit( nil, "test-domain", @@ -96,11 +101,13 @@ func TestBasicConfig(t *testing.T) { rl.Stats.TotalHits.Inc() rl.Stats.OverLimit.Inc() rl.Stats.NearLimit.Inc() + rl.Stats.WithinLimit.Inc() assert.EqualValues(20, rl.Limit.RequestsPerUnit) assert.Equal(pb.RateLimitResponse_RateLimit_MINUTE, rl.Limit.Unit) assert.EqualValues(1, stats.NewCounter("test-domain.key2.total_hits").Value()) assert.EqualValues(1, stats.NewCounter("test-domain.key2.over_limit").Value()) assert.EqualValues(1, stats.NewCounter("test-domain.key2.near_limit").Value()) + assert.EqualValues(1, stats.NewCounter("test-domain.key2.within_limit").Value()) rl = rlConfig.GetLimit( nil, "test-domain", @@ -110,11 +117,13 @@ func TestBasicConfig(t *testing.T) { rl.Stats.TotalHits.Inc() rl.Stats.OverLimit.Inc() rl.Stats.NearLimit.Inc() + rl.Stats.WithinLimit.Inc() assert.EqualValues(30, rl.Limit.RequestsPerUnit) assert.Equal(pb.RateLimitResponse_RateLimit_MINUTE, rl.Limit.Unit) assert.EqualValues(1, stats.NewCounter("test-domain.key2_value2.total_hits").Value()) assert.EqualValues(1, stats.NewCounter("test-domain.key2_value2.over_limit").Value()) assert.EqualValues(1, stats.NewCounter("test-domain.key2_value2.near_limit").Value()) + assert.EqualValues(1, stats.NewCounter("test-domain.key2_value2.within_limit").Value()) rl = rlConfig.GetLimit( nil, "test-domain", @@ -131,11 +140,13 @@ func TestBasicConfig(t *testing.T) { rl.Stats.TotalHits.Inc() rl.Stats.OverLimit.Inc() rl.Stats.NearLimit.Inc() + rl.Stats.WithinLimit.Inc() assert.EqualValues(1, rl.Limit.RequestsPerUnit) assert.Equal(pb.RateLimitResponse_RateLimit_HOUR, rl.Limit.Unit) assert.EqualValues(1, stats.NewCounter("test-domain.key3.total_hits").Value()) assert.EqualValues(1, stats.NewCounter("test-domain.key3.over_limit").Value()) assert.EqualValues(1, stats.NewCounter("test-domain.key3.near_limit").Value()) + assert.EqualValues(1, stats.NewCounter("test-domain.key3.within_limit").Value()) rl = rlConfig.GetLimit( nil, "test-domain", @@ -145,11 +156,13 @@ func TestBasicConfig(t *testing.T) { rl.Stats.TotalHits.Inc() rl.Stats.OverLimit.Inc() rl.Stats.NearLimit.Inc() + rl.Stats.WithinLimit.Inc() assert.EqualValues(1, rl.Limit.RequestsPerUnit) assert.Equal(pb.RateLimitResponse_RateLimit_DAY, rl.Limit.Unit) assert.EqualValues(1, stats.NewCounter("test-domain.key4.total_hits").Value()) assert.EqualValues(1, stats.NewCounter("test-domain.key4.over_limit").Value()) assert.EqualValues(1, stats.NewCounter("test-domain.key4.near_limit").Value()) + assert.EqualValues(1, stats.NewCounter("test-domain.key4.within_limit").Value()) } func TestConfigLimitOverride(t *testing.T) { @@ -179,9 +192,11 @@ func TestConfigLimitOverride(t *testing.T) { rl.Stats.TotalHits.Inc() rl.Stats.OverLimit.Inc() rl.Stats.NearLimit.Inc() + rl.Stats.WithinLimit.Inc() assert.EqualValues(1, stats.NewCounter("test-domain.key1_value1.subkey1_something.total_hits").Value()) assert.EqualValues(1, stats.NewCounter("test-domain.key1_value1.subkey1_something.over_limit").Value()) assert.EqualValues(1, stats.NewCounter("test-domain.key1_value1.subkey1_something.near_limit").Value()) + assert.EqualValues(1, stats.NewCounter("test-domain.key1_value1.subkey1_something.within_limit").Value()) // Change in override value doesn't erase stats rl = rlConfig.GetLimit( @@ -196,6 +211,7 @@ func TestConfigLimitOverride(t *testing.T) { rl.Stats.TotalHits.Inc() rl.Stats.OverLimit.Inc() rl.Stats.NearLimit.Inc() + rl.Stats.WithinLimit.Inc() common.AssertProtoEqual(assert, &pb.RateLimitResponse_RateLimit{ RequestsPerUnit: 42, Unit: pb.RateLimitResponse_RateLimit_HOUR, @@ -203,6 +219,7 @@ func TestConfigLimitOverride(t *testing.T) { assert.EqualValues(2, stats.NewCounter("test-domain.key1_value1.subkey1_something.total_hits").Value()) assert.EqualValues(2, stats.NewCounter("test-domain.key1_value1.subkey1_something.over_limit").Value()) assert.EqualValues(2, stats.NewCounter("test-domain.key1_value1.subkey1_something.near_limit").Value()) + assert.EqualValues(2, stats.NewCounter("test-domain.key1_value1.subkey1_something.within_limit").Value()) // Different value creates a different counter rl = rlConfig.GetLimit( @@ -221,9 +238,11 @@ func TestConfigLimitOverride(t *testing.T) { rl.Stats.TotalHits.Inc() rl.Stats.OverLimit.Inc() rl.Stats.NearLimit.Inc() + rl.Stats.WithinLimit.Inc() assert.EqualValues(1, stats.NewCounter("test-domain.key1_value1.subkey1_something_else.total_hits").Value()) assert.EqualValues(1, stats.NewCounter("test-domain.key1_value1.subkey1_something_else.over_limit").Value()) assert.EqualValues(1, stats.NewCounter("test-domain.key1_value1.subkey1_something_else.near_limit").Value()) + assert.EqualValues(1, stats.NewCounter("test-domain.key1_value1.subkey1_something_else.within_limit").Value()) } func expectConfigPanic(t *testing.T, call func(), expectedError string) { diff --git a/test/limiter/base_limiter_test.go b/test/limiter/base_limiter_test.go index 94b63d77..41aa0e5b 100644 --- a/test/limiter/base_limiter_test.go +++ b/test/limiter/base_limiter_test.go @@ -141,4 +141,5 @@ func TestGetResponseStatusBelowLimit(t *testing.T) { assert.Equal(uint32(4), responseStatus.GetLimitRemaining()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) assert.Equal(limits[0].Limit, responseStatus.GetCurrentLimit()) + assert.Equal(uint64(1), limits[0].Stats.WithinLimit.Value()) } diff --git a/test/memcached/cache_impl_test.go b/test/memcached/cache_impl_test.go index 847b76f4..1e2ba8d7 100644 --- a/test/memcached/cache_impl_test.go +++ b/test/memcached/cache_impl_test.go @@ -51,6 +51,7 @@ func TestMemcached(t *testing.T) { assert.Equal(uint64(1), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(1), limits[0].Stats.WithinLimit.Value()) timeSource.EXPECT().UnixNow().Return(int64(1234)).MaxTimes(3) client.EXPECT().GetMulti([]string{"domain_key2_value2_subkey2_subvalue2_1200"}).Return( @@ -74,6 +75,7 @@ func TestMemcached(t *testing.T) { assert.Equal(uint64(1), limits[1].Stats.TotalHits.Value()) assert.Equal(uint64(1), limits[1].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[1].Stats.NearLimit.Value()) + assert.Equal(uint64(0), limits[1].Stats.WithinLimit.Value()) timeSource.EXPECT().UnixNow().Return(int64(1000000)).MaxTimes(5) client.EXPECT().GetMulti([]string{ @@ -105,9 +107,11 @@ func TestMemcached(t *testing.T) { assert.Equal(uint64(1), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(1), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(0), limits[0].Stats.WithinLimit.Value()) assert.Equal(uint64(1), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(1), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(0), limits[0].Stats.WithinLimit.Value()) cache.Flush() } @@ -137,6 +141,7 @@ func TestMemcachedGetError(t *testing.T) { assert.Equal(uint64(1), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(1), limits[0].Stats.WithinLimit.Value()) // No error, but the key is missing timeSource.EXPECT().UnixNow().Return(int64(1234)).MaxTimes(3) @@ -154,6 +159,7 @@ func TestMemcachedGetError(t *testing.T) { assert.Equal(uint64(1), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(1), limits[0].Stats.WithinLimit.Value()) cache.Flush() } @@ -227,6 +233,7 @@ func TestOverLimitWithLocalCache(t *testing.T) { assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimitWithLocalCache.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(1), limits[0].Stats.WithinLimit.Value()) // Check the local cache stats. testLocalCacheStats(localCacheStats, statsStore, sink, 0, 1, 1, 0, 0) @@ -246,6 +253,7 @@ func TestOverLimitWithLocalCache(t *testing.T) { assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimitWithLocalCache.Value()) assert.Equal(uint64(1), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(2), limits[0].Stats.WithinLimit.Value()) // Check the local cache stats. testLocalCacheStats(localCacheStats, statsStore, sink, 0, 2, 2, 0, 0) @@ -265,6 +273,7 @@ func TestOverLimitWithLocalCache(t *testing.T) { assert.Equal(uint64(1), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimitWithLocalCache.Value()) assert.Equal(uint64(1), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(2), limits[0].Stats.WithinLimit.Value()) // Check the local cache stats. testLocalCacheStats(localCacheStats, statsStore, sink, 0, 2, 3, 0, 1) @@ -281,6 +290,7 @@ func TestOverLimitWithLocalCache(t *testing.T) { assert.Equal(uint64(2), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(1), limits[0].Stats.OverLimitWithLocalCache.Value()) assert.Equal(uint64(1), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(2), limits[0].Stats.WithinLimit.Value()) // Check the local cache stats. testLocalCacheStats(localCacheStats, statsStore, sink, 1, 3, 4, 0, 1) @@ -317,6 +327,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(1), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(1), limits[0].Stats.WithinLimit.Value()) // Test Near Limit Stats. At Near Limit Ratio, still OK timeSource.EXPECT().UnixNow().Return(int64(1000000)).MaxTimes(3) @@ -332,6 +343,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(2), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(1), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(2), limits[0].Stats.WithinLimit.Value()) // Test Near Limit Stats. We went OVER_LIMIT, but the near_limit counter only increases // when we are near limit, not after we have passed the limit. @@ -348,6 +360,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(3), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(1), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(1), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(2), limits[0].Stats.WithinLimit.Value()) // Now test hitsAddend that is greater than 1 // All of it under limit, under near limit @@ -366,6 +379,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(3), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(3), limits[0].Stats.WithinLimit.Value()) // All of it under limit, some over near limit timeSource.EXPECT().UnixNow().Return(int64(1234)).MaxTimes(3) @@ -383,6 +397,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(2), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(1), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(2), limits[0].Stats.WithinLimit.Value()) // All of it under limit, all of it over near limit timeSource.EXPECT().UnixNow().Return(int64(1234)).MaxTimes(3) @@ -400,6 +415,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(3), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(3), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(3), limits[0].Stats.WithinLimit.Value()) // Some of it over limit, all of it over near limit timeSource.EXPECT().UnixNow().Return(int64(1234)).MaxTimes(3) @@ -417,6 +433,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(3), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(2), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(1), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(0), limits[0].Stats.WithinLimit.Value()) // Some of it in all three places timeSource.EXPECT().UnixNow().Return(int64(1234)).MaxTimes(3) @@ -434,6 +451,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(7), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(2), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(4), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(0), limits[0].Stats.WithinLimit.Value()) // all of it over limit timeSource.EXPECT().UnixNow().Return(int64(1234)).MaxTimes(3) @@ -451,6 +469,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(3), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(3), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(0), limits[0].Stats.WithinLimit.Value()) cache.Flush() } @@ -493,6 +512,7 @@ func TestMemcacheWithJitter(t *testing.T) { assert.Equal(uint64(1), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(1), limits[0].Stats.WithinLimit.Value()) cache.Flush() } @@ -534,6 +554,7 @@ func TestMemcacheAdd(t *testing.T) { assert.Equal(uint64(1), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(1), limits[0].Stats.WithinLimit.Value()) // A rate limit with 1-minute window timeSource.EXPECT().UnixNow().Return(int64(1234)).MaxTimes(3) @@ -557,6 +578,7 @@ func TestMemcacheAdd(t *testing.T) { assert.Equal(uint64(1), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(1), limits[0].Stats.WithinLimit.Value()) cache.Flush() } diff --git a/test/redis/fixed_cache_impl_test.go b/test/redis/fixed_cache_impl_test.go index 080d617d..65883f4b 100644 --- a/test/redis/fixed_cache_impl_test.go +++ b/test/redis/fixed_cache_impl_test.go @@ -69,6 +69,7 @@ func testRedis(usePerSecondRedis bool) func(*testing.T) { assert.Equal(uint64(1), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(1), limits[0].Stats.WithinLimit.Value()) clientUsed = client timeSource.EXPECT().UnixNow().Return(int64(1234)).MaxTimes(3) @@ -93,6 +94,7 @@ func testRedis(usePerSecondRedis bool) func(*testing.T) { assert.Equal(uint64(1), limits[1].Stats.TotalHits.Value()) assert.Equal(uint64(1), limits[1].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[1].Stats.NearLimit.Value()) + assert.Equal(uint64(0), limits[1].Stats.WithinLimit.Value()) clientUsed = client timeSource.EXPECT().UnixNow().Return(int64(1000000)).MaxTimes(5) @@ -121,9 +123,11 @@ func testRedis(usePerSecondRedis bool) func(*testing.T) { assert.Equal(uint64(1), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(1), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(0), limits[0].Stats.WithinLimit.Value()) assert.Equal(uint64(1), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(1), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(0), limits[0].Stats.WithinLimit.Value()) } } @@ -196,6 +200,7 @@ func TestOverLimitWithLocalCache(t *testing.T) { assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimitWithLocalCache.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(1), limits[0].Stats.WithinLimit.Value()) // Check the local cache stats. testLocalCacheStats(localCacheStats, statsStore, sink, 0, 1, 1, 0, 0) @@ -215,6 +220,7 @@ func TestOverLimitWithLocalCache(t *testing.T) { assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimitWithLocalCache.Value()) assert.Equal(uint64(1), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(2), limits[0].Stats.WithinLimit.Value()) // Check the local cache stats. testLocalCacheStats(localCacheStats, statsStore, sink, 0, 2, 2, 0, 0) @@ -234,6 +240,7 @@ func TestOverLimitWithLocalCache(t *testing.T) { assert.Equal(uint64(1), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimitWithLocalCache.Value()) assert.Equal(uint64(1), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(2), limits[0].Stats.WithinLimit.Value()) // Check the local cache stats. testLocalCacheStats(localCacheStats, statsStore, sink, 0, 2, 3, 0, 1) @@ -251,6 +258,7 @@ func TestOverLimitWithLocalCache(t *testing.T) { assert.Equal(uint64(2), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(1), limits[0].Stats.OverLimitWithLocalCache.Value()) assert.Equal(uint64(1), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(2), limits[0].Stats.WithinLimit.Value()) // Check the local cache stats. testLocalCacheStats(localCacheStats, statsStore, sink, 1, 3, 4, 0, 1) @@ -285,6 +293,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(1), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(1), limits[0].Stats.WithinLimit.Value()) // Test Near Limit Stats. At Near Limit Ratio, still OK timeSource.EXPECT().UnixNow().Return(int64(1000000)).MaxTimes(3) @@ -300,6 +309,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(2), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(1), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(2), limits[0].Stats.WithinLimit.Value()) // Test Near Limit Stats. We went OVER_LIMIT, but the near_limit counter only increases // when we are near limit, not after we have passed the limit. @@ -316,6 +326,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(3), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(1), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(1), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(2), limits[0].Stats.WithinLimit.Value()) // Now test hitsAddend that is greater than 1 // All of it under limit, under near limit @@ -333,6 +344,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(3), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(3), limits[0].Stats.WithinLimit.Value()) // All of it under limit, some over near limit timeSource.EXPECT().UnixNow().Return(int64(1234)).MaxTimes(3) @@ -349,6 +361,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(2), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(1), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(2), limits[0].Stats.WithinLimit.Value()) // All of it under limit, all of it over near limit timeSource.EXPECT().UnixNow().Return(int64(1234)).MaxTimes(3) @@ -365,6 +378,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(3), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(3), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(3), limits[0].Stats.WithinLimit.Value()) // Some of it over limit, all of it over near limit timeSource.EXPECT().UnixNow().Return(int64(1234)).MaxTimes(3) @@ -381,6 +395,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(3), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(2), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(1), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(0), limits[0].Stats.WithinLimit.Value()) // Some of it in all three places timeSource.EXPECT().UnixNow().Return(int64(1234)).MaxTimes(3) @@ -397,6 +412,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(7), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(2), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(4), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(0), limits[0].Stats.WithinLimit.Value()) // all of it over limit timeSource.EXPECT().UnixNow().Return(int64(1234)).MaxTimes(3) @@ -413,6 +429,7 @@ func TestNearLimit(t *testing.T) { assert.Equal(uint64(3), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(3), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(0), limits[0].Stats.WithinLimit.Value()) } func TestRedisWithJitter(t *testing.T) { @@ -441,4 +458,5 @@ func TestRedisWithJitter(t *testing.T) { assert.Equal(uint64(1), limits[0].Stats.TotalHits.Value()) assert.Equal(uint64(0), limits[0].Stats.OverLimit.Value()) assert.Equal(uint64(0), limits[0].Stats.NearLimit.Value()) + assert.Equal(uint64(1), limits[0].Stats.WithinLimit.Value()) } From 9e3bcb8453233ff3170989bbd5c2a1311bcd8eb6 Mon Sep 17 00:00:00 2001 From: Jia Hao Date: Wed, 3 Mar 2021 18:47:08 -0500 Subject: [PATCH 2/3] fix formatting Signed-off-by: Jia Hao --- src/config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/config.go b/src/config/config.go index 8ee14535..83ed972b 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -20,7 +20,7 @@ type RateLimitStats struct { OverLimit stats.Counter NearLimit stats.Counter OverLimitWithLocalCache stats.Counter - WithinLimit stats.Counter + WithinLimit stats.Counter } // Wrapper for an individual rate limit config entry which includes the defined limit and stats. From f1308b5fb987566efb17506baca48ee7d6fec2c9 Mon Sep 17 00:00:00 2001 From: Jia Hao Date: Wed, 3 Mar 2021 19:37:59 -0500 Subject: [PATCH 3/3] add within_limit counter to prom statsd exporter config Signed-off-by: Jia Hao --- examples/prom-statsd-exporter/conf.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/examples/prom-statsd-exporter/conf.yaml b/examples/prom-statsd-exporter/conf.yaml index 0706548d..1e47ef98 100644 --- a/examples/prom-statsd-exporter/conf.yaml +++ b/examples/prom-statsd-exporter/conf.yaml @@ -20,6 +20,13 @@ mappings: # Requires statsd exporter >= v0.6.0 since it uses the "drop" action. labels: domain: "$1" key1: "$2" + - match: + "ratelimit.service.rate_limit.*.*.within_limit" + name: "ratelimit_service_rate_limit_within_limit" + timer_type: "histogram" + labels: + domain: "$1" + key1: "$2" - match: "ratelimit.service.rate_limit.*.*.*.near_limit" @@ -45,6 +52,14 @@ mappings: # Requires statsd exporter >= v0.6.0 since it uses the "drop" action. domain: "$1" key1: "$2" key2: "$3" + - match: + "ratelimit.service.rate_limit.*.*.*.within_limit" + name: "ratelimit_service_rate_limit_within_limit" + timer_type: "histogram" + labels: + domain: "$1" + key1: "$2" + key2: "$3" - match: "ratelimit.service.call.should_rate_limit.*" name: "ratelimit_service_should_rate_limit_error"