summaryrefslogtreecommitdiff
path: root/chromium/base/metrics/persistent_histogram_storage.cc
blob: e2a56d7df6cabf0aaddc4252d5dcd088e84a8ddc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/metrics/persistent_histogram_storage.h"

#include "base/files/file_util.h"
#include "base/files/important_file_writer.h"
#include "base/logging.h"
#include "base/metrics/persistent_histogram_allocator.h"
#include "base/metrics/persistent_memory_allocator.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "build/build_config.h"

namespace {

constexpr size_t kAllocSize = 1 << 20;  // 1 MiB

}  // namespace

namespace base {

PersistentHistogramStorage::PersistentHistogramStorage(
    StringPiece allocator_name,
    StorageDirManagement storage_dir_management)
    : storage_dir_management_(storage_dir_management) {
  DCHECK(!allocator_name.empty());
  DCHECK(IsStringASCII(allocator_name));

  GlobalHistogramAllocator::CreateWithLocalMemory(kAllocSize,
                                                  0,  // No identifier.
                                                  allocator_name);
  GlobalHistogramAllocator::Get()->CreateTrackingHistograms(allocator_name);
}

PersistentHistogramStorage::~PersistentHistogramStorage() {
  PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
  allocator->UpdateTrackingHistograms();

  // TODO(chengx): Investigate making early return depend on whethere there are
  // metrics to report at this point or not.
  if (disabled_)
    return;

  // Stop if the storage base directory has not been properly set.
  if (storage_base_dir_.empty()) {
    LOG(ERROR)
        << "Could not write \"" << allocator->Name()
        << "\" persistent histograms to file as the storage base directory "
           "is not properly set.";
    return;
  }

  FilePath storage_dir = storage_base_dir_.AppendASCII(allocator->Name());

  switch (storage_dir_management_) {
    case StorageDirManagement::kCreate:
      if (!CreateDirectory(storage_dir)) {
        LOG(ERROR)
            << "Could not write \"" << allocator->Name()
            << "\" persistent histograms to file as the storage directory "
               "cannot be created.";
        return;
      }
      break;
    case StorageDirManagement::kUseExisting:
      if (!DirectoryExists(storage_dir)) {
        // When the consumer of this class decides to use an existing storage
        // directory, it should ensure the directory's existence if it's
        // essential.
        LOG(ERROR)
            << "Could not write \"" << allocator->Name()
            << "\" persistent histograms to file as the storage directory "
               "does not exist.";
        return;
      }
      break;
  }

  // Save data using the current time as the filename. The actual filename
  // doesn't matter (so long as it ends with the correct extension) but this
  // works as well as anything.
  Time::Exploded exploded;
  Time::Now().LocalExplode(&exploded);
  const FilePath file_path =
      storage_dir
          .AppendASCII(StringPrintf("%04d%02d%02d%02d%02d%02d", exploded.year,
                                    exploded.month, exploded.day_of_month,
                                    exploded.hour, exploded.minute,
                                    exploded.second))
          .AddExtension(PersistentMemoryAllocator::kFileExtension);

  StringPiece contents(static_cast<const char*>(allocator->data()),
                       allocator->used());
  if (!ImportantFileWriter::WriteFileAtomically(file_path, contents)) {
    LOG(ERROR) << "Persistent histograms fail to write to file: "
               << file_path.value();
  }
}

}  // namespace base