Christopher Wiley | 5781aa4 | 2012-07-30 14:42:23 -0700 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium OS 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 | #ifndef SHILL_MEMORY_LOG_H_ |
| 6 | #define SHILL_MEMORY_LOG_H_ |
| 7 | |
| 8 | #include <deque> |
| 9 | #include <string> |
| 10 | #include <sstream> |
Han Shen | afb5b5a | 2012-08-13 11:43:28 -0700 | [diff] [blame] | 11 | #include <unistd.h> |
Christopher Wiley | 5781aa4 | 2012-07-30 14:42:23 -0700 | [diff] [blame] | 12 | |
| 13 | #include <base/basictypes.h> |
| 14 | #include <base/lazy_instance.h> |
| 15 | #include <base/logging.h> |
| 16 | #include <gtest/gtest_prod.h> |
| 17 | |
Paul Stewart | 5ad1606 | 2013-02-21 18:10:48 -0800 | [diff] [blame] | 18 | namespace base { |
| 19 | |
Christopher Wiley | 3e7635e | 2012-08-15 09:46:17 -0700 | [diff] [blame] | 20 | class FilePath; |
| 21 | |
Paul Stewart | 5ad1606 | 2013-02-21 18:10:48 -0800 | [diff] [blame] | 22 | } // namespace base |
| 23 | |
Christopher Wiley | 5781aa4 | 2012-07-30 14:42:23 -0700 | [diff] [blame] | 24 | // MemoryLog is nothing but a memory buffer of the most recent messages, capped |
| 25 | // by a configurable limit of how many message bytes to remember at a time. |
| 26 | // When a new message comes in, we add it to the buffer, then drop the oldest |
| 27 | // messages until the size of the buffer is under the byte limit. The number of |
| 28 | // bytes in the buffer does not include std::string overhead, nor overhead from |
| 29 | // the buffer implementation. Only bytes in messages are counted. |
| 30 | // |
| 31 | // When something 'interesting' happens (e.g. connectivity event or crash), the |
| 32 | // logic reacting to that event can dump the contents of the MemoryLog to disk. |
| 33 | // This gives us a verbose log of the most recent events up until the event, |
| 34 | // which may be useful for further debugging. |
| 35 | |
| 36 | namespace shill { |
| 37 | |
Christopher Wiley | 5781aa4 | 2012-07-30 14:42:23 -0700 | [diff] [blame] | 38 | class MemoryLog { |
| 39 | public: |
| 40 | // Returns a singleton of this class. |
| 41 | static MemoryLog *GetInstance(); |
| 42 | |
Christopher Wiley | 5781aa4 | 2012-07-30 14:42:23 -0700 | [diff] [blame] | 43 | ~MemoryLog(); |
| 44 | // Appends this message to the log, dropping the oldest messages until the log |
| 45 | // is under the byte limit. |
| 46 | void Append(const std::string &msg); |
| 47 | // Removes all messages from the log. |
| 48 | void Clear(); |
Christopher Wiley | 5781aa4 | 2012-07-30 14:42:23 -0700 | [diff] [blame] | 49 | // Sets the maximum size for the log and drops messages until we get under it. |
| 50 | void SetMaximumSize(size_t size_in_bytes); |
Christopher Wiley | 3e7635e | 2012-08-15 09:46:17 -0700 | [diff] [blame] | 51 | // See FlushToDiskImpl(). |
| 52 | void FlushToDisk(); |
Christopher Wiley | 5781aa4 | 2012-07-30 14:42:23 -0700 | [diff] [blame] | 53 | |
| 54 | size_t maximum_size_bytes() const { return maximum_size_bytes_; } |
| 55 | size_t current_size_bytes() const { return current_size_bytes_; } |
| 56 | |
| 57 | private: |
| 58 | friend class MemoryLogTest; |
Christopher Wiley | f11cebb | 2012-08-08 12:22:20 -0700 | [diff] [blame] | 59 | // Required for constructing LazyInstance<MemoryLog>. |
| 60 | friend struct base::DefaultLazyInstanceTraits<MemoryLog>; |
Christopher Wiley | 3e7635e | 2012-08-15 09:46:17 -0700 | [diff] [blame] | 61 | FRIEND_TEST(ManagerTest, PopProfileShouldClearMemoryLog); |
| 62 | FRIEND_TEST(MemoryLogTest, MemoryLogFlushToDiskCannotCreateFile); |
| 63 | FRIEND_TEST(MemoryLogTest, MemoryLogFlushToDiskRotateWorks); |
Christopher Wiley | 5781aa4 | 2012-07-30 14:42:23 -0700 | [diff] [blame] | 64 | FRIEND_TEST(MemoryLogTest, MemoryLogFlushToDiskWorks); |
Christopher Wiley | 3e7635e | 2012-08-15 09:46:17 -0700 | [diff] [blame] | 65 | FRIEND_TEST(MemoryLogTest, MemoryLogFlushToFileWorks); |
Christopher Wiley | 5781aa4 | 2012-07-30 14:42:23 -0700 | [diff] [blame] | 66 | FRIEND_TEST(MemoryLogTest, MemoryLogIsLogging); |
| 67 | FRIEND_TEST(MemoryLogTest, MemoryLogLimitingWorks); |
Christopher Wiley | f11cebb | 2012-08-08 12:22:20 -0700 | [diff] [blame] | 68 | FRIEND_TEST(MemoryLogTest, MemoryLogMessageInterceptorWorks); |
Christopher Wiley | 5781aa4 | 2012-07-30 14:42:23 -0700 | [diff] [blame] | 69 | |
| 70 | // Arbitrary default verbose log capacity is an even megabyte. |
| 71 | static const size_t kDefaultMaximumMemoryLogSizeInBytes = 1 << 20; |
Christopher Wiley | 3e7635e | 2012-08-15 09:46:17 -0700 | [diff] [blame] | 72 | // Default log dump path used with FlushToDisk() when a user is logged in. |
| 73 | static const char kDefaultLoggedInDumpPath[]; |
| 74 | // Default log dump path used when no user is logged in. |
| 75 | static const char kDefaultLoggedOutDumpPath[]; |
| 76 | // If this file exists, then we say that a user is logged in |
| 77 | static const char kLoggedInTokenPath[]; |
| 78 | // The on disk log file may only be this big before we'll forcibly rotate it. |
| 79 | // This means we may have this number * 2 bytes on disk at any time. |
| 80 | static const size_t kDefaultMaxDiskLogSizeInBytes = |
| 81 | kDefaultMaximumMemoryLogSizeInBytes * 20; |
Christopher Wiley | 5781aa4 | 2012-07-30 14:42:23 -0700 | [diff] [blame] | 82 | |
| 83 | std::deque<std::string> log_; |
| 84 | |
| 85 | void ShrinkToTargetSize(size_t number_bytes); |
| 86 | size_t TestGetNumberMessages() { return log_.size(); } |
Christopher Wiley | 3e7635e | 2012-08-15 09:46:17 -0700 | [diff] [blame] | 87 | bool TestContainsMessageWithText(const char *msg); |
| 88 | void TestSetMaxDiskLogSize(size_t number_bytes) { |
| 89 | maximum_disk_log_size_bytes_ = number_bytes; |
| 90 | } |
| 91 | // Appends the current contents of the memory buffer to a specified file on |
| 92 | // disk. Returns the number of bytes written to disk, or -1 on failure. -1 is |
| 93 | // returned on failure even if some bytes have already made it to disk. |
| 94 | // Attempts to create the parent directories of |file_path| if it does not |
| 95 | // already exist. If the resulting log file is too large (> kMaxDiskLogSize), |
| 96 | // tries to rotate logs. |
Paul Stewart | 5ad1606 | 2013-02-21 18:10:48 -0800 | [diff] [blame] | 97 | ssize_t FlushToFile(const base::FilePath &file_path); |
Christopher Wiley | 3e7635e | 2012-08-15 09:46:17 -0700 | [diff] [blame] | 98 | // Flushes the log to disk via FlushToFile, then clears the log, and tries to |
| 99 | // rotate our logs if |file_path| is larger than |
| 100 | // |maximum_disk_log_size_bytes_|. |
| 101 | // |
| 102 | // We rotate here rather than through logrotate because we fear situations |
| 103 | // where we experience a lot of connectivity problems in a short span of time |
| 104 | // before logrotate has a chance to run. |
Paul Stewart | 5ad1606 | 2013-02-21 18:10:48 -0800 | [diff] [blame] | 105 | void FlushToDiskImpl(const base::FilePath &file_path); |
Christopher Wiley | 5781aa4 | 2012-07-30 14:42:23 -0700 | [diff] [blame] | 106 | |
| 107 | size_t maximum_size_bytes_; |
| 108 | size_t current_size_bytes_; |
Christopher Wiley | 3e7635e | 2012-08-15 09:46:17 -0700 | [diff] [blame] | 109 | size_t maximum_disk_log_size_bytes_; |
Christopher Wiley | 5781aa4 | 2012-07-30 14:42:23 -0700 | [diff] [blame] | 110 | |
Christopher Wiley | f11cebb | 2012-08-08 12:22:20 -0700 | [diff] [blame] | 111 | DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryLog); |
Christopher Wiley | 5781aa4 | 2012-07-30 14:42:23 -0700 | [diff] [blame] | 112 | }; |
| 113 | |
| 114 | class MemoryLogMessage { |
| 115 | public: |
| 116 | MemoryLogMessage(const char *file, |
| 117 | int line, |
| 118 | logging::LogSeverity severity, |
| 119 | bool propagate_down); |
| 120 | ~MemoryLogMessage(); |
| 121 | |
| 122 | std::ostream &stream() { return stream_; } |
| 123 | |
| 124 | private: |
Christopher Wiley | 5781aa4 | 2012-07-30 14:42:23 -0700 | [diff] [blame] | 125 | const char *file_; |
| 126 | const int line_; |
| 127 | const logging::LogSeverity severity_; |
| 128 | bool propagate_down_; |
| 129 | std::ostringstream stream_; |
| 130 | size_t message_start_; |
| 131 | |
| 132 | void Init(); |
| 133 | |
| 134 | DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryLogMessage); |
| 135 | }; |
| 136 | |
| 137 | } // namespace shill |
| 138 | |
| 139 | #endif // SHILL_MEMORY_LOG_H_ |