breadcrumb_manager.cc 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/breadcrumbs/core/breadcrumb_manager.h"
  5. #include "base/containers/adapters.h"
  6. #include "base/format_macros.h"
  7. #include "base/observer_list.h"
  8. #include "base/strings/stringprintf.h"
  9. #include "components/breadcrumbs/core/breadcrumb_manager_observer.h"
  10. #include "components/breadcrumbs/core/crash_reporter_breadcrumb_constants.h"
  11. namespace breadcrumbs {
  12. namespace {
  13. // The maximum number of breadcrumbs which are expected to be useful to store.
  14. // NOTE: Events are "bucketed" into groups by short time intervals to make it
  15. // more efficient to manage the continuous dropping of old events. Since events
  16. // are only dropped at the bucket level, it is expected that the total number of
  17. // stored breadcrumbs will exceed this value. This value should be close to the
  18. // upper limit of useful events. (Most events + timestamp breadcrumbs are
  19. // currently longer than 10 characters.)
  20. constexpr unsigned long kMaxUsefulBreadcrumbEvents = kMaxDataLength / 10;
  21. // The minimum number of event buckets to keep, even if they are expired.
  22. const int kMinEventBuckets = 2;
  23. // The time, in minutes, after which events are removed (unless there are fewer
  24. // than |kMinEventBuckets| event buckets, in which case no time limit applies).
  25. const int kEventExpirationMinutes = 20;
  26. } // namespace
  27. BreadcrumbManager::BreadcrumbManager(base::TimeTicks start_time)
  28. : start_time_(start_time) {}
  29. BreadcrumbManager::~BreadcrumbManager() = default;
  30. const std::list<std::string> BreadcrumbManager::GetEvents(
  31. size_t event_count_limit) {
  32. DropOldEvents();
  33. std::list<std::string> events;
  34. for (const EventBucket& event_bucket : base::Reversed(event_buckets_)) {
  35. for (const std::string& event : base::Reversed(event_bucket.events)) {
  36. events.push_front(event);
  37. if (event_count_limit > 0 && events.size() >= event_count_limit) {
  38. return events;
  39. }
  40. }
  41. }
  42. return events;
  43. }
  44. void BreadcrumbManager::AddEvent(const std::string& event) {
  45. DCHECK_EQ(std::string::npos, event.find('\n'));
  46. const base::TimeDelta elapsed_time = GetElapsedTime();
  47. // If a bucket exists, it will be at the end of the list.
  48. const int minutes_elapsed = elapsed_time.InMinutes();
  49. if (event_buckets_.empty() ||
  50. event_buckets_.back().minutes_elapsed != minutes_elapsed) {
  51. event_buckets_.emplace_back(minutes_elapsed);
  52. }
  53. // Prepend a timestamp containing elapsed time in H:MM:SS format. This is
  54. // preferred over base::TimeDurationWithSeconds() and wall-clock time to
  55. // avoid revealing client language or time zone.
  56. const int64_t total_seconds = elapsed_time.InSeconds();
  57. const int64_t hours = total_seconds / base::Time::kSecondsPerHour;
  58. const int64_t minutes = (total_seconds / base::Time::kSecondsPerMinute) %
  59. base::Time::kMinutesPerHour;
  60. const int64_t seconds = total_seconds % base::Time::kSecondsPerMinute;
  61. const std::string event_log =
  62. base::StringPrintf("%" PRIu64 ":%02" PRIu64 ":%02" PRIu64 " %s", hours,
  63. minutes, seconds, event.c_str());
  64. event_buckets_.back().events.push_back(event_log);
  65. for (auto& observer : observers_) {
  66. observer.EventAdded(this, event_log);
  67. }
  68. DropOldEvents();
  69. }
  70. void BreadcrumbManager::DropOldEvents() {
  71. bool old_buckets_dropped = false;
  72. // Drop buckets that are more than kEventExpirationMinutes old.
  73. while (event_buckets_.size() > kMinEventBuckets) {
  74. const int oldest_bucket_minutes = event_buckets_.front().minutes_elapsed;
  75. if (GetElapsedTime().InMinutes() - oldest_bucket_minutes <
  76. kEventExpirationMinutes) {
  77. break;
  78. }
  79. event_buckets_.pop_front();
  80. old_buckets_dropped = true;
  81. }
  82. // Drop buckets if the data is unlikely to ever be needed.
  83. unsigned long newer_event_count = 0;
  84. auto event_bucket_it = event_buckets_.rbegin();
  85. while (event_bucket_it != event_buckets_.rend()) {
  86. const std::list<std::string>& bucket_events = event_bucket_it->events;
  87. if (newer_event_count > kMaxUsefulBreadcrumbEvents) {
  88. event_buckets_.erase(event_buckets_.begin(), event_bucket_it.base());
  89. old_buckets_dropped = true;
  90. break;
  91. }
  92. newer_event_count += bucket_events.size();
  93. ++event_bucket_it;
  94. }
  95. if (old_buckets_dropped) {
  96. for (auto& observer : observers_) {
  97. observer.OldEventsRemoved(this);
  98. }
  99. }
  100. }
  101. base::TimeDelta BreadcrumbManager::GetElapsedTime() {
  102. return base::TimeTicks::Now() - start_time_;
  103. }
  104. void BreadcrumbManager::AddObserver(BreadcrumbManagerObserver* observer) {
  105. observers_.AddObserver(observer);
  106. }
  107. void BreadcrumbManager::RemoveObserver(BreadcrumbManagerObserver* observer) {
  108. observers_.RemoveObserver(observer);
  109. }
  110. BreadcrumbManager::EventBucket::EventBucket(int minutes_elapsed)
  111. : minutes_elapsed(minutes_elapsed) {}
  112. BreadcrumbManager::EventBucket::EventBucket(const EventBucket&) = default;
  113. BreadcrumbManager::EventBucket::~EventBucket() = default;
  114. } // namespace breadcrumbs