Loading include/log/log.h +49 −1 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ #include <stdint.h> /* uint16_t, int32_t */ #include <stdio.h> #include <sys/types.h> #include <time.h> /* clock_gettime */ #include <time.h> #include <unistd.h> #include <android/log.h> Loading Loading @@ -812,6 +812,54 @@ int __android_log_error_write(int tag, const char* subTag, int32_t uid, void __android_log_close(); #endif #ifndef __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE #ifndef __ANDROID_API__ #define __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE 1 #elif __ANDROID_API__ > 25 /* > OC */ #define __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE 1 #else #define __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE 0 #endif #endif #if __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE /* * if last is NULL, caller _must_ provide a consistent value for seconds. * * Return -1 if we can not acquire a lock, which below will permit the logging, * error on allowing a log message through. */ int __android_log_ratelimit(time_t seconds, time_t* last); /* * Usage: * * // Global default and state * IF_ALOG_RATELIMIT() { * ALOG*(...); * } * * // local state, 10 seconds ratelimit * static time_t local_state; * IF_ALOG_RATELIMIT_LOCAL(10, &local_state) { * ALOG*(...); * } */ #define IF_ALOG_RATELIMIT() \ if (__android_log_ratelimit(0, NULL) > 0) #define IF_ALOG_RATELIMIT_LOCAL(seconds, state) \ if (__android_log_ratelimit(seconds, state) > 0) #else /* No ratelimiting as API unsupported */ #define IF_ALOG_RATELIMIT() if (1) #define IF_ALOG_RATELIMIT_LOCAL(...) if (1) #endif #if defined(__clang__) #pragma clang diagnostic pop #endif Loading liblog/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ liblog_sources = [ "config_write.c", "logger_name.c", "logger_lock.c", "log_ratelimit.cpp", ] liblog_host_sources = [ "fake_log_device.c", Loading liblog/log_ratelimit.cpp 0 → 100644 +86 −0 Original line number Diff line number Diff line /* ** Copyright 2016, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #include <errno.h> #include <pthread.h> #include <time.h> #include <log/log.h> #include "log_portability.h" // Global default if 'last' argument in __android_log_ratelimit is NULL static time_t g_last_clock; // Global above can not deal well with callers playing games with the // seconds argument, so we will also hold on to the maximum value // ever provided and use that to gain consistency. If the caller // provides their own 'last' argument, then they can play such games // of varying the 'seconds' argument to their pleasure. static time_t g_last_seconds; static const time_t last_seconds_default = 10; static const time_t last_seconds_max = 24 * 60 * 60; // maximum of a day static const time_t last_seconds_min = 2; // granularity // Lock to protect last_clock and last_seconds, but also 'last' // argument (not NULL) as supplied to __android_log_ratelimit. static pthread_mutex_t lock_ratelimit = PTHREAD_MUTEX_INITIALIZER; // if last is NULL, caller _must_ provide a consistent value for // seconds, otherwise we will take the maximum ever issued and hold // on to that. Preserves value of non-zero errno. Return -1 if we // can not acquire a lock, 0 if we are not to log a message, and 1 // if we are ok to log a message. Caller should check > 0 for true. LIBLOG_ABI_PUBLIC int __android_log_ratelimit(time_t seconds, time_t* last) { int save_errno = errno; // Two reasons for trylock failure: // 1. In a signal handler. Must prevent deadlock // 2. Too many threads calling __android_log_ratelimit. // Bonus to not print if they race here because that // dovetails the goal of ratelimiting. One may print // and the others will wait their turn ... if (pthread_mutex_trylock(&lock_ratelimit)) { if (save_errno) errno = save_errno; return -1; } if (seconds == 0) { seconds = last_seconds_default; } else if (seconds < last_seconds_min) { seconds = last_seconds_min; } else if (seconds > last_seconds_max) { seconds = last_seconds_max; } if (!last) { if (g_last_seconds > seconds) { seconds = g_last_seconds; } else if (g_last_seconds < seconds) { g_last_seconds = seconds; } last = &g_last_clock; } time_t now = time(NULL); if ((now == (time_t)-1) || ((*last + seconds) > now)) { pthread_mutex_unlock(&lock_ratelimit); if (save_errno) errno = save_errno; return 0; } *last = now; pthread_mutex_unlock(&lock_ratelimit); if (save_errno) errno = save_errno; return 1; } liblog/tests/liblog_test.cpp +32 −0 Original line number Diff line number Diff line Loading @@ -2870,3 +2870,35 @@ TEST(liblog, event_log_tags) { GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } TEST(liblog, __android_log_ratelimit) { time_t state = 0; errno = 42; // Prime __android_log_ratelimit(3, &state); EXPECT_EQ(errno, 42); // Check EXPECT_FALSE(__android_log_ratelimit(3, &state)); sleep(1); EXPECT_FALSE(__android_log_ratelimit(3, &state)); sleep(4); EXPECT_TRUE(__android_log_ratelimit(3, &state)); sleep(5); EXPECT_TRUE(__android_log_ratelimit(3, &state)); // API checks IF_ALOG_RATELIMIT_LOCAL(3, &state) { EXPECT_FALSE(0 != "IF_ALOG_RATELIMIT_LOCAL(3, &state)"); } IF_ALOG_RATELIMIT() { ; } else { EXPECT_TRUE(0 == "IF_ALOG_RATELIMIT()"); } IF_ALOG_RATELIMIT() { EXPECT_FALSE(0 != "IF_ALOG_RATELIMIT()"); } // Do not test default seconds, to allow liblog to tune freely } Loading
include/log/log.h +49 −1 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ #include <stdint.h> /* uint16_t, int32_t */ #include <stdio.h> #include <sys/types.h> #include <time.h> /* clock_gettime */ #include <time.h> #include <unistd.h> #include <android/log.h> Loading Loading @@ -812,6 +812,54 @@ int __android_log_error_write(int tag, const char* subTag, int32_t uid, void __android_log_close(); #endif #ifndef __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE #ifndef __ANDROID_API__ #define __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE 1 #elif __ANDROID_API__ > 25 /* > OC */ #define __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE 1 #else #define __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE 0 #endif #endif #if __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE /* * if last is NULL, caller _must_ provide a consistent value for seconds. * * Return -1 if we can not acquire a lock, which below will permit the logging, * error on allowing a log message through. */ int __android_log_ratelimit(time_t seconds, time_t* last); /* * Usage: * * // Global default and state * IF_ALOG_RATELIMIT() { * ALOG*(...); * } * * // local state, 10 seconds ratelimit * static time_t local_state; * IF_ALOG_RATELIMIT_LOCAL(10, &local_state) { * ALOG*(...); * } */ #define IF_ALOG_RATELIMIT() \ if (__android_log_ratelimit(0, NULL) > 0) #define IF_ALOG_RATELIMIT_LOCAL(seconds, state) \ if (__android_log_ratelimit(seconds, state) > 0) #else /* No ratelimiting as API unsupported */ #define IF_ALOG_RATELIMIT() if (1) #define IF_ALOG_RATELIMIT_LOCAL(...) if (1) #endif #if defined(__clang__) #pragma clang diagnostic pop #endif Loading
liblog/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ liblog_sources = [ "config_write.c", "logger_name.c", "logger_lock.c", "log_ratelimit.cpp", ] liblog_host_sources = [ "fake_log_device.c", Loading
liblog/log_ratelimit.cpp 0 → 100644 +86 −0 Original line number Diff line number Diff line /* ** Copyright 2016, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #include <errno.h> #include <pthread.h> #include <time.h> #include <log/log.h> #include "log_portability.h" // Global default if 'last' argument in __android_log_ratelimit is NULL static time_t g_last_clock; // Global above can not deal well with callers playing games with the // seconds argument, so we will also hold on to the maximum value // ever provided and use that to gain consistency. If the caller // provides their own 'last' argument, then they can play such games // of varying the 'seconds' argument to their pleasure. static time_t g_last_seconds; static const time_t last_seconds_default = 10; static const time_t last_seconds_max = 24 * 60 * 60; // maximum of a day static const time_t last_seconds_min = 2; // granularity // Lock to protect last_clock and last_seconds, but also 'last' // argument (not NULL) as supplied to __android_log_ratelimit. static pthread_mutex_t lock_ratelimit = PTHREAD_MUTEX_INITIALIZER; // if last is NULL, caller _must_ provide a consistent value for // seconds, otherwise we will take the maximum ever issued and hold // on to that. Preserves value of non-zero errno. Return -1 if we // can not acquire a lock, 0 if we are not to log a message, and 1 // if we are ok to log a message. Caller should check > 0 for true. LIBLOG_ABI_PUBLIC int __android_log_ratelimit(time_t seconds, time_t* last) { int save_errno = errno; // Two reasons for trylock failure: // 1. In a signal handler. Must prevent deadlock // 2. Too many threads calling __android_log_ratelimit. // Bonus to not print if they race here because that // dovetails the goal of ratelimiting. One may print // and the others will wait their turn ... if (pthread_mutex_trylock(&lock_ratelimit)) { if (save_errno) errno = save_errno; return -1; } if (seconds == 0) { seconds = last_seconds_default; } else if (seconds < last_seconds_min) { seconds = last_seconds_min; } else if (seconds > last_seconds_max) { seconds = last_seconds_max; } if (!last) { if (g_last_seconds > seconds) { seconds = g_last_seconds; } else if (g_last_seconds < seconds) { g_last_seconds = seconds; } last = &g_last_clock; } time_t now = time(NULL); if ((now == (time_t)-1) || ((*last + seconds) > now)) { pthread_mutex_unlock(&lock_ratelimit); if (save_errno) errno = save_errno; return 0; } *last = now; pthread_mutex_unlock(&lock_ratelimit); if (save_errno) errno = save_errno; return 1; }
liblog/tests/liblog_test.cpp +32 −0 Original line number Diff line number Diff line Loading @@ -2870,3 +2870,35 @@ TEST(liblog, event_log_tags) { GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } TEST(liblog, __android_log_ratelimit) { time_t state = 0; errno = 42; // Prime __android_log_ratelimit(3, &state); EXPECT_EQ(errno, 42); // Check EXPECT_FALSE(__android_log_ratelimit(3, &state)); sleep(1); EXPECT_FALSE(__android_log_ratelimit(3, &state)); sleep(4); EXPECT_TRUE(__android_log_ratelimit(3, &state)); sleep(5); EXPECT_TRUE(__android_log_ratelimit(3, &state)); // API checks IF_ALOG_RATELIMIT_LOCAL(3, &state) { EXPECT_FALSE(0 != "IF_ALOG_RATELIMIT_LOCAL(3, &state)"); } IF_ALOG_RATELIMIT() { ; } else { EXPECT_TRUE(0 == "IF_ALOG_RATELIMIT()"); } IF_ALOG_RATELIMIT() { EXPECT_FALSE(0 != "IF_ALOG_RATELIMIT()"); } // Do not test default seconds, to allow liblog to tune freely }