| // 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" | |
| #if defined(STARBOARD) | |
| #include "starboard/common/file.h" | |
| #endif | |
| 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 defined(STARBOARD) | |
| // All path should be UTF8 above Starboard. | |
| SbFileError error; | |
| bool out_created; | |
| starboard::ScopedFile sb_file(file_path.AsUTF8Unsafe().c_str(), | |
| kSbFileCreateAlways | kSbFileWrite, | |
| &out_created, &error); | |
| int bytes_written = sb_file.WriteAll(contents.data(), contents.size()); | |
| if (bytes_written == contents.size()) { | |
| #else | |
| if (!ImportantFileWriter::WriteFileAtomically(file_path, contents)) { | |
| #endif | |
| LOG(ERROR) << "Persistent histograms fail to write to file: " | |
| << file_path.value(); | |
| } | |
| } | |
| } // namespace base |