blob: 2089e7f6e5d14a901ff17e0059b3124fa914919d [file] [log] [blame]
Christopher Wiley5781aa42012-07-30 14:42:23 -07001// 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 Shenafb5b5a2012-08-13 11:43:28 -070011#include <unistd.h>
Christopher Wiley5781aa42012-07-30 14:42:23 -070012
13#include <base/basictypes.h>
14#include <base/lazy_instance.h>
15#include <base/logging.h>
16#include <gtest/gtest_prod.h>
17
Paul Stewart5ad16062013-02-21 18:10:48 -080018namespace base {
19
Christopher Wiley3e7635e2012-08-15 09:46:17 -070020class FilePath;
21
Paul Stewart5ad16062013-02-21 18:10:48 -080022} // namespace base
23
Christopher Wiley5781aa42012-07-30 14:42:23 -070024// 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
36namespace shill {
37
Christopher Wiley5781aa42012-07-30 14:42:23 -070038class MemoryLog {
39 public:
40 // Returns a singleton of this class.
41 static MemoryLog *GetInstance();
42
Christopher Wiley5781aa42012-07-30 14:42:23 -070043 ~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 Wiley5781aa42012-07-30 14:42:23 -070049 // Sets the maximum size for the log and drops messages until we get under it.
50 void SetMaximumSize(size_t size_in_bytes);
Christopher Wiley3e7635e2012-08-15 09:46:17 -070051 // See FlushToDiskImpl().
52 void FlushToDisk();
Christopher Wiley5781aa42012-07-30 14:42:23 -070053
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 Wileyf11cebb2012-08-08 12:22:20 -070059 // Required for constructing LazyInstance<MemoryLog>.
60 friend struct base::DefaultLazyInstanceTraits<MemoryLog>;
Christopher Wiley3e7635e2012-08-15 09:46:17 -070061 FRIEND_TEST(ManagerTest, PopProfileShouldClearMemoryLog);
62 FRIEND_TEST(MemoryLogTest, MemoryLogFlushToDiskCannotCreateFile);
63 FRIEND_TEST(MemoryLogTest, MemoryLogFlushToDiskRotateWorks);
Christopher Wiley5781aa42012-07-30 14:42:23 -070064 FRIEND_TEST(MemoryLogTest, MemoryLogFlushToDiskWorks);
Christopher Wiley3e7635e2012-08-15 09:46:17 -070065 FRIEND_TEST(MemoryLogTest, MemoryLogFlushToFileWorks);
Christopher Wiley5781aa42012-07-30 14:42:23 -070066 FRIEND_TEST(MemoryLogTest, MemoryLogIsLogging);
67 FRIEND_TEST(MemoryLogTest, MemoryLogLimitingWorks);
Christopher Wileyf11cebb2012-08-08 12:22:20 -070068 FRIEND_TEST(MemoryLogTest, MemoryLogMessageInterceptorWorks);
Christopher Wiley5781aa42012-07-30 14:42:23 -070069
70 // Arbitrary default verbose log capacity is an even megabyte.
71 static const size_t kDefaultMaximumMemoryLogSizeInBytes = 1 << 20;
Christopher Wiley3e7635e2012-08-15 09:46:17 -070072 // 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 Wiley5781aa42012-07-30 14:42:23 -070082
83 std::deque<std::string> log_;
84
85 void ShrinkToTargetSize(size_t number_bytes);
86 size_t TestGetNumberMessages() { return log_.size(); }
Christopher Wiley3e7635e2012-08-15 09:46:17 -070087 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 Stewart5ad16062013-02-21 18:10:48 -080097 ssize_t FlushToFile(const base::FilePath &file_path);
Christopher Wiley3e7635e2012-08-15 09:46:17 -070098 // 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 Stewart5ad16062013-02-21 18:10:48 -0800105 void FlushToDiskImpl(const base::FilePath &file_path);
Christopher Wiley5781aa42012-07-30 14:42:23 -0700106
107 size_t maximum_size_bytes_;
108 size_t current_size_bytes_;
Christopher Wiley3e7635e2012-08-15 09:46:17 -0700109 size_t maximum_disk_log_size_bytes_;
Christopher Wiley5781aa42012-07-30 14:42:23 -0700110
Christopher Wileyf11cebb2012-08-08 12:22:20 -0700111 DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryLog);
Christopher Wiley5781aa42012-07-30 14:42:23 -0700112};
113
114class 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 Wiley5781aa42012-07-30 14:42:23 -0700125 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_