blob: 3a7a85f00367f1331e4e88966d288e20c194e72f [file] [log] [blame]
Brian Silverman01f0d222014-02-16 01:09:11 -08001#ifndef AOS_COMMON_UTIL_LOG_INTERVAL_H_
2#define AOS_COMMON_UTIL_LOG_INTERVAL_H_
3
4#include "aos/common/time.h"
5#include "aos/common/logging/logging.h"
6
7#include <string>
8
9namespace aos {
10namespace util {
11
12// A class to help with logging things that happen a lot only occasionally.
13//
14// Intended use {
15// static LogInterval interval(::aos::time::Time::InSeconds(0.2));
16//
17// if (WantToLog()) {
18// interval.WantToLog();
19// }
20// if (interval.ShouldLog()) {
21// LOG(DEBUG, "thingie happened! (%d times)\n", interval.Count());
22// }
23// }
24class LogInterval {
25 public:
Austin Schuh61bdc602016-12-04 19:10:10 -080026 constexpr LogInterval(::std::chrono::nanoseconds interval)
27 : interval_(interval) {}
Brian Silverman01f0d222014-02-16 01:09:11 -080028
29 void WantToLog() {
30 if (count_ == 0) {
Austin Schuh61bdc602016-12-04 19:10:10 -080031 last_done_ = ::aos::monotonic_clock::now();
Brian Silverman01f0d222014-02-16 01:09:11 -080032 }
33 ++count_;
34 }
35 bool ShouldLog() {
Austin Schuh61bdc602016-12-04 19:10:10 -080036 const ::aos::monotonic_clock::time_point now =
37 ::aos::monotonic_clock::now();
38 const bool r = now >= interval_ + last_done_ && count_ > 0;
Brian Silverman01f0d222014-02-16 01:09:11 -080039 if (r) {
40 last_done_ = now;
41 }
42 return r;
43 }
44 int Count() {
45 const int r = count_;
46 count_ = 0;
47 return r;
48 }
49
Austin Schuh61bdc602016-12-04 19:10:10 -080050 ::std::chrono::nanoseconds interval() const { return interval_; }
Brian Silverman50a9d032014-02-16 17:20:57 -080051
Brian Silverman01f0d222014-02-16 01:09:11 -080052 private:
Austin Schuh61bdc602016-12-04 19:10:10 -080053 int count_ = 0;
54 const ::std::chrono::nanoseconds interval_;
55 ::aos::monotonic_clock::time_point last_done_ =
56 ::aos::monotonic_clock::min_time;
Brian Silverman01f0d222014-02-16 01:09:11 -080057};
58
59// This one is even easier to use. It always logs with a message "%s %d
Brian Silverman9c9ab422014-02-25 13:42:53 -080060// times\n". Call LOG_INTERVAL wherever it should log and make sure Print gets
61// called often (ie not after a conditional return)
Brian Silverman01f0d222014-02-16 01:09:11 -080062class SimpleLogInterval {
63 public:
Austin Schuh61bdc602016-12-04 19:10:10 -080064 SimpleLogInterval(::std::chrono::nanoseconds interval, log_level level,
Brian Silverman01f0d222014-02-16 01:09:11 -080065 const ::std::string &message)
66 : interval_(interval), level_(level), message_(message) {}
67
68#define LOG_INTERVAL(simple_log) \
Brian Silverman9c9ab422014-02-25 13:42:53 -080069 simple_log.WantToLog(LOG_SOURCENAME ": " STRINGIFY(__LINE__))
70 void WantToLog(const char *context) {
71 context_ = context;
72 interval_.WantToLog();
73 }
74
75 void Print() {
Brian Silverman01f0d222014-02-16 01:09:11 -080076 if (interval_.ShouldLog()) {
Brian Silverman9c9ab422014-02-25 13:42:53 -080077 CHECK_NOTNULL(context_);
78 log_do(level_, "%s: %.*s %d times over %f sec\n", context_,
Brian Silverman97478342014-02-16 20:26:31 -080079 static_cast<int>(message_.size()), message_.data(),
Austin Schuh61bdc602016-12-04 19:10:10 -080080 interval_.Count(),
81 ::std::chrono::duration_cast<::std::chrono::duration<double>>(
82 interval_.interval()).count());
Brian Silverman9c9ab422014-02-25 13:42:53 -080083 context_ = NULL;
Brian Silverman01f0d222014-02-16 01:09:11 -080084 }
85 }
86
87 private:
88 LogInterval interval_;
89 const log_level level_;
90 const ::std::string message_;
Brian Silverman9c9ab422014-02-25 13:42:53 -080091 const char *context_ = NULL;
Brian Silverman01f0d222014-02-16 01:09:11 -080092};
93
94} // namespace util
95} // namespace aos
96
97#endif // AOS_COMMON_UTIL_LOG_INTERVAL_H_