blob: c44e8240a0b9f7a16a95dc0bbd62dc88d0c10b7d [file] [log] [blame]
#ifndef _H_Debug
#define _H_Debug
/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
#ifndef _WINDOWS
// TODO(jat): remove, for snprintf prototypes which should go away
#include <stdio.h>
#endif
#include <ostream>
#include <string>
#include "Platform.h"
// Get a default debug config if none supplied.
#ifndef GWT_DEBUGLEVEL
#include "DebugLevel.h"
#endif
/**
* Debugging class to get debugging output to a platform-specific location, with multiple
* levels supported.
*
* To use:
* #define GWT_DEBUGLEVEL level // where level is in LogLevel
* #include "Debug.h"
* Debug::log(Debug::Warning) << ...
*
* Zero overhead if GWT_DEBUGDISABLE is defined, other than the effort spent on side
* effects for stream object construction. If that is expensive, use something like
* Debug::level(Debug::Warning) to conditionalize expensive logging computations.
*/
class Debug {
public:
enum LogLevel {
None,
Error,
Warning,
Info,
Debugging,
Spam
};
private:
static const LogLevel minLogLevel = GWT_DEBUGLEVEL;
public:
/**
* Return true if the requested level would be logged. Use to protect
* expensive computations for logging.
*/
static bool level(LogLevel testLevel) {
#ifdef GWT_DEBUGDISABLE
return false;
#else
return testLevel <= minLogLevel;
#endif
}
private:
// complete the current log message
static void logFinish();
// begin a new log message
static void logStart(LogLevel level);
// add a string to the current log message
static void logString(const char* str);
static void logString(const std::string& str) {
logString(str.c_str());
}
public:
// Note that flush is special-cased in the manipulator output operator,
// and its implementation is inlined there. If its implementation is
// modified, the implementation of the manipulator output operator will
// need to be modified as well.
class DebugStream;
static DebugStream& flush(DebugStream& dbg);
class DebugStream {
const bool shouldLog;
// TODO(jat): better implementations of output operators
public:
DebugStream(LogLevel level) : shouldLog(Debug::level(level)) {
if (shouldLog) {
Debug::logStart(level);
}
}
bool isActive() const {
return shouldLog;
}
DebugStream& operator<<(long v) {
if (shouldLog) {
char buf[20];
snprintf(buf, sizeof(buf), "%ld", v);
Debug::logString(buf);
}
return *this;
}
DebugStream& operator<<(unsigned long v) {
if (shouldLog) {
char buf[20];
snprintf(buf, sizeof(buf), "%lu", v);
Debug::logString(buf);
}
return *this;
}
DebugStream& operator<<(long long v) {
if (shouldLog) {
char buf[40];
snprintf(buf, sizeof(buf), "%lld", v);
Debug::logString(buf);
}
return *this;
}
DebugStream& operator<<(unsigned long long v) {
if (shouldLog) {
char buf[40];
snprintf(buf, sizeof(buf), "%llu", v);
Debug::logString(buf);
}
return *this;
}
DebugStream& operator<<(int v) {
if (shouldLog) {
char buf[20];
snprintf(buf, sizeof(buf), "%d", v);
Debug::logString(buf);
}
return *this;
}
DebugStream& operator<<(unsigned int v) {
if (shouldLog) {
char buf[20];
snprintf(buf, sizeof(buf), "%u", v);
Debug::logString(buf);
}
return *this;
}
DebugStream& operator<<(double v) {
if (shouldLog) {
char buf[20];
snprintf(buf, sizeof(buf), "%g", v);
Debug::logString(buf);
}
return *this;
}
DebugStream& operator<<(const std::string& str) {
if (shouldLog) {
Debug::logString(str);
}
return *this;
}
DebugStream& operator<<(const char* str) {
if (shouldLog) {
Debug::logString(str);
}
return *this;
}
DebugStream& operator<<(const void* v) {
if (shouldLog) {
char buf[20];
snprintf(buf, sizeof(buf), "%p", v);
Debug::logString(buf);
}
return *this;
}
DebugStream& operator<<(DebugStream& (*manip)(DebugStream&)) {
if (shouldLog) {
// Special-case flush for efficiency.
if (manip == Debug::flush) {
Debug::logFinish();
} else {
return manip(*this);
}
}
return *this;
}
};
static DebugStream log(LogLevel testLevel) {
return DebugStream(testLevel);
}
};
#endif