| // 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_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 |