Index: base/files/important_file_writer.cc |
diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc |
index 0696c96b6c955e388dcb0f6af8398ccb9033f8cb..4cef799128f397532c9b9d4109f027db3f628984 100644 |
--- a/base/files/important_file_writer.cc |
+++ b/base/files/important_file_writer.cc |
@@ -19,6 +19,7 @@ |
#include "base/files/file_util.h" |
#include "base/logging.h" |
#include "base/macros.h" |
+#include "base/metrics/histogram_functions.h" |
#include "base/metrics/histogram_macros.h" |
#include "base/numerics/safe_conversions.h" |
#include "base/strings/string_number_conversions.h" |
@@ -49,10 +50,34 @@ enum TempFileFailure { |
TEMP_FILE_FAILURE_MAX |
}; |
-void LogFailure(const FilePath& path, TempFileFailure failure_code, |
+// Helper function to write samples to a histogram with a dynamically assigned |
+// histogram name. Works with different error code types convertible to int |
+// which is the actual argument type of UmaHistogramExactLinear. |
+template <typename SampleType> |
+void UmaHistogramExactLinearWithSuffix(const char* histogram_name, |
+ StringPiece histogram_suffix, |
+ SampleType add_sample, |
+ SampleType max_sample) { |
+ static_assert(std::is_convertible<SampleType, int>::value, |
+ "SampleType should be convertible to int"); |
+ DCHECK(histogram_name); |
+ std::string histogram_full_name(histogram_name); |
+ if (!histogram_suffix.empty()) { |
+ histogram_full_name.append(1, '.'); |
dcheng
2017/06/20 08:25:34
I suspect that since basic_string is all in header
xaerox
2017/06/20 08:56:08
Thanks! Indeed, since strlen is intrinsic, a cleve
|
+ histogram_full_name.append(histogram_suffix.data(), |
+ histogram_suffix.length()); |
+ } |
+ UmaHistogramExactLinear(histogram_full_name, static_cast<int>(add_sample), |
+ static_cast<int>(max_sample)); |
+} |
+ |
+void LogFailure(const FilePath& path, |
+ StringPiece histogram_suffix, |
+ TempFileFailure failure_code, |
StringPiece message) { |
- UMA_HISTOGRAM_ENUMERATION("ImportantFile.TempFileFailures", failure_code, |
- TEMP_FILE_FAILURE_MAX); |
+ UmaHistogramExactLinearWithSuffix("ImportantFile.TempFileFailures", |
+ histogram_suffix, failure_code, |
+ TEMP_FILE_FAILURE_MAX); |
DPLOG(WARNING) << "temp file failure: " << path.value() << " : " << message; |
} |
@@ -62,21 +87,43 @@ void WriteScopedStringToFileAtomically( |
const FilePath& path, |
std::unique_ptr<std::string> data, |
Closure before_write_callback, |
- Callback<void(bool success)> after_write_callback) { |
+ Callback<void(bool success)> after_write_callback, |
+ const std::string& histogram_suffix) { |
if (!before_write_callback.is_null()) |
before_write_callback.Run(); |
- bool result = ImportantFileWriter::WriteFileAtomically(path, *data); |
+ bool result = |
+ ImportantFileWriter::WriteFileAtomically(path, *data, histogram_suffix); |
if (!after_write_callback.is_null()) |
after_write_callback.Run(result); |
} |
+base::File::Error GetLastFileError() { |
+#if defined(OS_WIN) |
+ return base::File::OSErrorToFileError(::GetLastError()); |
+#elif defined(OS_POSIX) |
+ return base::File::OSErrorToFileError(errno); |
+#else |
+ return base::File::FILE_OK; |
+#endif |
+} |
+ |
+void DeleteTmpFile(const FilePath& tmp_file_path, |
+ StringPiece histogram_suffix) { |
+ if (!DeleteFile(tmp_file_path, false)) { |
+ UmaHistogramExactLinearWithSuffix("ImportantFile.FileDeleteError", |
+ histogram_suffix, -GetLastFileError(), |
+ -base::File::FILE_ERROR_MAX); |
+ } |
+} |
+ |
} // namespace |
// static |
bool ImportantFileWriter::WriteFileAtomically(const FilePath& path, |
- StringPiece data) { |
+ StringPiece data, |
+ StringPiece histogram_suffix) { |
#if defined(OS_CHROMEOS) |
// On Chrome OS, chrome gets killed when it cannot finish shutdown quickly, |
// and this function seems to be one of the slowest shutdown steps. |
@@ -97,13 +144,21 @@ bool ImportantFileWriter::WriteFileAtomically(const FilePath& path, |
// is securely created. |
FilePath tmp_file_path; |
if (!CreateTemporaryFileInDir(path.DirName(), &tmp_file_path)) { |
- LogFailure(path, FAILED_CREATING, "could not create temporary file"); |
+ UmaHistogramExactLinearWithSuffix("ImportantFile.FileCreateError", |
+ histogram_suffix, -GetLastFileError(), |
+ -base::File::FILE_ERROR_MAX); |
+ LogFailure(path, histogram_suffix, FAILED_CREATING, |
+ "could not create temporary file"); |
return false; |
} |
File tmp_file(tmp_file_path, File::FLAG_OPEN | File::FLAG_WRITE); |
if (!tmp_file.IsValid()) { |
- LogFailure(path, FAILED_OPENING, "could not open temporary file"); |
+ UmaHistogramExactLinearWithSuffix( |
+ "ImportantFile.FileOpenError", histogram_suffix, |
+ -tmp_file.error_details(), -base::File::FILE_ERROR_MAX); |
+ LogFailure(path, histogram_suffix, FAILED_OPENING, |
+ "could not open temporary file"); |
DeleteFile(tmp_file_path, false); |
return false; |
} |
@@ -111,25 +166,35 @@ bool ImportantFileWriter::WriteFileAtomically(const FilePath& path, |
// If this fails in the wild, something really bad is going on. |
const int data_length = checked_cast<int32_t>(data.length()); |
int bytes_written = tmp_file.Write(0, data.data(), data_length); |
+ if (bytes_written < data_length) { |
+ UmaHistogramExactLinearWithSuffix("ImportantFile.FileWriteError", |
+ histogram_suffix, -GetLastFileError(), |
+ -base::File::FILE_ERROR_MAX); |
+ } |
bool flush_success = tmp_file.Flush(); |
tmp_file.Close(); |
if (bytes_written < data_length) { |
- LogFailure(path, FAILED_WRITING, "error writing, bytes_written=" + |
- IntToString(bytes_written)); |
- DeleteFile(tmp_file_path, false); |
+ LogFailure(path, histogram_suffix, FAILED_WRITING, |
+ "error writing, bytes_written=" + IntToString(bytes_written)); |
+ DeleteTmpFile(tmp_file_path, histogram_suffix); |
return false; |
} |
if (!flush_success) { |
- LogFailure(path, FAILED_FLUSHING, "error flushing"); |
- DeleteFile(tmp_file_path, false); |
+ LogFailure(path, histogram_suffix, FAILED_FLUSHING, "error flushing"); |
+ DeleteTmpFile(tmp_file_path, histogram_suffix); |
return false; |
} |
- if (!ReplaceFile(tmp_file_path, path, nullptr)) { |
- LogFailure(path, FAILED_RENAMING, "could not rename temporary file"); |
- DeleteFile(tmp_file_path, false); |
+ base::File::Error replace_file_error = base::File::FILE_OK; |
+ if (!ReplaceFile(tmp_file_path, path, &replace_file_error)) { |
+ UmaHistogramExactLinearWithSuffix("ImportantFile.FileRenameError", |
+ histogram_suffix, -replace_file_error, |
+ -base::File::FILE_ERROR_MAX); |
+ LogFailure(path, histogram_suffix, FAILED_RENAMING, |
+ "could not rename temporary file"); |
+ DeleteTmpFile(tmp_file_path, histogram_suffix); |
return false; |
} |
@@ -138,19 +203,23 @@ bool ImportantFileWriter::WriteFileAtomically(const FilePath& path, |
ImportantFileWriter::ImportantFileWriter( |
const FilePath& path, |
- scoped_refptr<SequencedTaskRunner> task_runner) |
+ scoped_refptr<SequencedTaskRunner> task_runner, |
+ const char* histogram_suffix) |
: ImportantFileWriter(path, |
std::move(task_runner), |
- kDefaultCommitInterval) {} |
+ kDefaultCommitInterval, |
+ histogram_suffix) {} |
ImportantFileWriter::ImportantFileWriter( |
const FilePath& path, |
scoped_refptr<SequencedTaskRunner> task_runner, |
- TimeDelta interval) |
+ TimeDelta interval, |
+ const char* histogram_suffix) |
: path_(path), |
task_runner_(std::move(task_runner)), |
serializer_(nullptr), |
commit_interval_(interval), |
+ histogram_suffix_(histogram_suffix ? histogram_suffix : ""), |
weak_factory_(this) { |
DCHECK(task_runner_); |
} |
@@ -178,7 +247,7 @@ void ImportantFileWriter::WriteNow(std::unique_ptr<std::string> data) { |
Closure task = AdaptCallbackForRepeating( |
BindOnce(&WriteScopedStringToFileAtomically, path_, std::move(data), |
std::move(before_next_write_callback_), |
- std::move(after_next_write_callback_))); |
+ std::move(after_next_write_callback_), histogram_suffix_)); |
if (!task_runner_->PostTask(FROM_HERE, MakeCriticalClosure(task))) { |
// Posting the task to background message loop is not expected |