Home | History | Annotate | Download | only in metrics
      1 // Copyright 2018 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 
      5 #include "base/metrics/persistent_histogram_storage.h"
      6 
      7 #include "base/files/file_util.h"
      8 #include "base/files/important_file_writer.h"
      9 #include "base/logging.h"
     10 #include "base/metrics/persistent_histogram_allocator.h"
     11 #include "base/metrics/persistent_memory_allocator.h"
     12 #include "base/strings/string_util.h"
     13 #include "base/strings/stringprintf.h"
     14 #include "base/time/time.h"
     15 #include "build/build_config.h"
     16 
     17 namespace {
     18 
     19 constexpr size_t kAllocSize = 1 << 20;  // 1 MiB
     20 
     21 }  // namespace
     22 
     23 namespace base {
     24 
     25 PersistentHistogramStorage::PersistentHistogramStorage(
     26     StringPiece allocator_name,
     27     StorageDirManagement storage_dir_management)
     28     : storage_dir_management_(storage_dir_management) {
     29   DCHECK(!allocator_name.empty());
     30   DCHECK(IsStringASCII(allocator_name));
     31 
     32   GlobalHistogramAllocator::CreateWithLocalMemory(kAllocSize,
     33                                                   0,  // No identifier.
     34                                                   allocator_name);
     35   GlobalHistogramAllocator::Get()->CreateTrackingHistograms(allocator_name);
     36 }
     37 
     38 PersistentHistogramStorage::~PersistentHistogramStorage() {
     39   PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
     40   allocator->UpdateTrackingHistograms();
     41 
     42   // TODO(chengx): Investigate making early return depend on whethere there are
     43   // metrics to report at this point or not.
     44   if (disabled_)
     45     return;
     46 
     47   // Stop if the storage base directory has not been properly set.
     48   if (storage_base_dir_.empty()) {
     49     LOG(ERROR)
     50         << "Could not write \"" << allocator->Name()
     51         << "\" persistent histograms to file as the storage base directory "
     52            "is not properly set.";
     53     return;
     54   }
     55 
     56   FilePath storage_dir = storage_base_dir_.AppendASCII(allocator->Name());
     57 
     58   switch (storage_dir_management_) {
     59     case StorageDirManagement::kCreate:
     60       if (!CreateDirectory(storage_dir)) {
     61         LOG(ERROR)
     62             << "Could not write \"" << allocator->Name()
     63             << "\" persistent histograms to file as the storage directory "
     64                "cannot be created.";
     65         return;
     66       }
     67       break;
     68     case StorageDirManagement::kUseExisting:
     69       if (!DirectoryExists(storage_dir)) {
     70         // When the consumer of this class decides to use an existing storage
     71         // directory, it should ensure the directory's existence if it's
     72         // essential.
     73         LOG(ERROR)
     74             << "Could not write \"" << allocator->Name()
     75             << "\" persistent histograms to file as the storage directory "
     76                "does not exist.";
     77         return;
     78       }
     79       break;
     80   }
     81 
     82   // Save data using the current time as the filename. The actual filename
     83   // doesn't matter (so long as it ends with the correct extension) but this
     84   // works as well as anything.
     85   Time::Exploded exploded;
     86   Time::Now().LocalExplode(&exploded);
     87   const FilePath file_path =
     88       storage_dir
     89           .AppendASCII(StringPrintf("%04d%02d%02d%02d%02d%02d", exploded.year,
     90                                     exploded.month, exploded.day_of_month,
     91                                     exploded.hour, exploded.minute,
     92                                     exploded.second))
     93           .AddExtension(PersistentMemoryAllocator::kFileExtension);
     94 
     95   StringPiece contents(static_cast<const char*>(allocator->data()),
     96                        allocator->used());
     97   if (!ImportantFileWriter::WriteFileAtomically(file_path, contents)) {
     98     LOG(ERROR) << "Persistent histograms fail to write to file: "
     99                << file_path.value();
    100   }
    101 }
    102 
    103 }  // namespace base
    104