Commit e31a91b6 authored by 's avatar

* Add LOG_TO_STRING.

* Add LOG_AT_LEVEL.
* Add DVLOG.
* Add LOG_TO_SINK_ONLY.
* Log microseconds.
* Add --log_backtrace_at option.
* Introduce CrashReason class.
* Fix some bugs.


git-svn-id: https://google-glog.googlecode.com/svn/trunk@29 eb4d4688-79bd-11dd-afb4-1d65580434c0
parent eecffc5a
This diff is collapsed.
// Copyright 2006 Google Inc. All Rights Reserved.
// Author: Maxim Lifantsev
//
// Logging routines that do not allocate any memory and acquire any
// locks, and can therefore be used by low-level memory allocation
// and synchronization code.
// Thread-safe logging routines that do not allocate any memory or
// acquire any locks, and can therefore be used by low-level memory
// allocation and synchronization code.
#ifndef BASE_RAW_LOGGING_H__
#define BASE_RAW_LOGGING_H__
#ifndef BASE_RAW_LOGGING_H_
#define BASE_RAW_LOGGING_H_
@ac_google_start_namespace@
......@@ -38,15 +38,68 @@
// I0821 211317 file.cc:142] RAW: status is 20
#define RAW_LOG(severity, ...) \
do { \
@ac_google_namespace@::RawLog__(@ac_google_namespace@::severity, __FILE__, __LINE__, __VA_ARGS__); \
switch (@ac_google_namespace@::severity) { \
case 0: \
RAW_LOG_INFO(__VA_ARGS__); \
break; \
case 1: \
RAW_LOG_WARNING(__VA_ARGS__); \
break; \
case 2: \
RAW_LOG_ERROR(__VA_ARGS__); \
break; \
case 3: \
RAW_LOG_FATAL(__VA_ARGS__); \
break; \
default: \
break; \
} \
} while (0)
// The following STRIP_LOG testing is performed in the header file so that it's
// possible to completely compile out the logging code and the log messages.
#if STRIP_LOG == 0
#define RAW_VLOG(verboselevel, ...) \
do { \
if (VLOG_IS_ON(verboselevel)) { \
@ac_google_namespace@::RawLog__(@ac_google_namespace@::INFO, __FILE__, __LINE__, __VA_ARGS__); \
RAW_LOG_INFO(__VA_ARGS__); \
} \
} while (0)
#else
#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG == 0
#if STRIP_LOG == 0
#define RAW_LOG_INFO(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::INFO, \
__FILE__, __LINE__, __VA_ARGS__)
#else
#define RAW_LOG_INFO(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG == 0
#if STRIP_LOG <= 1
#define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::WARNING, \
__FILE__, __LINE__, __VA_ARGS__)
#else
#define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG <= 1
#if STRIP_LOG <= 2
#define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::ERROR, \
__FILE__, __LINE__, __VA_ARGS__)
#else
#define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG <= 2
#if STRIP_LOG <= 3
#define RAW_LOG_FATAL(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::FATAL, \
__FILE__, __LINE__, __VA_ARGS__)
#else
#define RAW_LOG_FATAL(...) \
do { \
@ac_google_namespace@::RawLogStub__(0, __VA_ARGS__); \
exit(1); \
} while (0)
#endif // STRIP_LOG <= 3
// Similar to CHECK(condition) << message,
// but for low-level modules: we use only RAW_LOG that does not allocate memory.
......@@ -77,6 +130,11 @@
#endif // NDEBUG
// Stub log function used to work around for unused variable warnings when
// building with STRIP_LOG > 0.
static inline void RawLogStub__(int ignored, ...) {
}
// Helper function to implement RAW_LOG and RAW_VLOG
// Logs format... at "severity" level, reporting it
// as called from file:line.
......@@ -91,8 +149,8 @@ GOOGLE_GLOG_DLL_DECL void RawLog__(LogSeverity severity,
// this module does not have to directly call localtime_r(),
// which could allocate memory.
extern "C" struct ::tm;
GOOGLE_GLOG_DLL_DECL void RawLog__SetLastTime(const struct ::tm& t);
GOOGLE_GLOG_DLL_DECL void RawLog__SetLastTime(const struct ::tm& t, int usecs);
@ac_google_end_namespace@
#endif // BASE_RAW_LOGGING_H__
#endif // BASE_RAW_LOGGING_H_
......@@ -58,7 +58,7 @@ DEFINE_string(test_srcdir, TEST_SRC_DIR,
#ifdef NDEBUG
DEFINE_int32(benchmark_iters, 100000000, "Number of iterations per benchmark");
#else
DEFINE_int32(benchmark_iters, 1000000, "Number of iterations per benchmark");
DEFINE_int32(benchmark_iters, 100000, "Number of iterations per benchmark");
#endif
#ifdef HAVE_LIB_GTEST
......@@ -153,7 +153,7 @@ static int RUN_ALL_TESTS() {
_END_GOOGLE_NAMESPACE_
#endif
#endif // ! HAVE_LIB_GTEST
_START_GOOGLE_NAMESPACE_
......@@ -366,7 +366,6 @@ static string MungeLine(const string& line) {
}
if (!before.empty()) before += " ";
iss >> time;
CHECK_EQ(6, time.size());
iss >> thread_lineinfo;
CHECK(!thread_lineinfo.empty());
if (thread_lineinfo[thread_lineinfo.size() - 1] != ']') {
......
This diff is collapsed.
......@@ -28,15 +28,42 @@
#include "glog/raw_logging.h"
#include "googletest.h"
DECLARE_string(log_backtrace_at); // logging.cc
#ifdef HAVE_LIB_GMOCK
#include <gmock/gmock.h>
#include "mock-log.h"
// Introduce several symbols from gmock.
using testing::_;
using testing::AnyNumber;
using testing::HasSubstr;
using testing::AllOf;
using testing::StrNe;
using testing::StrictMock;
using testing::InitGoogleMock;
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
#endif
using namespace std;
using namespace GOOGLE_NAMESPACE;
// Some non-advertised functions that we want to test or use.
_START_GOOGLE_NAMESPACE_
namespace base {
namespace internal {
bool GetExitOnDFatal();
void SetExitOnDFatal(bool value);
} // namespace internal
} // namespace base
_END_GOOGLE_NAMESPACE_
static void TestLogging(bool check_counts);
static void TestRawLogging();
static void LogWithLevels(int v, int severity, bool err, bool alsoerr);
static void TestLoggingLevels();
static void TestLogString();
static void TestLogSink();
static void TestLogToString();
static void TestLogSinkWaitTillSent();
static void TestCHECK();
static void TestDCHECK();
......@@ -98,6 +125,20 @@ BENCHMARK(BM_Check2);
static void CheckFailure(int a, int b, const char* file, int line, const char* msg) {
}
static void BM_logspeed(int n) {
while (n-- > 0) {
LOG(INFO) << "test message";
}
}
BENCHMARK(BM_logspeed);
static void BM_vlog(int n) {
while (n-- > 0) {
VLOG(1) << "test message";
}
}
BENCHMARK(BM_vlog);
int main(int argc, char **argv) {
// Test some basics before InitGoogleLogging:
CaptureTestStderr();
......@@ -106,13 +147,16 @@ int main(int argc, char **argv) {
LogWithLevels(0, 0, 0, 0); // simulate "before global c-tors"
const string early_stderr = GetCapturedTestStderr();
FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]);
RunSpecifiedBenchmarks();
FLAGS_logtostderr = true;
InitGoogleTest(&argc, argv);
#ifdef HAVE_LIB_GTEST
InitGoogleMock(&argc, argv);
#endif
// so that death tests run before we use threads
CHECK_EQ(RUN_ALL_TESTS(), 0);
......@@ -127,6 +171,7 @@ int main(int argc, char **argv) {
TestLoggingLevels();
TestLogString();
TestLogSink();
TestLogToString();
TestLogSinkWaitTillSent();
TestCHECK();
TestDCHECK();
......@@ -145,7 +190,7 @@ int main(int argc, char **argv) {
TestErrno();
TestTruncate();
LOG(INFO) << "PASS";
fprintf(stdout, "PASS\n");
return 0;
}
......@@ -368,6 +413,22 @@ void TestLogString() {
}
}
void TestLogToString() {
string error;
string* no_error = NULL;
LOG_TO_STRING(INFO, &error) << "LOG_TO_STRING: " << "collected info";
LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
LOG_TO_STRING(WARNING, &error) << "LOG_TO_STRING: " << "collected warning";
LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
LOG_TO_STRING(ERROR, &error) << "LOG_TO_STRING: " << "collected error";
LOG(INFO) << "Captured by LOG_TO_STRING: " << error;
LOG_TO_STRING(INFO, no_error) << "LOG_TO_STRING: " << "reported info";
LOG_TO_STRING(WARNING, no_error) << "LOG_TO_STRING: " << "reported warning";
LOG_TO_STRING(ERROR, NULL) << "LOG_TO_STRING: " << "reported error";
}
class TestLogSinkImpl : public LogSink {
public:
vector<string> errors;
......@@ -392,6 +453,20 @@ void TestLogSink() {
LOG_TO_SINK(no_sink, WARNING) << "LOG_TO_SINK: " << "reported warning";
LOG_TO_SINK(NULL, ERROR) << "LOG_TO_SINK: " << "reported error";
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, INFO)
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "collected info";
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, WARNING)
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "collected warning";
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, ERROR)
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "collected error";
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(no_sink, INFO)
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "thrashed info";
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(no_sink, WARNING)
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "thrashed warning";
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(NULL, ERROR)
<< "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "thrashed error";
LOG(INFO) << "Captured by LOG_TO_SINK:";
for (size_t i = 0; i < sink.errors.size(); ++i) {
LogMessage("foo", LogMessage::kNoLogPrefix, INFO).stream()
......@@ -948,6 +1023,127 @@ void MyCheck(bool a, bool b) {
CHECK_EQ(a, b);
}
#ifdef HAVE_LIB_GMOCK
TEST(DVLog, Basic) {
ScopedMockLog log;
#if NDEBUG
// We are expecting that nothing is logged.
EXPECT_CALL(log, Log(_, _, _)).Times(0);
#else
EXPECT_CALL(log, Log(INFO, __FILE__, "debug log"));
#endif
FLAGS_v = 1;
DVLOG(1) << "debug log";
}
TEST(DVLog, V0) {
ScopedMockLog log;
// We are expecting that nothing is logged.
EXPECT_CALL(log, Log(_, _, _)).Times(0);
FLAGS_v = 0;
DVLOG(1) << "debug log";
}
TEST(LogAtLevel, Basic) {
ScopedMockLog log;
// The function version outputs "logging.h" as a file name.
EXPECT_CALL(log, Log(WARNING, StrNe(__FILE__), "function version"));
EXPECT_CALL(log, Log(INFO, __FILE__, "macro version"));
int severity = WARNING;
LogAtLevel(severity, "function version");
severity = INFO;
// We can use the macro version as a C++ stream.
LOG_AT_LEVEL(severity) << "macro" << ' ' << "version";
}
TEST(TestExitOnDFatal, ToBeOrNotToBe) {
// Check the default setting...
EXPECT_TRUE(base::internal::GetExitOnDFatal());
// Turn off...
base::internal::SetExitOnDFatal(false);
EXPECT_FALSE(base::internal::GetExitOnDFatal());
// We don't die.
{
ScopedMockLog log;
//EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber());
// LOG(DFATAL) has severity FATAL if debugging, but is
// downgraded to ERROR if not debugging.
const LogSeverity severity =
#ifdef NDEBUG
ERROR;
#else
FATAL;
#endif
EXPECT_CALL(log, Log(severity, __FILE__, "This should not be fatal"));
LOG(DFATAL) << "This should not be fatal";
}
// Turn back on...
base::internal::SetExitOnDFatal(true);
EXPECT_TRUE(base::internal::GetExitOnDFatal());
// Death comes on little cats' feet.
EXPECT_DEBUG_DEATH({
LOG(DFATAL) << "This should be fatal in debug mode";
}, "This should be fatal in debug mode");
}
#ifdef HAVE_STACKTRACE
static void BacktraceAtHelper() {
LOG(INFO) << "Not me";
// The vertical spacing of the next 3 lines is significant.
LOG(INFO) << "Backtrace me";
}
static int kBacktraceAtLine = __LINE__ - 2; // The line of the LOG(INFO) above
TEST(LogBacktraceAt, DoesNotBacktraceWhenDisabled) {
StrictMock<ScopedMockLog> log;
FLAGS_log_backtrace_at = "";
EXPECT_CALL(log, Log(_, _, "Backtrace me"));
EXPECT_CALL(log, Log(_, _, "Not me"));
BacktraceAtHelper();
}
TEST(LogBacktraceAt, DoesBacktraceAtRightLineWhenEnabled) {
StrictMock<ScopedMockLog> log;
char where[100];
snprintf(where, 100, "%s:%d", const_basename(__FILE__), kBacktraceAtLine);
FLAGS_log_backtrace_at = where;
// The LOG at the specified line should include a stacktrace which includes
// the name of the containing function, followed by the log message.
// We use HasSubstr()s instead of ContainsRegex() for environments
// which don't have regexp.
EXPECT_CALL(log, Log(_, _, AllOf(HasSubstr("stacktrace:"),
HasSubstr("BacktraceAtHelper"),
HasSubstr("main"),
HasSubstr("Backtrace me"))));
// Other LOGs should not include a backtrace.
EXPECT_CALL(log, Log(_, _, "Not me"));
BacktraceAtHelper();
}
#endif // HAVE_STACKTRACE
#endif // HAVE_LIB_GMOCK
struct UserDefinedClass {
bool operator==(const UserDefinedClass& rhs) const { return true; }
};
......
This diff is collapsed.
......@@ -7,10 +7,20 @@
#include <stdarg.h>
#include <stdio.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h> // for close() and write()
#endif
#include <fcntl.h> // for open()
#include <time.h>
#include "config.h"
#include "glog/logging.h" // To pick up flag settings etc.
#include "glog/raw_logging.h"
#include "base/commandlineflags.h"
#ifdef HAVE_STACKTRACE
# include "stacktrace.h"
#endif
#if defined(HAVE_SYSCALL_H)
#include <syscall.h> // for syscall()
......@@ -21,15 +31,24 @@
# include <unistd.h>
#endif
#if defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)
# define safe_write(fd, s, len) syscall(SYS_write, fd, s, len)
#else
// Not so safe, but what can you do?
# define safe_write(fd, s, len) write(fd, s, len)
#endif
_START_GOOGLE_NAMESPACE_
// Data for RawLog__ below. We simply pick up the latest
// time data created by a normal log message to avoid calling
// localtime_r which can allocate memory.
static struct ::tm last_tm_time_for_raw_log;
static int last_usecs_for_raw_log;
void RawLog__SetLastTime(const struct ::tm& t) {
void RawLog__SetLastTime(const struct ::tm& t, int usecs) {
memcpy(&last_tm_time_for_raw_log, &t, sizeof(last_tm_time_for_raw_log));
last_usecs_for_raw_log = usecs;
}
// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
......@@ -61,6 +80,11 @@ inline static bool VADoRawLog(char** buf, int* size,
return true;
}
static const int kLogBufSize = 3000;
static bool crashed = false;
static CrashReason crash_reason;
static char crash_buf[kLogBufSize + 1] = { 0 }; // Will end in '\0'
void RawLog__(LogSeverity severity, const char* file, int line,
const char* format, ...) {
if (!(FLAGS_logtostderr || severity >= FLAGS_stderrthreshold ||
......@@ -69,21 +93,22 @@ void RawLog__(LogSeverity severity, const char* file, int line,
}
// can't call localtime_r here: it can allocate
struct ::tm& t = last_tm_time_for_raw_log;
char buffer[3000]; // 3000 bytes should be enough for everyone... :-)
char buffer[kLogBufSize];
char* buf = buffer;
int size = sizeof(buffer);
if (is_default_thread()) {
DoRawLog(&buf, &size, "%c%02d%02d %02d%02d%02d %s:%d] RAW: ",
LogSeverityNames[severity][0],
1 + t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,
const_basename(const_cast<char *>(file)), line);
} else {
DoRawLog(&buf, &size, "%c%02d%02d %02d%02d%02d %08x %s:%d] RAW: ",
// NOTE: this format should match the specification in base/logging.h
DoRawLog(&buf, &size, "%c%02d%02d %02d:%02d:%02d.%06d %5u %s:%d] RAW: ",
LogSeverityNames[severity][0],
1 + t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,
int(pthread_self()),
last_usecs_for_raw_log,
static_cast<unsigned int>(GetTID()),
const_basename(const_cast<char *>(file)), line);
}
// Record the position and size of the buffer after the prefix
const char* msg_start = buf;
const int msg_size = size;
va_list ap;
va_start(ap, format);
bool no_chop = VADoRawLog(&buf, &size, format, ap);
......@@ -97,12 +122,23 @@ void RawLog__(LogSeverity severity, const char* file, int line,
// avoiding FILE buffering (to avoid invoking malloc()), and bypassing
// libc (to side-step any libc interception).
// We write just once to avoid races with other invocations of RawLog__.
#if defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)
syscall(SYS_write, STDERR_FILENO, buffer, strlen(buffer));
safe_write(STDERR_FILENO, buffer, strlen(buffer));
if (severity == FATAL) {
if (!sync_val_compare_and_swap(&crashed, false, true)) {
crash_reason.filename = file;
crash_reason.line_number = line;
memcpy(crash_buf, msg_start, msg_size); // Don't include prefix
crash_reason.message = crash_buf;
#ifdef HAVE_STACKTRACE
crash_reason.depth =
GetStackTrace(crash_reason.stack, ARRAYSIZE(crash_reason.stack), 1);
#else
write(STDERR_FILENO, buffer, strlen(buffer));
crash_reason.depth = 0;
#endif
if (severity == FATAL) LogMessage::Fail();
SetCrashReason(&crash_reason);
}
LogMessage::Fail(); // abort()
}
}
_END_GOOGLE_NAMESPACE_
......@@ -8,6 +8,11 @@
# include <sys/time.h>
#endif
#include <time.h>
#if defined(HAVE_SYSCALL_H)
#include <syscall.h> // for syscall()
#elif defined(HAVE_SYS_SYSCALL_H)
#include <sys/syscall.h> // for syscall()
#endif
#include "base/googleinit.h"
#include "stacktrace.h"
......@@ -41,6 +46,10 @@ static void DebugWriteToStderr(const char* data, void *unused) {
write(STDERR_FILENO, data, strlen(data));
}
void DebugWriteToString(const char* data, void *arg) {
reinterpret_cast<string*>(arg)->append(data);
}
// Print a program counter and its symbol name.
static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc,
const char * const prefix) {
......@@ -146,7 +155,6 @@ int64 CycleClock_Now() {
return (static_cast<int64>(now.wSecond) * 1000000 +
static_cast<int64>(now.wMilliseconds) * 1000);
#else
// TODO(hamaji): temporary impementation - it might be too slow.
struct timeval tv;
gettimeofday(&tv, NULL);
return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
......@@ -157,11 +165,53 @@ int64 UsecToCycles(int64 usec) {
return usec;
}
WallTime WallTime_Now() {
// Now, cycle clock is retuning microseconds since the epoch.
return CycleClock_Now() * 0.000001;
}
static int32 g_main_thread_pid = getpid();
int32 GetMainThreadPid() {
return g_main_thread_pid;
}
pid_t GetTID() {
// On Linux and FreeBSD, we try to use gettid().
#if defined OS_LINUX || defined OS_FREEBSD || defined OS_MACOSX
#ifndef __NR_gettid
#ifdef OS_MACOSX
#define __NR_gettid SYS_gettid
#elif ! defined __i386__
#error "Must define __NR_gettid for non-x86 platforms"
#else
#define __NR_gettid 224
#endif
#endif
static bool lacks_gettid = false;
if (!lacks_gettid) {
pid_t tid = syscall(__NR_gettid);
if (tid != -1) {
return tid;
}
// Technically, this variable has to be volatile, but there is a small
// performance penalty in accessing volatile variables and there should
// not be any serious adverse effect if a thread does not immediately see
// the value change to "true".
lacks_gettid = true;
}
#endif // OS_LINUX || OS_FREEBSD
// If gettid() could not be used, we use one of the following.
#if defined OS_LINUX
return getpid(); // Linux: getpid returns thread ID when gettid is absent
#elif defined OS_WINDOWS || defined OS_CYGWIN
return GetCurrentThreadId();
#else
// If none of the techniques above worked, we use pthread_self().
return (pid_t)pthread_self();
#endif
}
const char* const_basename(const char* filepath) {
const char* base = strrchr(filepath, '/');
#ifdef OS_WINDOWS // Look for either path separator in Windows
......@@ -186,6 +236,22 @@ static void MyUserNameInitializer() {
}
REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer());
#ifdef HAVE_STACKTRACE
void DumpStackTraceToString(string* stacktrace) {
DumpStackTrace(1, DebugWriteToString, stacktrace);
}
#endif
// We use an atomic operation to prevent problems with calling CrashReason
// from inside the Mutex implementation (potentially through RAW_CHECK).
static const CrashReason* g_reason = 0;
void SetCrashReason(const CrashReason* r) {
sync_val_compare_and_swap(&g_reason,
reinterpret_cast<const CrashReason*>(0),
r);
}
} // namespace glog_internal_namespace_
void InitGoogleLogging(const char* argv0) {
......
......@@ -40,7 +40,7 @@
#include <string>
#ifdef OS_WINDOWS
#if defined(OS_WINDOWS) && !defined(__CYGWIN__)
# include "port.h"
#endif
......@@ -74,7 +74,7 @@
# define STACKTRACE_H "stacktrace_x86-inl.h"
# elif defined(__x86_64__) && __GNUC__ >= 2
# define STACKTRACE_H "stacktrace_x86_64-inl.h"
# elif ((__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
# elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
# define STACKTRACE_H "stacktrace_powerpc-inl.h"
# endif
#endif
......@@ -95,8 +95,10 @@
# define HAVE_SYMBOLIZE
#endif
// There is a better way, but this is good enough in this file.
#define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
#ifndef ARRAYSIZE
// There is a better way, but this is good enough for our purpose.
# define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
#endif
_START_GOOGLE_NAMESPACE_
......@@ -119,8 +121,13 @@ int64 CycleClock_Now();
int64 UsecToCycles(int64 usec);
typedef double WallTime;
WallTime WallTime_Now();
int32 GetMainThreadPid();
pid_t GetTID();
const std::string& MyUserName();
// Get the part of filepath after the last path separator.
......@@ -155,6 +162,23 @@ inline T sync_val_compare_and_swap(T* ptr, T oldval, T newval) {
#endif
}
void DumpStackTraceToString(std::string* stacktrace);
struct CrashReason {
CrashReason() : filename(0), line_number(0), message(0), depth(0) {}
const char* filename;
int line_number;
const char* message;
// We'll also store a bit of context at the time of crash as it may not be
// available later on.
void* stack[32];
int depth;
};
void SetCrashReason(const CrashReason* r);
} // namespace glog_internal_namespace_
_END_GOOGLE_NAMESPACE_
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment