Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4c5daa47 authored by Ken Mixter's avatar Ken Mixter
Browse files

Add weekly crash counters, refactor metrics_daemon, respect opt-in in library.

BUG=5340,5814

Change-Id: I2c207055f1ebe48051193395e2dbe38d9140b025

Review URL: http://codereview.chromium.org/3171023
parent ccd84c03
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -42,3 +42,10 @@ extern "C" int CMetricsLibrarySendEnumToUMA(CMetricsLibrary handle,
    return 0;
  return lib->SendEnumToUMA(std::string(name), sample, max);
}

extern "C" int CMetricsLibraryAreMetricsEnabled(CMetricsLibrary handle) {
  MetricsLibrary* lib = reinterpret_cast<MetricsLibrary*>(handle);
  if (lib == NULL)
    return 0;
  return lib->AreMetricsEnabled();
}
+8 −4
Original line number Diff line number Diff line
@@ -27,6 +27,10 @@ int CMetricsLibrarySendToUMA(CMetricsLibrary handle,
// C wrapper for MetricsLibrary::SendEnumToUMA.
int CMetricsLibrarySendEnumToUMA(CMetricsLibrary handle,
                                 const char* name, int sample, int max);

// C wrapper for MetricsLibrary::AreMetricsEnabled.
int CMetricsLibraryAreMetricsEnabled(CMetricsLibrary handle);

#if defined(__cplusplus)
}
#endif
+49 −12
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@

#include <base/eintr_wrapper.h>
#include <base/logging.h>
#include "metrics_library.h"

namespace chromeos_metrics {

@@ -31,8 +32,7 @@ void TaggedCounter::Record::Add(int32 count) {

// TaggedCounter implementation.
TaggedCounter::TaggedCounter()
    : filename_(NULL),
      reporter_(NULL),
    : reporter_(NULL),
      reporter_handle_(NULL),
      record_state_(kRecordInvalid) {}

@@ -72,12 +72,13 @@ void TaggedCounter::UpdateInternal(int32 tag, int32 count, bool flush) {
  }

  DLOG(INFO) << "tag: " << tag << " count: " << count << " flush: " << flush;
  DCHECK(filename_);
  DCHECK(!filename_.empty());

  // NOTE: The assumption is that this TaggedCounter object is the
  // sole owner of the persistent storage file so no locking is
  // necessary.
  int fd = HANDLE_EINTR(open(filename_, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR));
  int fd = HANDLE_EINTR(open(filename_.c_str(),
                             O_RDWR | O_CREAT, S_IRUSR | S_IWUSR));
  if (fd < 0) {
    PLOG(WARNING) << "Unable to open the persistent counter file";
    return;
@@ -183,21 +184,57 @@ void TaggedCounter::WriteRecord(int fd) {
  }
}

MetricsLibraryInterface* TaggedCounterReporter::metrics_lib_ = NULL;

TaggedCounterReporter::TaggedCounterReporter()
    : tagged_counter_(new TaggedCounter()),
      min_(0),
      max_(0),
      buckets_(0) {
}

TaggedCounterReporter::~TaggedCounterReporter() {
}

void TaggedCounterReporter::Init(const char* filename,
                                 const char* histogram_name,
                                 int min,
                                 int max,
                                 int buckets) {
  tagged_counter_->Init(filename, Report, this);
  histogram_name_ = histogram_name;
  min_ = min;
  max_ = max;
  buckets_ = buckets;
  CHECK(min_ >= 0);
  CHECK(max_ > min_);
  CHECK(buckets_ > 0);
}

void TaggedCounterReporter::Report(void* handle, int32 tag, int32 count) {
  TaggedCounterReporter* this_reporter =
      reinterpret_cast<TaggedCounterReporter*>(handle);
  DLOG(INFO) << "received metric: " << this_reporter->histogram_name_
             << " " << count << " " << this_reporter->min_ << " "
             << this_reporter->max_ << " " << this_reporter->buckets_;
  CHECK(metrics_lib_ != NULL);
  CHECK(this_reporter->buckets_ > 0);
  metrics_lib_->SendToUMA(this_reporter->histogram_name_,
                          count,
                          this_reporter->min_,
                          this_reporter->max_,
                          this_reporter->buckets_);
}

FrequencyCounter::FrequencyCounter() : cycle_duration_(1) {
}

FrequencyCounter::~FrequencyCounter() {
}

void FrequencyCounter::Init(const char* filename,
                            TaggedCounterInterface::Reporter reporter,
                            void* reporter_handle,
void FrequencyCounter::Init(TaggedCounterInterface* tagged_counter,
                            time_t cycle_duration) {
  // Allow tests to inject tagged_counter_ dependency.
  if (tagged_counter_.get() == NULL) {
    tagged_counter_.reset(new TaggedCounter());
  }
  tagged_counter_->Init(filename, reporter, reporter_handle);
  tagged_counter_.reset(tagged_counter);
  DCHECK(cycle_duration > 0);
  cycle_duration_ = cycle_duration;
}
+107 −22
Original line number Diff line number Diff line
@@ -5,12 +5,15 @@
#ifndef METRICS_COUNTER_H_
#define METRICS_COUNTER_H_

#include <string>
#include <time.h>

#include <base/basictypes.h>
#include <base/scoped_ptr.h>
#include <gtest/gtest_prod.h>  // for FRIEND_TEST

class MetricsLibraryInterface;

namespace chromeos_metrics {

// Constants useful for frequency statistics.
@@ -44,16 +47,6 @@ class TaggedCounterInterface {

  virtual ~TaggedCounterInterface() {}

  // Initializes the counter by providing the persistent storage
  // location |filename| and a |reporter| callback for reporting
  // aggregated counts. |reporter_handle| is sent to the |reporter|
  // along with the aggregated counts.
  //
  // NOTE: The assumption is that this object is the sole owner of the
  // persistent storage file so no locking is currently implemented.
  virtual void Init(const char* filename,
                    Reporter reporter, void* reporter_handle) = 0;

  // Adds |count| of events for the given |tag|. If there's an
  // existing aggregated count for a different tag, it's reported
  // through the reporter callback and discarded.
@@ -67,12 +60,21 @@ class TaggedCounterInterface {
class TaggedCounter : public TaggedCounterInterface {
 public:
  TaggedCounter();
  ~TaggedCounter();
  virtual ~TaggedCounter();

  // Initializes the counter by providing the persistent storage
  // location |filename| and a |reporter| callback for reporting
  // aggregated counts. |reporter_handle| is sent to the |reporter|
  // along with the aggregated counts.
  //
  // NOTE: The assumption is that this object is the sole owner of the
  // persistent storage file so no locking is currently implemented.
  virtual void Init(const char* filename,
                    Reporter reporter, void* reporter_handle);

  // Implementation of interface methods.
  void Init(const char* filename, Reporter reporter, void* reporter_handle);
  void Update(int32 tag, int32 count);
  void Flush();
  virtual void Update(int32 tag, int32 count);
  virtual void Flush();

 private:
  friend class RecordTest;
@@ -146,7 +148,7 @@ class TaggedCounter : public TaggedCounterInterface {
  void WriteRecord(int fd);

  // Persistent storage file path.
  const char* filename_;
  std::string filename_;

  // Aggregated data reporter callback and handle to pass-through.
  Reporter reporter_;
@@ -159,6 +161,71 @@ class TaggedCounter : public TaggedCounterInterface {
  RecordState record_state_;
};

// TaggedCounterReporter provides a TaggedCounterInterface which both
// counts tagged events and reports them up through the metrics
// library to UMA.
class TaggedCounterReporter : public TaggedCounterInterface {
 public:
  TaggedCounterReporter();
  virtual ~TaggedCounterReporter();

  // Set the metrics library used by all TaggedCounterReporter
  // instances.  We assume there is only one metrics library
  // shared amongst all reporters.
  static void SetMetricsLibraryInterface(MetricsLibraryInterface* metrics_lib) {
    metrics_lib_ = metrics_lib;
  }

  // Initializes the counter by providing the persistent storage
  // location |filename|, a |histogram_name| (a linear histogram) to
  // report to with |min|, |max|, and |buckets| attributes for the
  // histogram.
  virtual void Init(const char* filename,
                    const char* histogram_name,
                    int min,
                    int max,
                    int buckets);

  // Implementation of interface method.
  virtual void Update(int32 tag, int32 count) {
    tagged_counter_->Update(tag, count);
  }
  // Implementation of interface method.
  virtual void Flush() {
    tagged_counter_->Flush();
  }

  // Accessor functions.
  const std::string& histogram_name() const {
    return histogram_name_;
  }

  int min() const {
    return min_;
  }

  int max() const {
    return max_;
  }

  int buckets() const {
    return buckets_;
  }

 protected:
  friend class TaggedCounterReporterTest;
  FRIEND_TEST(TaggedCounterReporterTest, Report);

  static void Report(void* handle, int32 tag, int32 count);

  static MetricsLibraryInterface* metrics_lib_;
  scoped_ptr<TaggedCounter> tagged_counter_;
  std::string histogram_name_;
  int min_;
  int max_;
  int buckets_;
};

// FrequencyCounter uses TaggedCounter to maintain a persistent
// storage of the number of events that occur in a given cycle
// duration (in other words, a frequency count).  For example, to
@@ -172,13 +239,11 @@ class FrequencyCounter {
  FrequencyCounter();
  virtual ~FrequencyCounter();

  // Initialize a frequency counter, which is necessary before first use.
  // |filename|, |reporter|, and |reporter_handle| are used as in
  // TaggedCounter::Init.  |cycle_duration| is the number of seconds
  // in a cycle.
  virtual void Init(const char* filename,
                    TaggedCounterInterface::Reporter reporter,
                    void* reporter_handle,
  // Initialize a frequency counter, which is necessary before first
  // use.  |tagged_counter| is used to store the counts, its memory
  // will be managed by this FrequencyCounter.  |cycle_duration| is
  // the number of seconds in a cycle.
  virtual void Init(TaggedCounterInterface* tagged_counter,
                    time_t cycle_duration);
  // Record that an event occurred.  |count| is the number of concurrent
  // events that have occurred.  The time is implicitly assumed to be the
@@ -187,9 +252,29 @@ class FrequencyCounter {
    UpdateInternal(count, time(NULL));
  }

  // Update the frequency counter based on the current time.  If a
  // cycle has finished, this will have the effect of flushing the
  // cycle's count, without first requiring another update to the
  // frequency counter.  The more often this is called, the lower the
  // latency to have a new sample submitted.
  virtual void FlushFinishedCycles() {
    Update(0);
  }

  // Accessor function.
  const TaggedCounterInterface& tagged_counter() const {
    return *tagged_counter_;
  }

  time_t cycle_duration() const {
    return cycle_duration_;
  }

 private:
  friend class FrequencyCounterTest;
  FRIEND_TEST(FrequencyCounterTest, UpdateInternal);
  FRIEND_TEST(FrequencyCounterTest, GetCycleNumberForWeek);
  FRIEND_TEST(FrequencyCounterTest, GetCycleNumberForDay);

  void UpdateInternal(int32 count, time_t now);
  int32 GetCycleNumber(time_t now);
+13 −1
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@

namespace chromeos_metrics {

class TaggedCounterMock : public TaggedCounterInterface {
class TaggedCounterMock : public TaggedCounter {
 public:
  MOCK_METHOD3(Init, void(const char* filename,
                          Reporter reporter, void* reporter_handle));
@@ -21,6 +21,17 @@ class TaggedCounterMock : public TaggedCounterInterface {
  MOCK_METHOD0(Flush, void());
};

class TaggedCounterReporterMock : public TaggedCounterReporter {
 public:
  MOCK_METHOD5(Init, void(const char* filename,
                          const char* histogram_name,
                          int min,
                          int max,
                          int nbuckets));
  MOCK_METHOD2(Update, void(int32 tag, int32 count));
  MOCK_METHOD0(Flush, void());
};

class FrequencyCounterMock : public FrequencyCounter {
 public:
  MOCK_METHOD4(Init, void(const char* filename,
@@ -28,6 +39,7 @@ class FrequencyCounterMock : public FrequencyCounter {
                          void* reporter_handle,
                          time_t cycle_duration));
  MOCK_METHOD1(Update, void(int32 count));
  MOCK_METHOD0(FlushFinishedCycles, void());
};

}  // namespace chromeos_metrics
Loading