liblog: add IF_ALOG_RATELIMIT
IF_ALOG_RATELIMIT()
ALOGE("Only one message globally using IF_ALOG_RATELIMIT()"
" in the process may appear ever ten seconds,"
" (%s)", strerror(errno));
static time_t last; /* initial state zero */
IF_ALOG_RATELIMIT_LOCAL(60, &last)
ALOGE("Only one message locally may appear every minute,"
" (%s)", strerror(errno));
These new calls are guaranteed not to affect the value of a
non-zero errno to simplify logging of errors. However, the
ALOGE calls in the above examples may update the errno value
upon their return.
Test: gTest liblog-unit-tests --gtest_filter=liblog.__android_log_ratelimit
Bug: 33535908
Change-Id: Id8cc192fc7d14504ffd418933cf88ae945c089f2
diff --git a/include/log/log.h b/include/log/log.h
index d6f0eb5..ece9ea6 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -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>
@@ -812,6 +812,54 @@
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