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