blob: 23ab7ef92a6c557373dc84346ef9e7519ae467f7 [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>
11
12#include <base/basictypes.h>
13#include <base/lazy_instance.h>
14#include <base/logging.h>
15#include <gtest/gtest_prod.h>
16
Christopher Wiley5781aa42012-07-30 14:42:23 -070017// MemoryLog is nothing but a memory buffer of the most recent messages, capped
18// by a configurable limit of how many message bytes to remember at a time.
19// When a new message comes in, we add it to the buffer, then drop the oldest
20// messages until the size of the buffer is under the byte limit. The number of
21// bytes in the buffer does not include std::string overhead, nor overhead from
22// the buffer implementation. Only bytes in messages are counted.
23//
24// When something 'interesting' happens (e.g. connectivity event or crash), the
25// logic reacting to that event can dump the contents of the MemoryLog to disk.
26// This gives us a verbose log of the most recent events up until the event,
27// which may be useful for further debugging.
28
29namespace shill {
30
Christopher Wiley5781aa42012-07-30 14:42:23 -070031class MemoryLog {
32 public:
33 // Returns a singleton of this class.
34 static MemoryLog *GetInstance();
Christopher Wileyf11cebb2012-08-08 12:22:20 -070035 // Installs a message handler that traps log messages that evaded MemoryLog
36 // earlier. These messages come from places like *CHECK, NOT_IMPLEMENTED, and
37 // similar logging calls. This will attempt to save the previous handler and
38 // call it recursively. It is the callers responsibility to ensure that no
39 // other thread is logging or touching the log handlers at the same time.
40 static void InstallLogInterceptor();
41 // Reinstalls the message handler in place when our interceptor was installed.
42 // It is up to the caller to ensure that no logging takes place during this
43 // call, and no other threads are touching the log message handlers. The
44 // caller is also responsible for guaranteeing our handler
45 static void UninstallLogInterceptor();
Christopher Wiley5781aa42012-07-30 14:42:23 -070046
Christopher Wiley5781aa42012-07-30 14:42:23 -070047 ~MemoryLog();
48 // Appends this message to the log, dropping the oldest messages until the log
49 // is under the byte limit.
50 void Append(const std::string &msg);
51 // Removes all messages from the log.
52 void Clear();
53 // Sends the current contents of the memory buffer to a specified file on
54 // disk. Returns the number of bytes written to disk, or -1 on failure. -1 is
55 // returned on failure even if some bytes have already made it to disk.
56 ssize_t FlushToDisk(const std::string &file_path);
57 // Sets the maximum size for the log and drops messages until we get under it.
58 void SetMaximumSize(size_t size_in_bytes);
59
60 size_t maximum_size_bytes() const { return maximum_size_bytes_; }
61 size_t current_size_bytes() const { return current_size_bytes_; }
62
63 private:
64 friend class MemoryLogTest;
Christopher Wileyf11cebb2012-08-08 12:22:20 -070065 // Required for constructing LazyInstance<MemoryLog>.
66 friend struct base::DefaultLazyInstanceTraits<MemoryLog>;
Christopher Wiley5781aa42012-07-30 14:42:23 -070067 FRIEND_TEST(MemoryLogTest, MemoryLogFlushToDiskWorks);
68 FRIEND_TEST(MemoryLogTest, MemoryLogIsLogging);
69 FRIEND_TEST(MemoryLogTest, MemoryLogLimitingWorks);
Christopher Wileyf11cebb2012-08-08 12:22:20 -070070 FRIEND_TEST(MemoryLogTest, MemoryLogMessageInterceptorWorks);
Christopher Wiley5781aa42012-07-30 14:42:23 -070071
72 // Arbitrary default verbose log capacity is an even megabyte.
73 static const size_t kDefaultMaximumMemoryLogSizeInBytes = 1 << 20;
74
75 std::deque<std::string> log_;
76
77 void ShrinkToTargetSize(size_t number_bytes);
78 size_t TestGetNumberMessages() { return log_.size(); }
79
80 size_t maximum_size_bytes_;
81 size_t current_size_bytes_;
82
Christopher Wileyf11cebb2012-08-08 12:22:20 -070083 DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryLog);
Christopher Wiley5781aa42012-07-30 14:42:23 -070084};
85
86class MemoryLogMessage {
87 public:
88 MemoryLogMessage(const char *file,
89 int line,
90 logging::LogSeverity severity,
91 bool propagate_down);
92 ~MemoryLogMessage();
93
94 std::ostream &stream() { return stream_; }
95
96 private:
Christopher Wiley5781aa42012-07-30 14:42:23 -070097 const char *file_;
98 const int line_;
99 const logging::LogSeverity severity_;
100 bool propagate_down_;
101 std::ostringstream stream_;
102 size_t message_start_;
103
104 void Init();
105
106 DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryLogMessage);
107};
108
109} // namespace shill
110
111#endif // SHILL_MEMORY_LOG_H_