blob: 69170e4a2ea53889b10579681529868398248169 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#ifndef AOS_UTIL_LOG_INTERVAL_H_
2#define AOS_UTIL_LOG_INTERVAL_H_
Brian Silverman01f0d222014-02-16 01:09:11 -08003
John Park33858a32018-09-28 23:05:48 -07004#include "aos/logging/logging.h"
James Kuszmaul651fc3f2019-05-15 21:14:25 -07005#include "aos/time/time.h"
Brian Silverman01f0d222014-02-16 01:09:11 -08006
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 {
Austin Schuhf2a50ba2016-12-24 16:16:26 -080015// static LogInterval interval(::std::chrono::millseconds(200));
Brian Silverman01f0d222014-02-16 01:09:11 -080016//
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(),
James Kuszmaul651fc3f2019-05-15 21:14:25 -070081 ::aos::time::DurationInSeconds(interval_.interval()));
Brian Silverman9c9ab422014-02-25 13:42:53 -080082 context_ = NULL;
Brian Silverman01f0d222014-02-16 01:09:11 -080083 }
84 }
85
86 private:
87 LogInterval interval_;
88 const log_level level_;
89 const ::std::string message_;
Brian Silverman9c9ab422014-02-25 13:42:53 -080090 const char *context_ = NULL;
Brian Silverman01f0d222014-02-16 01:09:11 -080091};
92
93} // namespace util
94} // namespace aos
95
John Park33858a32018-09-28 23:05:48 -070096#endif // AOS_UTIL_LOG_INTERVAL_H_