summaryrefslogtreecommitdiff
path: root/src/logging.cc
diff options
context:
space:
mode:
author <shinichiro.hamaji@gmail.com>2008-12-19 15:20:40 +0000
committer <shinichiro.hamaji@gmail.com>2008-12-19 15:20:40 +0000
commitafd586a5d5c96a606773bd48422b892957419b59 (patch)
treeb807abf9182af1dd4d6832c45c3b4bdfd80a5813 /src/logging.cc
parentc54c735616b5dba9966c342b0e14e07833bbec7b (diff)
downloadglog-afd586a5d5c96a606773bd48422b892957419b59.tar.gz
glog-afd586a5d5c96a606773bd48422b892957419b59.tar.bz2
glog-afd586a5d5c96a606773bd48422b892957419b59.zip
Initial windows support. Now we don't have the stacktrace and several unittests.
git-svn-id: https://google-glog.googlecode.com/svn/trunk@23 eb4d4688-79bd-11dd-afb4-1d65580434c0
Diffstat (limited to 'src/logging.cc')
-rw-r--r--src/logging.cc282
1 files changed, 161 insertions, 121 deletions
diff --git a/src/logging.cc b/src/logging.cc
index 06516fb..c0da25e 100644
--- a/src/logging.cc
+++ b/src/logging.cc
@@ -3,21 +3,28 @@
#include "utilities.h"
#include <assert.h>
-#include <pthread.h>
#include <iomanip>
#include <string>
-#include <unistd.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> // For _exit.
+#endif
#include <climits>
#include <sys/types.h>
#include <sys/stat.h>
-#include <sys/utsname.h>
+#ifdef HAVE_SYS_UTSNAME_H
+# include <sys/utsname.h> // For uname.
+#endif
#include <fcntl.h>
#include <cstdio>
#include <iostream>
#include <stdarg.h>
#include <stdlib.h>
-#include <pwd.h>
-#include <syslog.h>
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+#ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
#include <vector>
#include <errno.h> // for errno
#include <sstream>
@@ -101,6 +108,28 @@ DEFINE_bool(stop_logging_if_full_disk, false,
// TODO(hamaji): consider windows
#define PATH_SEPARATOR '/'
+static void GetHostName(string* hostname) {
+#if defined(HAVE_SYS_UTSNAME_H)
+ struct utsname buf;
+ if (0 != uname(&buf)) {
+ // ensure null termination on failure
+ *buf.nodename = '\0';
+ }
+ *hostname = buf.nodename;
+#elif defined(OS_WINDOWS)
+ char buf[256];
+ DWORD len;
+ if (GetComputerNameA(buf, &len)) {
+ *hostname = buf;
+ } else {
+ hostname->clear();
+ }
+#else
+# warning There is no way to retrieve the host name.
+ *hostname = "(unknown)";
+#endif
+}
+
_START_GOOGLE_NAMESPACE_
// A mutex that allows only one thread to log at a time, to keep things from
@@ -130,6 +159,8 @@ static bool SendEmailInternal(const char*dest, const char *subject,
base::Logger::~Logger() {
}
+namespace {
+
// Encapsulates all file-system related state
class LogFileObject : public base::Logger {
public:
@@ -182,61 +213,7 @@ class LogFileObject : public base::Logger {
bool CreateLogfile(const char* time_pid_string);
};
-LogFileObject::LogFileObject(LogSeverity severity,
- const char* base_filename)
- : base_filename_selected_(base_filename != NULL),
- base_filename_((base_filename != NULL) ? base_filename : ""),
- symlink_basename_(ProgramInvocationShortName()),
- filename_extension_(),
- file_(NULL),
- severity_(severity),
- bytes_since_flush_(0),
- file_length_(0),
- rollover_attempt_(kRolloverAttemptFrequency-1),
- next_flush_time_(0) {
- assert(severity >= 0);
- assert(severity < NUM_SEVERITIES);
-}
-
-LogFileObject::~LogFileObject() {
- MutexLock l(&lock_);
- if (file_ != NULL) {
- fclose(file_);
- file_ = NULL;
- }
-}
-
-void LogFileObject::SetBasename(const char* basename) {
- MutexLock l(&lock_);
- base_filename_selected_ = true;
- if (base_filename_ != basename) {
- // Get rid of old log file since we are changing names
- if (file_ != NULL) {
- fclose(file_);
- file_ = NULL;
- rollover_attempt_ = kRolloverAttemptFrequency-1;
- }
- base_filename_ = basename;
- }
-}
-
-void LogFileObject::SetExtension(const char* ext) {
- MutexLock l(&lock_);
- if (filename_extension_ != ext) {
- // Get rid of old log file since we are changing names
- if (file_ != NULL) {
- fclose(file_);
- file_ = NULL;
- rollover_attempt_ = kRolloverAttemptFrequency-1;
- }
- filename_extension_ = ext;
- }
-}
-
-void LogFileObject::SetSymlinkBasename(const char* symlink_basename) {
- MutexLock l(&lock_);
- symlink_basename_ = symlink_basename;
-}
+} // namespace
class LogDestination {
public:
@@ -339,10 +316,8 @@ Mutex LogDestination::sink_mutex_;
/* static */
const string& LogDestination::hostname() {
if (hostname_.empty()) {
- struct utsname buf;
- if (0 == uname(&buf)) {
- hostname_ = buf.nodename;
- } else {
+ GetHostName(&hostname_);
+ if (hostname_.empty()) {
hostname_ = "(unknown)";
}
}
@@ -355,22 +330,6 @@ LogDestination::LogDestination(LogSeverity severity,
logger_(&fileobject_) {
}
-void LogFileObject::Flush() {
- MutexLock l(&lock_);
- FlushUnlocked();
-}
-
-void LogFileObject::FlushUnlocked(){
- if (file_ != NULL) {
- fflush(file_);
- bytes_since_flush_ = 0;
- }
- // Figure out when we are due for another flush.
- const int64 next = (FLAGS_logbufsecs
- * static_cast<int64>(1000000)); // in usec
- next_flush_time_ = CycleClock_Now() + UsecToCycles(next);
-}
-
inline void LogDestination::FlushLogFilesUnsafe(int min_severity) {
// assume we have the log_mutex or we simply don't care
// about it
@@ -476,7 +435,7 @@ inline void LogDestination::SetEmailLogging(LogSeverity min_severity,
static void WriteToStderr(const char* message, size_t len) {
// Avoid using cerr from this module since we may get called during
// exit code, and cerr may be partially or fully destroyed by then.
- fwrite(message, len, 1, stderr);
+ write(STDERR_FILENO, message, len);
}
inline void LogDestination::MaybeLogToStderr(LogSeverity severity,
@@ -568,14 +527,100 @@ inline void LogDestination::WaitForSinks(LogMessage::LogMessageData* data) {
}
}
+LogDestination* LogDestination::log_destinations_[NUM_SEVERITIES];
+
+inline LogDestination* LogDestination::log_destination(LogSeverity severity) {
+ assert(severity >=0 && severity < NUM_SEVERITIES);
+ if (!log_destinations_[severity]) {
+ log_destinations_[severity] = new LogDestination(severity, NULL);
+ }
+ return log_destinations_[severity];
+}
+
+namespace {
+
+LogFileObject::LogFileObject(LogSeverity severity,
+ const char* base_filename)
+ : base_filename_selected_(base_filename != NULL),
+ base_filename_((base_filename != NULL) ? base_filename : ""),
+ symlink_basename_(ProgramInvocationShortName()),
+ filename_extension_(),
+ file_(NULL),
+ severity_(severity),
+ bytes_since_flush_(0),
+ file_length_(0),
+ rollover_attempt_(kRolloverAttemptFrequency-1),
+ next_flush_time_(0) {
+ assert(severity >= 0);
+ assert(severity < NUM_SEVERITIES);
+}
+
+LogFileObject::~LogFileObject() {
+ MutexLock l(&lock_);
+ if (file_ != NULL) {
+ fclose(file_);
+ file_ = NULL;
+ }
+}
+
+void LogFileObject::SetBasename(const char* basename) {
+ MutexLock l(&lock_);
+ base_filename_selected_ = true;
+ if (base_filename_ != basename) {
+ // Get rid of old log file since we are changing names
+ if (file_ != NULL) {
+ fclose(file_);
+ file_ = NULL;
+ rollover_attempt_ = kRolloverAttemptFrequency-1;
+ }
+ base_filename_ = basename;
+ }
+}
+
+void LogFileObject::SetExtension(const char* ext) {
+ MutexLock l(&lock_);
+ if (filename_extension_ != ext) {
+ // Get rid of old log file since we are changing names
+ if (file_ != NULL) {
+ fclose(file_);
+ file_ = NULL;
+ rollover_attempt_ = kRolloverAttemptFrequency-1;
+ }
+ filename_extension_ = ext;
+ }
+}
+
+void LogFileObject::SetSymlinkBasename(const char* symlink_basename) {
+ MutexLock l(&lock_);
+ symlink_basename_ = symlink_basename;
+}
+
+void LogFileObject::Flush() {
+ MutexLock l(&lock_);
+ FlushUnlocked();
+}
+
+void LogFileObject::FlushUnlocked(){
+ if (file_ != NULL) {
+ fflush(file_);
+ bytes_since_flush_ = 0;
+ }
+ // Figure out when we are due for another flush.
+ const int64 next = (FLAGS_logbufsecs
+ * static_cast<int64>(1000000)); // in usec
+ next_flush_time_ = CycleClock_Now() + UsecToCycles(next);
+}
+
bool LogFileObject::CreateLogfile(const char* time_pid_string) {
string string_filename = base_filename_+filename_extension_+
time_pid_string;
const char* filename = string_filename.c_str();
int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0664);
if (fd == -1) return false;
+#ifdef HAVE_FCNTL
// Mark the file close-on-exec. We don't really care if this fails
fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
file_ = fdopen(fd, "a"); // Make a FILE*.
if (file_ == NULL) { // Man, we're screwed!
@@ -599,6 +644,8 @@ bool LogFileObject::CreateLogfile(const char* time_pid_string) {
linkpath += linkname;
unlink(linkpath.c_str()); // delete old one if it exists
+ // We must have unistd.h.
+#ifdef HAVE_UNISTD_H
// Make the symlink be relative (in the same dir) so that if the
// entire log directory gets relocated the link is still valid.
const char *linkdest = slash ? (slash + 1) : filename;
@@ -611,6 +658,7 @@ bool LogFileObject::CreateLogfile(const char* time_pid_string) {
unlink(linkpath.c_str()); // delete old one if it exists
symlink(filename, linkpath.c_str()); // silently ignore failures
}
+#endif
}
return true; // Everything worked
@@ -627,7 +675,7 @@ void LogFileObject::Write(bool force_flush,
return;
}
- if ((file_length_ >> 20) >= FLAGS_max_log_size) {
+ if (static_cast<int>(file_length_ >> 20) >= FLAGS_max_log_size) {
fclose(file_);
file_ = NULL;
file_length_ = bytes_since_flush_ = 0;
@@ -679,10 +727,8 @@ void LogFileObject::Write(bool force_flush,
// Where does the file get put? Successively try the directories
// "/tmp", and "."
string stripped_filename(ProgramInvocationShortName()); // in cmdlineflag
- struct utsname buf;
- if (0 != uname(&buf)) {
- *buf.nodename = '\0'; // ensure null termination on failure
- }
+ string hostname;
+ GetHostName(&hostname);
string uidname = MyUserName();
// We should not call CHECK() here because this function can be
@@ -691,7 +737,7 @@ void LogFileObject::Write(bool force_flush,
// deadlock. Simply use a name like invalid-user.
if (uidname.empty()) uidname = "invalid-user";
- stripped_filename = stripped_filename+'.'+buf.nodename+'.'
+ stripped_filename = stripped_filename+'.'+hostname+'.'
+uidname+".log."
+LogSeverityNames[severity_]+'.';
// We're going to (potentially) try to put logs in several different dirs
@@ -771,26 +817,7 @@ void LogFileObject::Write(bool force_flush,
}
}
-LogDestination* LogDestination::log_destinations_[NUM_SEVERITIES];
-
-inline LogDestination* LogDestination::log_destination(LogSeverity severity) {
- assert(severity >=0 && severity < NUM_SEVERITIES);
- if (!log_destinations_[severity]) {
- log_destinations_[severity] = new LogDestination(severity, NULL);
- }
- return log_destinations_[severity];
-}
-
-// Get the part of filepath after the last path separator.
-// (Doesn't modify filepath, contrary to basename() in libgen.h.)
-static const char* const_basename(const char* filepath) {
- const char* base = strrchr(filepath, '/');
-#ifdef OS_WINDOWS // Look for either path separator in Windows
- if (!base)
- base = strrchr(filepath, '\\');
-#endif
- return base ? (base+1) : filepath;
-}
+} // namespace
//
// LogMessage's constructor starts each message with a string like:
@@ -1098,7 +1125,7 @@ void LogMessage::SendToLog() {
}
static void logging_fail() {
-#if defined _DEBUG && defined COMPILER_MSVC
+#if defined(_DEBUG) && defined(_MSC_VER)
// When debugging on windows, avoid the obnoxious dialog and make
// it possible to continue past a LOG(FATAL) in the debugger
_asm int 3
@@ -1108,9 +1135,10 @@ static void logging_fail() {
}
#ifdef HAVE___ATTRIBUTE__
+GOOGLE_GLOG_DLL_DECL
void (*g_logging_fail_func)() __attribute__((noreturn)) = &logging_fail;
#else
-void (*g_logging_fail_func)() = &logging_fail;
+GOOGLE_GLOG_DLL_DECL void (*g_logging_fail_func)() = &logging_fail;
#endif
void InstallFailureFunction(void (*fail_func)()) {
@@ -1151,6 +1179,7 @@ void LogMessage::SaveOrSendToLog() {
// L >= log_mutex (callers must hold the log_mutex).
void LogMessage::SendToSyslogAndLog() {
+#ifdef HAVE_SYSLOG_H
// Before any calls to syslog(), make a single call to openlog()
static bool openlog_already_called = false;
if (!openlog_already_called) {
@@ -1165,6 +1194,9 @@ void LogMessage::SendToSyslogAndLog() {
int(data_->num_chars_to_syslog_),
data_->message_text_ + data_->num_prefix_chars_);
SendToLog();
+#else
+ LOG(ERROR) << "No syslog support: message=" << data_->message_text_;
+#endif
}
base::Logger* base::GetLogger(LogSeverity severity) {
@@ -1333,7 +1365,7 @@ bool SendEmail(const char*dest, const char *subject, const char*body){
return SendEmailInternal(dest, subject, body, true);
}
-void GetTempDirectories(vector<string>* list) {
+static void GetTempDirectories(vector<string>* list) {
list->clear();
#ifdef OS_WINDOWS
// On windows we'll try to find a directory in this order:
@@ -1429,7 +1461,7 @@ void GetExistingTempDirectories(vector<string>* list) {
}
void TruncateLogFile(const char *path, int64 limit, int64 keep) {
-
+#ifdef HAVE_UNISTD_H
struct stat statbuf;
const int kCopyBlockSize = 8 << 10;
char copybuf[kCopyBlockSize];
@@ -1498,28 +1530,36 @@ void TruncateLogFile(const char *path, int64 limit, int64 keep) {
out_close_fd:
close(fd);
-
+#else
+ LOG(ERROR) << "No log truncation support.";
+#endif
}
void TruncateStdoutStderr() {
+#ifdef HAVE_UNISTD_H
int64 limit = FLAGS_max_log_size << 20;
int64 keep = 1 << 20;
TruncateLogFile("/proc/self/fd/1", limit, keep);
TruncateLogFile("/proc/self/fd/2", limit, keep);
+#else
+ LOG(ERROR) << "No log truncation support.";
+#endif
}
// Helper functions for string comparisons.
-#define DEFINE_CHECK_STROP_IMPL(name, func, expected) \
- string* Check##func##expected##Impl(const char* s1, const char* s2, \
- const char* names) { \
- bool equal = s1 == s2 || (s1 && s2 && !func(s1, s2)); \
- if (equal == expected) return NULL; \
- else { \
- strstream ss; \
+#define DEFINE_CHECK_STROP_IMPL(name, func, expected) \
+ string* Check##func##expected##Impl(const char* s1, const char* s2, \
+ const char* names) { \
+ bool equal = s1 == s2 || (s1 && s2 && !func(s1, s2)); \
+ if (equal == expected) return NULL; \
+ else { \
+ strstream ss; \
+ if (!s1) s1 = ""; \
+ if (!s2) s2 = ""; \
ss << #name " failed: " << names << " (" << s1 << " vs. " << s2 << ")"; \
- return new string(ss.str(), ss.pcount()); \
- } \
+ return new string(ss.str(), ss.pcount()); \
+ } \
}
DEFINE_CHECK_STROP_IMPL(CHECK_STREQ, strcmp, true)
DEFINE_CHECK_STROP_IMPL(CHECK_STRNE, strcmp, false)