blob: 23ab7ef92a6c557373dc84346ef9e7519ae467f7 [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SHILL_MEMORY_LOG_H_
#define SHILL_MEMORY_LOG_H_
#include <deque>
#include <string>
#include <sstream>
#include <base/basictypes.h>
#include <base/lazy_instance.h>
#include <base/logging.h>
#include <gtest/gtest_prod.h>
// MemoryLog is nothing but a memory buffer of the most recent messages, capped
// by a configurable limit of how many message bytes to remember at a time.
// When a new message comes in, we add it to the buffer, then drop the oldest
// messages until the size of the buffer is under the byte limit. The number of
// bytes in the buffer does not include std::string overhead, nor overhead from
// the buffer implementation. Only bytes in messages are counted.
//
// When something 'interesting' happens (e.g. connectivity event or crash), the
// logic reacting to that event can dump the contents of the MemoryLog to disk.
// This gives us a verbose log of the most recent events up until the event,
// which may be useful for further debugging.
namespace shill {
class MemoryLog {
public:
// Returns a singleton of this class.
static MemoryLog *GetInstance();
// Installs a message handler that traps log messages that evaded MemoryLog
// earlier. These messages come from places like *CHECK, NOT_IMPLEMENTED, and
// similar logging calls. This will attempt to save the previous handler and
// call it recursively. It is the callers responsibility to ensure that no
// other thread is logging or touching the log handlers at the same time.
static void InstallLogInterceptor();
// Reinstalls the message handler in place when our interceptor was installed.
// It is up to the caller to ensure that no logging takes place during this
// call, and no other threads are touching the log message handlers. The
// caller is also responsible for guaranteeing our handler
static void UninstallLogInterceptor();
~MemoryLog();
// Appends this message to the log, dropping the oldest messages until the log
// is under the byte limit.
void Append(const std::string &msg);
// Removes all messages from the log.
void Clear();
// Sends the current contents of the memory buffer to a specified file on
// disk. Returns the number of bytes written to disk, or -1 on failure. -1 is
// returned on failure even if some bytes have already made it to disk.
ssize_t FlushToDisk(const std::string &file_path);
// Sets the maximum size for the log and drops messages until we get under it.
void SetMaximumSize(size_t size_in_bytes);
size_t maximum_size_bytes() const { return maximum_size_bytes_; }
size_t current_size_bytes() const { return current_size_bytes_; }
private:
friend class MemoryLogTest;
// Required for constructing LazyInstance<MemoryLog>.
friend struct base::DefaultLazyInstanceTraits<MemoryLog>;
FRIEND_TEST(MemoryLogTest, MemoryLogFlushToDiskWorks);
FRIEND_TEST(MemoryLogTest, MemoryLogIsLogging);
FRIEND_TEST(MemoryLogTest, MemoryLogLimitingWorks);
FRIEND_TEST(MemoryLogTest, MemoryLogMessageInterceptorWorks);
// Arbitrary default verbose log capacity is an even megabyte.
static const size_t kDefaultMaximumMemoryLogSizeInBytes = 1 << 20;
std::deque<std::string> log_;
void ShrinkToTargetSize(size_t number_bytes);
size_t TestGetNumberMessages() { return log_.size(); }
size_t maximum_size_bytes_;
size_t current_size_bytes_;
DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryLog);
};
class MemoryLogMessage {
public:
MemoryLogMessage(const char *file,
int line,
logging::LogSeverity severity,
bool propagate_down);
~MemoryLogMessage();
std::ostream &stream() { return stream_; }
private:
const char *file_;
const int line_;
const logging::LogSeverity severity_;
bool propagate_down_;
std::ostringstream stream_;
size_t message_start_;
void Init();
DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryLogMessage);
};
} // namespace shill
#endif // SHILL_MEMORY_LOG_H_