Merge 7102881f26 into ca390c4718
This commit is contained in:
commit
60ef0bd36c
@ -53,14 +53,15 @@
|
||||
#include <string>
|
||||
|
||||
#include "config.h"
|
||||
#include "../utilities.h"
|
||||
|
||||
#ifdef GLOG_USE_GFLAGS
|
||||
|
||||
# include <gflags/gflags.h>
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
#else
|
||||
|
||||
# include "glog/logging.h"
|
||||
#include "glog/logging.h"
|
||||
|
||||
# define DECLARE_VARIABLE(type, shorttype, name, tn) \
|
||||
namespace fL##shorttype { \
|
||||
@ -107,6 +108,18 @@
|
||||
} \
|
||||
using fLS::FLAGS_##name
|
||||
|
||||
#define DECLARE_wstring(name) \
|
||||
namespace fLS { \
|
||||
extern GLOG_EXPORT std::wstring& FLAGS_##name; \
|
||||
} \
|
||||
using fLS::FLAGS_##name
|
||||
#define DEFINE_wstring(name, value, meaning) \
|
||||
namespace fLS { \
|
||||
std::wstring FLAGS_##name##_buf(value); \
|
||||
GLOG_EXPORT std::wstring& FLAGS_##name = FLAGS_##name##_buf; \
|
||||
wchar_t FLAGS_no##name; \
|
||||
} \
|
||||
using fLS::FLAGS_##name
|
||||
#endif // GLOG_USE_GFLAGS
|
||||
|
||||
// Define GLOG_DEFINE_* using DEFINE_* . By using these macros, we
|
||||
@ -128,10 +141,17 @@
|
||||
#define GLOG_DEFINE_string(name, value, meaning) \
|
||||
DEFINE_string(name, EnvToString("GLOG_" #name, value), meaning)
|
||||
|
||||
#define GLOG_DEFINE_wstring(name, value, meaning) \
|
||||
DEFINE_wstring(name, EnvToString(L"GLOG_" #name, value), meaning)
|
||||
|
||||
|
||||
// These macros (could be functions, but I don't want to bother with a .cc
|
||||
// file), make it easier to initialize flags from the environment.
|
||||
|
||||
#define EnvToString(envname, dflt) (!getenv(envname) ? (dflt) : getenv(envname))
|
||||
#define EnvToString(envname, dflt) \
|
||||
(google::logging::internal::getenv(envname).empty() \
|
||||
? (dflt) \
|
||||
: google::logging::internal::getenv(envname))
|
||||
|
||||
#define EnvToBool(envname, dflt) \
|
||||
(!getenv(envname) ? (dflt) \
|
||||
|
||||
50
src/flags.cc
50
src/flags.cc
@ -32,22 +32,46 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include <array>
|
||||
#include "base/commandlineflags.h"
|
||||
#include "glog/log_severity.h"
|
||||
|
||||
#include "utilities.h"
|
||||
namespace {
|
||||
|
||||
// Compute the default value for --log_dir
|
||||
static const char* DefaultLogDir() {
|
||||
constexpr const char* const names[]{"GOOGLE_LOG_DIR", "TEST_TMPDIR"};
|
||||
for (const char* const name : names) {
|
||||
const char* const env = std::getenv(name);
|
||||
if (env != nullptr && env[0] != '\0') {
|
||||
return env;
|
||||
|
||||
template <class Ch, int N>
|
||||
std::basic_string<Ch> DefaultLogDir(const std::array<const Ch*, N>& names) {
|
||||
for (const Ch* name : names) {
|
||||
auto val = google::logging::internal::getenv(name);
|
||||
if(!val.empty()) {
|
||||
return val;
|
||||
}
|
||||
|
||||
}
|
||||
return "";
|
||||
return {};
|
||||
}
|
||||
|
||||
template<class Ch>
|
||||
struct LogDirEnvVar;
|
||||
|
||||
template <>
|
||||
struct LogDirEnvVar<char> {
|
||||
constexpr static std::array<const char*, 2> names() noexcept {
|
||||
return {"GOOGLE_LOG_DIR", "TEST_TMPDIR"};
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct LogDirEnvVar<wchar_t> {
|
||||
constexpr static std::array<const wchar_t*, 2> names() noexcept {
|
||||
return {L"GOOGLE_LOG_DIR", L"TEST_TMPDIR"};
|
||||
}
|
||||
};
|
||||
|
||||
template <class Ch>
|
||||
decltype(auto) DefaultLogDir() {
|
||||
return DefaultLogDir<Ch, 2>(LogDirEnvVar<Ch>::names());
|
||||
}
|
||||
|
||||
bool BoolFromEnv(const char* varname, bool defval) {
|
||||
@ -123,9 +147,15 @@ GLOG_DEFINE_string(logmailer, "", "Mailer used to send logging email");
|
||||
GLOG_DEFINE_int32(logfile_mode, 0664, "Log file mode/permissions.");
|
||||
|
||||
GLOG_DEFINE_string(
|
||||
log_dir, DefaultLogDir(),
|
||||
log_dir, DefaultLogDir<char>(),
|
||||
"If specified, logfiles are written into this directory instead "
|
||||
"of the default logging directory.");
|
||||
|
||||
GLOG_DEFINE_wstring(
|
||||
log_wdir, DefaultLogDir<wchar_t>(),
|
||||
L"If specified, logfiles are written into this directory instead "
|
||||
L"of the default logging directory.");
|
||||
|
||||
GLOG_DEFINE_string(log_link, "",
|
||||
"Put additional links to the log "
|
||||
"files in this directory");
|
||||
|
||||
@ -51,6 +51,7 @@
|
||||
#pragma push_macro("DECLARE_VARIABLE")
|
||||
#pragma push_macro("DECLARE_bool")
|
||||
#pragma push_macro("DECLARE_string")
|
||||
#pragma push_macro("DECLARE_wstring")
|
||||
#pragma push_macro("DECLARE_int32")
|
||||
#pragma push_macro("DECLARE_uint32")
|
||||
|
||||
@ -66,6 +67,10 @@
|
||||
# undef DECLARE_string
|
||||
#endif
|
||||
|
||||
#ifdef DECLARE_wstring
|
||||
# undef DECLARE_wstring
|
||||
#endif
|
||||
|
||||
#ifdef DECLARE_int32
|
||||
# undef DECLARE_int32
|
||||
#endif
|
||||
@ -100,8 +105,17 @@
|
||||
extern GLOG_EXPORT std::string& FLAGS_##name; \
|
||||
} \
|
||||
using fLS::FLAGS_##name
|
||||
|
||||
#define DECLARE_wstring(name) \
|
||||
namespace fLS { \
|
||||
extern GLOG_EXPORT std::wstring& FLAGS_##name; \
|
||||
} \
|
||||
using fLS::FLAGS_##name
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
DECLARE_int32(logemaillevel);
|
||||
DECLARE_int32(logcleansecs);
|
||||
|
||||
@ -157,6 +171,10 @@ DECLARE_int32(minloglevel);
|
||||
// default logging directory.
|
||||
DECLARE_string(log_dir);
|
||||
|
||||
// If specified, logfiles are written into this directory instead of the
|
||||
// default logging directory.
|
||||
DECLARE_wstring(log_wdir);
|
||||
|
||||
// Set the log file mode.
|
||||
DECLARE_int32(logfile_mode);
|
||||
|
||||
@ -185,6 +203,7 @@ DECLARE_bool(symbolize_stacktrace);
|
||||
#pragma pop_macro("DECLARE_VARIABLE")
|
||||
#pragma pop_macro("DECLARE_bool")
|
||||
#pragma pop_macro("DECLARE_string")
|
||||
#pragma pop_macro("DECLARE_wstring")
|
||||
#pragma pop_macro("DECLARE_int32")
|
||||
#pragma pop_macro("DECLARE_uint32")
|
||||
|
||||
|
||||
@ -1442,6 +1442,9 @@ GLOG_EXPORT void FlushLogFilesUnsafe(LogSeverity min_severity);
|
||||
GLOG_EXPORT void SetLogDestination(LogSeverity severity,
|
||||
const char* base_filename);
|
||||
|
||||
GLOG_EXPORT void SetLogDestination(LogSeverity severity,
|
||||
const wchar_t* base_filename);
|
||||
|
||||
//
|
||||
// Set the basename of the symlink to the latest log file at a given
|
||||
// severity. If symlink_basename is empty, do not make a symlink. If
|
||||
@ -1450,7 +1453,8 @@ GLOG_EXPORT void SetLogDestination(LogSeverity severity,
|
||||
//
|
||||
GLOG_EXPORT void SetLogSymlink(LogSeverity severity,
|
||||
const char* symlink_basename);
|
||||
|
||||
GLOG_EXPORT void SetLogSymlink(LogSeverity severity,
|
||||
const wchar_t* symlink_basename);
|
||||
//
|
||||
// Used to send logs to some other kind of destination
|
||||
// Users should subclass LogSink and override send to do whatever they want.
|
||||
@ -1501,6 +1505,7 @@ GLOG_EXPORT void RemoveLogSink(LogSink* destination);
|
||||
// name. Thread-safe.
|
||||
//
|
||||
GLOG_EXPORT void SetLogFilenameExtension(const char* filename_extension);
|
||||
GLOG_EXPORT void SetLogFilenameExtension(const wchar_t* filename_extension);
|
||||
|
||||
//
|
||||
// Make it so that all log messages of at least a particular severity
|
||||
@ -1528,7 +1533,8 @@ GLOG_EXPORT void SetEmailLogging(LogSeverity min_severity,
|
||||
GLOG_EXPORT bool SendEmail(const char* dest, const char* subject,
|
||||
const char* body);
|
||||
|
||||
GLOG_EXPORT const std::vector<std::string>& GetLoggingDirectories();
|
||||
GLOG_EXPORT const std::vector<std::string> GetLoggingDirectories();
|
||||
GLOG_EXPORT const std::vector<std::wstring>& GetLoggingDirectoriesW();
|
||||
|
||||
// Print any fatal message again -- useful to call from signal handler
|
||||
// so that the last thing in the output is the fatal message.
|
||||
|
||||
@ -70,11 +70,12 @@
|
||||
|
||||
using std::map;
|
||||
using std::string;
|
||||
using std::wstring;
|
||||
using std::vector;
|
||||
|
||||
namespace google {
|
||||
extern void (*g_logging_fail_func)();
|
||||
extern void GetExistingTempDirectories(std::vector<std::string>& list);
|
||||
extern void GetExistingTempDirectories(std::vector<std::wstring>& list);
|
||||
extern int posix_strerror_r(int err, char* buf, size_t len);
|
||||
extern std::string StrError(int err);
|
||||
} // namespace google
|
||||
@ -82,12 +83,12 @@ extern std::string StrError(int err);
|
||||
#undef GLOG_EXPORT
|
||||
#define GLOG_EXPORT
|
||||
|
||||
static inline string GetTempDir() {
|
||||
vector<string> temp_directories_list;
|
||||
static inline wstring GetTempDirW() {
|
||||
vector<wstring> temp_directories_list;
|
||||
google::GetExistingTempDirectories(temp_directories_list);
|
||||
|
||||
if (temp_directories_list.empty()) {
|
||||
fprintf(stderr, "No temporary directory found\n");
|
||||
fwprintf(stderr, L"No temporary directory found\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -95,6 +96,12 @@ static inline string GetTempDir() {
|
||||
return temp_directories_list.front();
|
||||
}
|
||||
|
||||
static inline string GetTempDir() {
|
||||
wstring temp_dir = GetTempDirW();
|
||||
return google::logging::internal::StrConvert<wchar_t, char>(temp_dir);
|
||||
}
|
||||
|
||||
|
||||
#if defined(GLOG_OS_WINDOWS) && defined(_MSC_VER) && !defined(TEST_SRC_DIR)
|
||||
// The test will run in glog/vsproject/<project name>
|
||||
// (e.g., glog/vsproject/logging_unittest).
|
||||
|
||||
450
src/logging.cc
450
src/logging.cc
@ -72,6 +72,7 @@
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
#ifdef HAVE__CHSIZE_S
|
||||
# include <io.h> // for truncate log file
|
||||
@ -106,6 +107,7 @@ using std::ostringstream;
|
||||
using std::setfill;
|
||||
using std::setw;
|
||||
using std::string;
|
||||
using std::wstring;
|
||||
using std::vector;
|
||||
|
||||
using std::fclose;
|
||||
@ -123,7 +125,12 @@ using std::fdopen;
|
||||
#define EXCLUSIVE_LOCKS_REQUIRED(mu)
|
||||
|
||||
// TODO(hamaji): consider windows
|
||||
enum { PATH_SEPARATOR = '/' };
|
||||
#ifdef GLOG_OS_WINDOWS
|
||||
const wchar_t * const PATH_SEPARATOR = L"\\/";
|
||||
#else
|
||||
const wchar_t* const PATH_SEPARATOR = L"/";
|
||||
#endif // GLOG_OS_WINDOWS
|
||||
|
||||
|
||||
#ifndef HAVE_PREAD
|
||||
static ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
|
||||
@ -149,6 +156,113 @@ static ssize_t pwrite(int fd, void* buf, size_t count, off_t offset) {
|
||||
}
|
||||
#endif // !HAVE_PWRITE
|
||||
|
||||
namespace details {
|
||||
int open(const char* filename, int flags, mode_t mode) {
|
||||
return ::open(filename, flags, mode);
|
||||
}
|
||||
|
||||
int open(const wchar_t* filename, int flags, mode_t mode) {
|
||||
#ifdef GLOG_OS_WINDOWS
|
||||
return _wopen(filename, flags, mode);
|
||||
#else
|
||||
auto str_filename = google::logging::internal::StrConvert<wchar_t, char>(filename);
|
||||
return open(str_filename.c_str(), flags, mode);
|
||||
#endif // GLOG_OS_WINDOWS
|
||||
}
|
||||
|
||||
int unlink(const char* filename) {
|
||||
return ::unlink(filename);
|
||||
}
|
||||
int unlink(const wchar_t* filename) {
|
||||
#ifdef GLOG_OS_WINDOWS
|
||||
return ::_wunlink(filename);
|
||||
#else
|
||||
auto str_filename = google::logging::internal::StrConvert<wchar_t, char>(filename);
|
||||
return unlink(str_filename.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
int symlink(const char* dest, const char* src) {
|
||||
#ifdef GLOG_OS_WINDOWS
|
||||
// the CreateSymbolicLinkA func requires a privilege
|
||||
return ::CreateSymbolicLinkA(dest, src, 0x0) == 0 ? GetLastError() : 0;
|
||||
#elif defined(HAVE_UNISTD_H)
|
||||
return ::symlink(dest, src);
|
||||
#endif // GLOG_OS_WINDOWS
|
||||
}
|
||||
|
||||
int symlink(const wchar_t* target, const wchar_t* symlink_file) {
|
||||
#ifdef GLOG_OS_WINDOWS
|
||||
return ::CreateSymbolicLinkW(symlink_file, target, 0x0) == 0 ? GetLastError()
|
||||
: 0;
|
||||
#elif defined(HAVE_UNISTD_H)
|
||||
auto str_target = google::logging::internal::StrConvert<wchar_t, char>(target);
|
||||
auto str_symlink_file =
|
||||
google::logging::internal::StrConvert<wchar_t, char>(symlink_file);
|
||||
return symlink(str_target.c_str(), str_symlink_file.c_str());
|
||||
#endif // GLOG_OS_WINDOWS
|
||||
}
|
||||
|
||||
decltype(auto) opendir(const char* dir_name) { return ::opendir(dir_name); }
|
||||
decltype(auto) opendir(const wchar_t* dir_name) {
|
||||
#ifdef GLOG_OS_WINDOWS
|
||||
return ::wopendir(dir_name);
|
||||
#else
|
||||
auto str_dir = google::logging::internal::StrConvert<wchar_t, char>(dir_name);
|
||||
return opendir(str_dir.c_str());
|
||||
#endif // GLOG_OS_WINDOWS
|
||||
}
|
||||
|
||||
dirent* readdir(DIR* dir) { return ::readdir(dir); }
|
||||
int closedir(DIR* dir) { return ::closedir(dir); }
|
||||
#ifdef GLOG_OS_WINDOWS
|
||||
wdirent* readdir(WDIR* dir) { return ::wreaddir(dir); }
|
||||
int closedir(WDIR* dir) { return ::wclosedir(dir); }
|
||||
#endif // GLOG_OS_WINDOWS
|
||||
|
||||
#ifdef GLOG_OS_WINDOWS
|
||||
typedef struct _stat64i32 wstat;
|
||||
#else
|
||||
typedef struct stat wstat;
|
||||
#endif // GLOG_OS_WINDOWS
|
||||
|
||||
int stat(const char* filename, struct stat* const s) {
|
||||
return ::stat(filename, s);
|
||||
}
|
||||
int stat(const wchar_t* filename, wstat* s) {
|
||||
#ifdef GLOG_OS_WINDOWS
|
||||
return ::_wstat(filename, s);
|
||||
#else
|
||||
auto str_filename =
|
||||
google::logging::internal::StrConvert<wchar_t, char>(filename);
|
||||
return ::stat(str_filename.c_str(), s);
|
||||
#endif // GLOG_OS_WINDOWS
|
||||
}
|
||||
int access(const char* dir_name, int access_mode) {
|
||||
return ::access(dir_name, access_mode);
|
||||
}
|
||||
int access(const wchar_t* dir_name, int access_mode) {
|
||||
#ifdef GLOG_OS_WINDOWS
|
||||
return ::_waccess(dir_name, access_mode);
|
||||
#else
|
||||
auto str_dir_name =
|
||||
google::logging::internal::StrConvert<wchar_t, char>(dir_name);
|
||||
return ::access(str_dir_name.c_str(), access_mode);
|
||||
#endif // GLOG_OS_WINDOWS
|
||||
}
|
||||
void perror(const char* msg) {
|
||||
::perror(msg);
|
||||
}
|
||||
void perror(const wchar_t *msg) {
|
||||
#ifdef GLOG_OS_WINDOWS
|
||||
_wperror(msg);
|
||||
#else
|
||||
auto str_msg = google::logging::internal::StrConvert<wchar_t, char>(msg);
|
||||
perror(str_msg.c_str());
|
||||
#endif
|
||||
}
|
||||
} // namespace details
|
||||
|
||||
static void GetHostName(string* hostname) {
|
||||
#if defined(HAVE_SYS_UTSNAME_H)
|
||||
struct utsname buf;
|
||||
@ -329,8 +443,9 @@ int64 LogMessage::num_messages_[NUM_SEVERITIES] = {0, 0, 0, 0};
|
||||
static bool stop_writing = false;
|
||||
|
||||
const char* const LogSeverityNames[] = {"INFO", "WARNING", "ERROR", "FATAL"};
|
||||
|
||||
// Has the user called SetExitOnDFatal(true)?
|
||||
const wchar_t* const LogSeverityNamesW[] = {L"INFO", L"WARNING", L"ERROR",
|
||||
L"FATAL"};
|
||||
// Has the user called SetExitOnDFatal(true)?
|
||||
static bool exit_on_dfatal = true;
|
||||
|
||||
const char* GetLogSeverityName(LogSeverity severity) {
|
||||
@ -343,7 +458,6 @@ static bool SendEmailInternal(const char* dest, const char* subject,
|
||||
base::Logger::~Logger() = default;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::intmax_t kSecondsInDay = 60 * 60 * 24;
|
||||
constexpr std::intmax_t kSecondsInWeek = kSecondsInDay * 7;
|
||||
|
||||
@ -378,7 +492,7 @@ std::unique_ptr<PrefixFormatter> g_prefix_formatter;
|
||||
// Encapsulates all file-system related state
|
||||
class LogFileObject : public base::Logger {
|
||||
public:
|
||||
LogFileObject(LogSeverity severity, const char* base_filename);
|
||||
LogFileObject(LogSeverity severity, const wchar_t* base_filename);
|
||||
~LogFileObject() override;
|
||||
|
||||
void Write(bool force_flush, // Should we force a flush here?
|
||||
@ -387,9 +501,9 @@ class LogFileObject : public base::Logger {
|
||||
const char* message, size_t message_len) override;
|
||||
|
||||
// Configuration options
|
||||
void SetBasename(const char* basename);
|
||||
void SetExtension(const char* ext);
|
||||
void SetSymlinkBasename(const char* symlink_basename);
|
||||
void SetBasename(const wchar_t* basename);
|
||||
void SetExtension(const wchar_t* ext);
|
||||
void SetSymlinkBasename(const wchar_t* symlink_basename);
|
||||
|
||||
// Normal flushing routine
|
||||
void Flush() override;
|
||||
@ -411,9 +525,9 @@ class LogFileObject : public base::Logger {
|
||||
|
||||
std::mutex mutex_;
|
||||
bool base_filename_selected_;
|
||||
string base_filename_;
|
||||
string symlink_basename_;
|
||||
string filename_extension_; // option users can specify (eg to add port#)
|
||||
wstring base_filename_;
|
||||
wstring symlink_basename_;
|
||||
wstring filename_extension_; // option users can specify (eg to add port#)
|
||||
std::unique_ptr<FILE> file_;
|
||||
LogSeverity severity_;
|
||||
uint32 bytes_since_flush_{0};
|
||||
@ -427,7 +541,9 @@ class LogFileObject : public base::Logger {
|
||||
// Actually create a logfile using the value of base_filename_ and the
|
||||
// optional argument time_pid_string
|
||||
// REQUIRES: lock_ is held
|
||||
bool CreateLogfile(const string& time_pid_string);
|
||||
bool CreateLogfile(const wstring& time_pid_string);
|
||||
void CreateSymlink(const wstring& link_des_w, const wstring& link_path_w,
|
||||
const wstring& line_name_w);
|
||||
};
|
||||
|
||||
// Encapsulate all log cleaner related states
|
||||
@ -440,23 +556,23 @@ class LogCleaner {
|
||||
void Disable();
|
||||
|
||||
void Run(const std::chrono::system_clock::time_point& current_time,
|
||||
bool base_filename_selected, const string& base_filename,
|
||||
const string& filename_extension);
|
||||
bool base_filename_selected, const wstring& base_filename,
|
||||
const wstring& filename_extension);
|
||||
|
||||
bool enabled() const { return enabled_; }
|
||||
|
||||
private:
|
||||
vector<string> GetOverdueLogNames(
|
||||
string log_directory,
|
||||
vector<std::wstring> GetOverdueLogNames(
|
||||
const std::wstring &log_directory,
|
||||
const std::chrono::system_clock::time_point& current_time,
|
||||
const string& base_filename, const string& filename_extension) const;
|
||||
const std::wstring& base_filename, const std::wstring& filename_extension) const;
|
||||
|
||||
bool IsLogFromCurrentProject(const string& filepath,
|
||||
const string& base_filename,
|
||||
const string& filename_extension) const;
|
||||
bool IsLogFromCurrentProject(const std::wstring& filepath,
|
||||
const std::wstring& base_filename,
|
||||
const std::wstring& filename_extension) const;
|
||||
|
||||
bool IsLogLastModifiedOver(
|
||||
const string& filepath,
|
||||
const std::wstring& filepath,
|
||||
const std::chrono::system_clock::time_point& current_time) const;
|
||||
|
||||
bool enabled_{false};
|
||||
@ -479,11 +595,11 @@ class LogDestination {
|
||||
|
||||
// These methods are just forwarded to by their global versions.
|
||||
static void SetLogDestination(LogSeverity severity,
|
||||
const char* base_filename);
|
||||
static void SetLogSymlink(LogSeverity severity, const char* symlink_basename);
|
||||
const wchar_t* base_filename);
|
||||
static void SetLogSymlink(LogSeverity severity, const wchar_t* symlink_basename);
|
||||
static void AddLogSink(LogSink* destination);
|
||||
static void RemoveLogSink(LogSink* destination);
|
||||
static void SetLogFilenameExtension(const char* filename_extension);
|
||||
static void SetLogFilenameExtension(const wchar_t* filename_extension);
|
||||
static void SetStderrLogging(LogSeverity min_severity);
|
||||
static void SetEmailLogging(LogSeverity min_severity, const char* addresses);
|
||||
static void LogToStderr();
|
||||
@ -502,7 +618,7 @@ class LogDestination {
|
||||
}
|
||||
|
||||
static void DeleteLogDestinations();
|
||||
LogDestination(LogSeverity severity, const char* base_filename);
|
||||
LogDestination(LogSeverity severity, const wchar_t* base_filename);
|
||||
|
||||
private:
|
||||
#if defined(__cpp_lib_shared_mutex) && (__cpp_lib_shared_mutex >= 201505L)
|
||||
@ -601,7 +717,7 @@ const string& LogDestination::hostname() {
|
||||
return hostname_;
|
||||
}
|
||||
|
||||
LogDestination::LogDestination(LogSeverity severity, const char* base_filename)
|
||||
LogDestination::LogDestination(LogSeverity severity, const wchar_t* base_filename)
|
||||
: fileobject_(severity, base_filename), logger_(&fileobject_) {}
|
||||
|
||||
LogDestination::~LogDestination() { ResetLoggerImpl(); }
|
||||
@ -647,7 +763,7 @@ inline void LogDestination::FlushLogFiles(int min_severity) {
|
||||
}
|
||||
|
||||
inline void LogDestination::SetLogDestination(LogSeverity severity,
|
||||
const char* base_filename) {
|
||||
const wchar_t* base_filename) {
|
||||
// Prevent any subtle race conditions by wrapping a mutex lock around
|
||||
// all this stuff.
|
||||
std::lock_guard<std::mutex> l{log_mutex};
|
||||
@ -655,7 +771,7 @@ inline void LogDestination::SetLogDestination(LogSeverity severity,
|
||||
}
|
||||
|
||||
inline void LogDestination::SetLogSymlink(LogSeverity severity,
|
||||
const char* symlink_basename) {
|
||||
const wchar_t* symlink_basename) {
|
||||
CHECK_GE(severity, 0);
|
||||
CHECK_LT(severity, NUM_SEVERITIES);
|
||||
std::lock_guard<std::mutex> l{log_mutex};
|
||||
@ -681,7 +797,7 @@ inline void LogDestination::RemoveLogSink(LogSink* destination) {
|
||||
}
|
||||
}
|
||||
|
||||
inline void LogDestination::SetLogFilenameExtension(const char* ext) {
|
||||
inline void LogDestination::SetLogFilenameExtension(const wchar_t* ext) {
|
||||
// Prevent any subtle race conditions by wrapping a mutex lock around
|
||||
// all this stuff.
|
||||
std::lock_guard<std::mutex> l{log_mutex};
|
||||
@ -703,8 +819,7 @@ inline void LogDestination::LogToStderr() {
|
||||
// SetLogDestination already do the locking!
|
||||
SetStderrLogging(GLOG_INFO); // thus everything is "also" logged to stderr
|
||||
for (int i = 0; i < NUM_SEVERITIES; ++i) {
|
||||
SetLogDestination(static_cast<LogSeverity>(i),
|
||||
""); // "" turns off logging to a logfile
|
||||
SetLogDestination(static_cast<LogSeverity>(i), L""); // "" turns off logging to a logfile
|
||||
}
|
||||
}
|
||||
|
||||
@ -904,11 +1019,10 @@ void SetApplicationFingerprint(const std::string& fingerprint) {
|
||||
|
||||
namespace {
|
||||
|
||||
// Directory delimiter; Windows supports both forward slashes and backslashes
|
||||
#ifdef GLOG_OS_WINDOWS
|
||||
const char possible_dir_delim[] = {'\\', '/'};
|
||||
const wchar_t possible_dir_delim[] = {L'\\', L'/'};
|
||||
#else
|
||||
const char possible_dir_delim[] = {'/'};
|
||||
const wchar_t possible_dir_delim[] = {L'/'};
|
||||
#endif
|
||||
|
||||
string PrettyDuration(const std::chrono::duration<int>& secs) {
|
||||
@ -922,10 +1036,10 @@ string PrettyDuration(const std::chrono::duration<int>& secs) {
|
||||
return result.str();
|
||||
}
|
||||
|
||||
LogFileObject::LogFileObject(LogSeverity severity, const char* base_filename)
|
||||
LogFileObject::LogFileObject(LogSeverity severity, const wchar_t* base_filename)
|
||||
: base_filename_selected_(base_filename != nullptr),
|
||||
base_filename_((base_filename != nullptr) ? base_filename : ""),
|
||||
symlink_basename_(glog_internal_namespace_::ProgramInvocationShortName()),
|
||||
base_filename_((base_filename != nullptr) ? base_filename : L""),
|
||||
symlink_basename_(logging::internal::StrConvert<char, wchar_t>(glog_internal_namespace_::ProgramInvocationShortName())),
|
||||
filename_extension_(),
|
||||
severity_(severity),
|
||||
rollover_attempt_(kRolloverAttemptFrequency - 1),
|
||||
@ -936,7 +1050,7 @@ LogFileObject::~LogFileObject() {
|
||||
file_ = nullptr;
|
||||
}
|
||||
|
||||
void LogFileObject::SetBasename(const char* basename) {
|
||||
void LogFileObject::SetBasename(const wchar_t* basename) {
|
||||
std::lock_guard<std::mutex> l{mutex_};
|
||||
base_filename_selected_ = true;
|
||||
if (base_filename_ != basename) {
|
||||
@ -949,7 +1063,7 @@ void LogFileObject::SetBasename(const char* basename) {
|
||||
}
|
||||
}
|
||||
|
||||
void LogFileObject::SetExtension(const char* ext) {
|
||||
void LogFileObject::SetExtension(const wchar_t* ext) {
|
||||
std::lock_guard<std::mutex> l{mutex_};
|
||||
if (filename_extension_ != ext) {
|
||||
// Get rid of old log file since we are changing names
|
||||
@ -961,7 +1075,7 @@ void LogFileObject::SetExtension(const char* ext) {
|
||||
}
|
||||
}
|
||||
|
||||
void LogFileObject::SetSymlinkBasename(const char* symlink_basename) {
|
||||
void LogFileObject::SetSymlinkBasename(const wchar_t* symlink_basename) {
|
||||
std::lock_guard<std::mutex> l{mutex_};
|
||||
symlink_basename_ = symlink_basename;
|
||||
}
|
||||
@ -983,21 +1097,21 @@ void LogFileObject::FlushUnlocked(
|
||||
std::chrono::duration<int32>{FLAGS_logbufsecs});
|
||||
}
|
||||
|
||||
bool LogFileObject::CreateLogfile(const string& time_pid_string) {
|
||||
string string_filename = base_filename_;
|
||||
bool LogFileObject::CreateLogfile(const wstring& time_pid_string) {
|
||||
wstring string_filename = base_filename_;
|
||||
if (FLAGS_timestamp_in_logfile_name) {
|
||||
string_filename += time_pid_string;
|
||||
}
|
||||
string_filename += filename_extension_;
|
||||
const char* filename = string_filename.c_str();
|
||||
// only write to files, create if non-existant.
|
||||
int flags = O_WRONLY | O_CREAT;
|
||||
if (FLAGS_timestamp_in_logfile_name) {
|
||||
// demand that the file is unique for our timestamp (fail if it exists).
|
||||
flags = flags | O_EXCL;
|
||||
}
|
||||
FileDescriptor fd{
|
||||
open(filename, flags, static_cast<mode_t>(FLAGS_logfile_mode))};
|
||||
FileDescriptor fd{details::open(string_filename.c_str(), flags,
|
||||
static_cast<mode_t>(FLAGS_logfile_mode))};
|
||||
|
||||
if (!fd) return false;
|
||||
#ifdef HAVE_FCNTL
|
||||
// Mark the file close-on-exec. We don't really care if this fails
|
||||
@ -1030,7 +1144,9 @@ bool LogFileObject::CreateLogfile(const string& time_pid_string) {
|
||||
file_.reset(fdopen(fd.release(), "a")); // Make a FILE*.
|
||||
if (file_ == nullptr) { // Man, we're screwed!
|
||||
if (FLAGS_timestamp_in_logfile_name) {
|
||||
unlink(filename); // Erase the half-baked evidence: an unusable log file,
|
||||
details::unlink(string_filename.c_str()); // Erase the half-baked evidence: an
|
||||
// unusable log
|
||||
// file,
|
||||
// only if we just created it.
|
||||
}
|
||||
return false;
|
||||
@ -1051,41 +1167,36 @@ bool LogFileObject::CreateLogfile(const string& time_pid_string) {
|
||||
// no error.
|
||||
if (!symlink_basename_.empty()) {
|
||||
// take directory from filename
|
||||
const char* slash = strrchr(filename, PATH_SEPARATOR);
|
||||
const string linkname =
|
||||
symlink_basename_ + '.' + LogSeverityNames[severity_];
|
||||
string linkpath;
|
||||
if (slash)
|
||||
linkpath = string(
|
||||
filename, static_cast<size_t>(slash - filename + 1)); // get dirname
|
||||
std::size_t slash = string_filename.find_last_of(PATH_SEPARATOR);
|
||||
const wstring linkname =
|
||||
symlink_basename_ + L'.' + LogSeverityNamesW[severity_];
|
||||
wstring linkpath;
|
||||
if (slash != std::string::npos)
|
||||
linkpath = string_filename.substr(0, slash + 1); // get dirname
|
||||
linkpath += linkname;
|
||||
unlink(linkpath.c_str()); // delete old one if it exists
|
||||
details::unlink(linkpath.c_str()); // delete old one if it exists
|
||||
|
||||
#if defined(GLOG_OS_WINDOWS)
|
||||
// TODO(hamaji): Create lnk file on Windows?
|
||||
#elif defined(HAVE_UNISTD_H)
|
||||
// We must 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;
|
||||
if (symlink(linkdest, linkpath.c_str()) != 0) {
|
||||
// silently ignore failures
|
||||
}
|
||||
|
||||
// Make an additional link to the log file in a place specified by
|
||||
// FLAGS_log_link, if indicated
|
||||
if (!FLAGS_log_link.empty()) {
|
||||
linkpath = FLAGS_log_link + "/" + linkname;
|
||||
unlink(linkpath.c_str()); // delete old one if it exists
|
||||
if (symlink(filename, linkpath.c_str()) != 0) {
|
||||
// silently ignore failures
|
||||
}
|
||||
}
|
||||
#endif
|
||||
wstring link_dest = slash != std::string::npos
|
||||
? (string_filename.substr(slash + 1))
|
||||
: string_filename;
|
||||
CreateSymlink(link_dest, linkpath, linkname);
|
||||
}
|
||||
|
||||
return true; // Everything worked
|
||||
}
|
||||
void LogFileObject::CreateSymlink(const wstring& link_dest_w,
|
||||
const wstring& link_path_w,
|
||||
const wstring& link_name_w) {
|
||||
details::symlink(link_dest_w.c_str(), link_path_w.c_str());
|
||||
if (!FLAGS_log_link.empty()) {
|
||||
auto new_link_path =
|
||||
logging::internal::StrConvert<char, wchar_t>(FLAGS_log_link) + L"/" +
|
||||
link_name_w;
|
||||
details::unlink(new_link_path.c_str());
|
||||
details::symlink(link_dest_w.c_str(), new_link_path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void LogFileObject::Write(
|
||||
bool force_flush, const std::chrono::system_clock::time_point& timestamp,
|
||||
@ -1131,18 +1242,18 @@ void LogFileObject::Write(
|
||||
}
|
||||
|
||||
// The logfile's filename will have the date/time & pid in it
|
||||
ostringstream time_pid_stream;
|
||||
time_pid_stream.fill('0');
|
||||
std::wostringstream time_pid_stream;
|
||||
time_pid_stream.fill(L'0');
|
||||
time_pid_stream << 1900 + tm_time.tm_year << setw(2) << 1 + tm_time.tm_mon
|
||||
<< setw(2) << tm_time.tm_mday << '-' << setw(2)
|
||||
<< setw(2) << tm_time.tm_mday << L'-' << setw(2)
|
||||
<< tm_time.tm_hour << setw(2) << tm_time.tm_min << setw(2)
|
||||
<< tm_time.tm_sec << '.' << GetMainThreadPid();
|
||||
const string& time_pid_string = time_pid_stream.str();
|
||||
<< tm_time.tm_sec << L'.' << GetMainThreadPid();
|
||||
const wstring& time_pid_string = time_pid_stream.str();
|
||||
|
||||
if (base_filename_selected_) {
|
||||
if (!CreateLogfile(time_pid_string)) {
|
||||
perror("Could not create log file");
|
||||
fprintf(stderr, "COULD NOT CREATE LOGFILE '%s'!\n",
|
||||
fwprintf(stderr, L"COULD NOT CREATE LOGFILE '%s'!\n",
|
||||
time_pid_string.c_str());
|
||||
return;
|
||||
}
|
||||
@ -1173,13 +1284,15 @@ void LogFileObject::Write(
|
||||
stripped_filename = stripped_filename + '.' + hostname + '.' + uidname +
|
||||
".log." + LogSeverityNames[severity_] + '.';
|
||||
// We're going to (potentially) try to put logs in several different dirs
|
||||
const vector<string>& log_dirs = GetLoggingDirectories();
|
||||
const vector<wstring> log_dirs = GetLoggingDirectoriesW();
|
||||
|
||||
// Go through the list of dirs, and try to create the log file in each
|
||||
// until we succeed or run out of options
|
||||
bool success = false;
|
||||
wstring stripped_filename_w =
|
||||
logging::internal::StrConvert<char, wchar_t>(stripped_filename);
|
||||
for (const auto& log_dir : log_dirs) {
|
||||
base_filename_ = log_dir + "/" + stripped_filename;
|
||||
base_filename_ = log_dir + stripped_filename_w;
|
||||
if (CreateLogfile(time_pid_string)) {
|
||||
success = true;
|
||||
break;
|
||||
@ -1188,7 +1301,7 @@ void LogFileObject::Write(
|
||||
// If we never succeeded, we have to give up
|
||||
if (success == false) {
|
||||
perror("Could not create logging file");
|
||||
fprintf(stderr, "COULD NOT CREATE A LOGGINGFILE %s!",
|
||||
fwprintf(stderr, L"COULD NOT CREATE A LOGGINGFILE %s!",
|
||||
time_pid_string.c_str());
|
||||
return;
|
||||
}
|
||||
@ -1292,8 +1405,8 @@ void LogCleaner::Enable(const std::chrono::minutes& overdue) {
|
||||
void LogCleaner::Disable() { enabled_ = false; }
|
||||
|
||||
void LogCleaner::Run(const std::chrono::system_clock::time_point& current_time,
|
||||
bool base_filename_selected, const string& base_filename,
|
||||
const string& filename_extension) {
|
||||
bool base_filename_selected, const wstring& base_filename,
|
||||
const wstring& filename_extension) {
|
||||
assert(enabled_);
|
||||
assert(!base_filename_selected || !base_filename.empty());
|
||||
|
||||
@ -1307,55 +1420,53 @@ void LogCleaner::Run(const std::chrono::system_clock::time_point& current_time,
|
||||
std::chrono::duration_cast<std::chrono::system_clock::duration>(
|
||||
std::chrono::duration<int32>{FLAGS_logcleansecs});
|
||||
|
||||
vector<string> dirs;
|
||||
vector<wstring> dirs;
|
||||
|
||||
if (!base_filename_selected) {
|
||||
dirs = GetLoggingDirectories();
|
||||
dirs = GetLoggingDirectoriesW();
|
||||
} else {
|
||||
size_t pos = base_filename.find_last_of(possible_dir_delim, string::npos,
|
||||
sizeof(possible_dir_delim));
|
||||
if (pos != string::npos) {
|
||||
string dir = base_filename.substr(0, pos + 1);
|
||||
wstring dir = base_filename.substr(0, pos + 1);
|
||||
dirs.push_back(dir);
|
||||
} else {
|
||||
dirs.emplace_back(".");
|
||||
dirs.emplace_back(L".");
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::string& dir : dirs) {
|
||||
vector<string> logs = GetOverdueLogNames(dir, current_time, base_filename,
|
||||
for (const std::wstring& dir : dirs) {
|
||||
vector<wstring> logs = GetOverdueLogNames(dir, current_time, base_filename,
|
||||
filename_extension);
|
||||
for (const std::string& log : logs) {
|
||||
for (const std::wstring& log : logs) {
|
||||
// NOTE May fail on Windows if the file is still open
|
||||
int result = unlink(log.c_str());
|
||||
int result = details::unlink(log.c_str());
|
||||
if (result != 0) {
|
||||
perror(("Could not remove overdue log " + log).c_str());
|
||||
details::perror((L"Could not remove overdue log " + log).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector<string> LogCleaner::GetOverdueLogNames(
|
||||
string log_directory,
|
||||
vector<std::wstring> LogCleaner::GetOverdueLogNames(
|
||||
const std::wstring &log_directory,
|
||||
const std::chrono::system_clock::time_point& current_time,
|
||||
const string& base_filename, const string& filename_extension) const {
|
||||
const std::wstring& base_filename, const std::wstring& filename_extension) const {
|
||||
// The names of overdue logs.
|
||||
vector<string> overdue_log_names;
|
||||
vector<std::wstring> overdue_log_names;
|
||||
|
||||
// Try to get all files within log_directory.
|
||||
DIR* dir;
|
||||
struct dirent* ent;
|
||||
auto dir = details::opendir(log_directory.c_str());
|
||||
|
||||
if ((dir = opendir(log_directory.c_str()))) {
|
||||
while ((ent = readdir(dir))) {
|
||||
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
|
||||
if (dir) {
|
||||
auto ent = details::readdir(dir);
|
||||
while (ent) {
|
||||
std::wstring filepath = logging::internal::StrConvert(ent->d_name);
|
||||
if (filepath == L"." || filepath == L"..") {
|
||||
continue;
|
||||
}
|
||||
|
||||
string filepath = ent->d_name;
|
||||
const char* const dir_delim_end =
|
||||
const wchar_t* const dir_delim_end =
|
||||
possible_dir_delim + sizeof(possible_dir_delim);
|
||||
|
||||
if (!log_directory.empty() &&
|
||||
std::find(possible_dir_delim, dir_delim_end,
|
||||
log_directory[log_directory.size() - 1]) != dir_delim_end) {
|
||||
@ -1368,25 +1479,25 @@ vector<string> LogCleaner::GetOverdueLogNames(
|
||||
overdue_log_names.push_back(filepath);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
details::closedir(dir);
|
||||
}
|
||||
|
||||
return overdue_log_names;
|
||||
}
|
||||
|
||||
bool LogCleaner::IsLogFromCurrentProject(
|
||||
const string& filepath, const string& base_filename,
|
||||
const string& filename_extension) const {
|
||||
const std::wstring& filepath, const std::wstring& base_filename,
|
||||
const std::wstring& filename_extension) const {
|
||||
// We should remove duplicated delimiters from `base_filename`, e.g.,
|
||||
// before: "/tmp//<base_filename>.<create_time>.<pid>"
|
||||
// after: "/tmp/<base_filename>.<create_time>.<pid>"
|
||||
string cleaned_base_filename;
|
||||
std::wstring cleaned_base_filename;
|
||||
|
||||
const char* const dir_delim_end =
|
||||
const wchar_t* const dir_delim_end =
|
||||
possible_dir_delim + sizeof(possible_dir_delim);
|
||||
|
||||
size_t real_filepath_size = filepath.size();
|
||||
for (char c : base_filename) {
|
||||
for (wchar_t c : base_filename) {
|
||||
if (cleaned_base_filename.empty()) {
|
||||
cleaned_base_filename += c;
|
||||
} else if (std::find(possible_dir_delim, dir_delim_end, c) ==
|
||||
@ -1410,7 +1521,7 @@ bool LogCleaner::IsLogFromCurrentProject(
|
||||
return false;
|
||||
}
|
||||
// for origin version, `filename_extension` is middle of the `filepath`.
|
||||
string ext = filepath.substr(cleaned_base_filename.size(),
|
||||
std::wstring ext = filepath.substr(cleaned_base_filename.size(),
|
||||
filename_extension.size());
|
||||
if (ext == filename_extension) {
|
||||
cleaned_base_filename += filename_extension;
|
||||
@ -1429,30 +1540,30 @@ bool LogCleaner::IsLogFromCurrentProject(
|
||||
// The characters after `cleaned_base_filename` should match the format:
|
||||
// YYYYMMDD-HHMMSS.pid
|
||||
for (size_t i = cleaned_base_filename.size(); i < real_filepath_size; i++) {
|
||||
const char& c = filepath[i];
|
||||
const wchar_t& c = filepath[i];
|
||||
|
||||
if (i <= cleaned_base_filename.size() + 7) { // 0 ~ 7 : YYYYMMDD
|
||||
if (c < '0' || c > '9') {
|
||||
if (c < L'0' || c > L'9') {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (i == cleaned_base_filename.size() + 8) { // 8: -
|
||||
if (c != '-') {
|
||||
if (c != L'-') {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (i <= cleaned_base_filename.size() + 14) { // 9 ~ 14: HHMMSS
|
||||
if (c < '0' || c > '9') {
|
||||
if (c < L'0' || c > L'9') {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (i == cleaned_base_filename.size() + 15) { // 15: .
|
||||
if (c != '.') {
|
||||
if (c != L'.') {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (i >= cleaned_base_filename.size() + 16) { // 16+: pid
|
||||
if (c < '0' || c > '9') {
|
||||
if (c < L'0' || c > L'9') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1462,12 +1573,12 @@ bool LogCleaner::IsLogFromCurrentProject(
|
||||
}
|
||||
|
||||
bool LogCleaner::IsLogLastModifiedOver(
|
||||
const string& filepath,
|
||||
const std::wstring& filepath,
|
||||
const std::chrono::system_clock::time_point& current_time) const {
|
||||
// Try to get the last modified time of this file.
|
||||
struct stat file_stat;
|
||||
details::wstat file_stat;
|
||||
|
||||
if (stat(filepath.c_str(), &file_stat) == 0) {
|
||||
if (details::stat(filepath.c_str(), &file_stat) == 0) {
|
||||
const auto last_modified_time =
|
||||
std::chrono::system_clock::from_time_t(file_stat.st_mtime);
|
||||
const auto diff = current_time - last_modified_time;
|
||||
@ -2004,10 +2115,18 @@ void FlushLogFilesUnsafe(LogSeverity min_severity) {
|
||||
}
|
||||
|
||||
void SetLogDestination(LogSeverity severity, const char* base_filename) {
|
||||
auto w_base_filename = logging::internal::StrConvert<char, wchar_t>(base_filename);
|
||||
SetLogDestination(severity, w_base_filename.c_str());
|
||||
}
|
||||
void SetLogDestination(LogSeverity severity, const wchar_t* base_filename) {
|
||||
LogDestination::SetLogDestination(severity, base_filename);
|
||||
}
|
||||
|
||||
void SetLogSymlink(LogSeverity severity, const char* symlink_basename) {
|
||||
auto w_symlink_basename = logging::internal::StrConvert<char, wchar_t>(symlink_basename);
|
||||
SetLogSymlink(severity, w_symlink_basename.c_str());
|
||||
}
|
||||
void SetLogSymlink(LogSeverity severity, const wchar_t* symlink_basename) {
|
||||
LogDestination::SetLogSymlink(severity, symlink_basename);
|
||||
}
|
||||
|
||||
@ -2046,8 +2165,11 @@ void AddLogSink(LogSink* destination) {
|
||||
void RemoveLogSink(LogSink* destination) {
|
||||
LogDestination::RemoveLogSink(destination);
|
||||
}
|
||||
|
||||
void SetLogFilenameExtension(const char* ext) {
|
||||
void SetLogFilenameExtension(const char* filename_extension) {
|
||||
auto w_extension = logging::internal::StrConvert<char, wchar_t>(filename_extension);
|
||||
SetLogFilenameExtension(w_extension.c_str());
|
||||
}
|
||||
void SetLogFilenameExtension(const wchar_t* ext) {
|
||||
LogDestination::SetLogFilenameExtension(ext);
|
||||
}
|
||||
|
||||
@ -2243,44 +2365,43 @@ bool SendEmail(const char* dest, const char* subject, const char* body) {
|
||||
return SendEmailInternal(dest, subject, body, true);
|
||||
}
|
||||
|
||||
static void GetTempDirectories(vector<string>& list) {
|
||||
static void GetTempDirectories(vector<wstring>& list) {
|
||||
list.clear();
|
||||
#ifdef GLOG_OS_WINDOWS
|
||||
// On windows we'll try to find a directory in this order:
|
||||
// C:/Documents & Settings/whomever/TEMP (or whatever GetTempPath() is)
|
||||
// C:/TMP/
|
||||
// C:/TEMP/
|
||||
char tmp[MAX_PATH];
|
||||
if (GetTempPathA(MAX_PATH, tmp)) list.push_back(tmp);
|
||||
list.push_back("C:\\TMP\\");
|
||||
list.push_back("C:\\TEMP\\");
|
||||
wchar_t tmp[MAX_PATH];
|
||||
if (GetTempPathW(MAX_PATH, tmp)) list.push_back(tmp);
|
||||
list.push_back(L"C:\\TMP\\");
|
||||
list.push_back(L"C:\\TEMP\\");
|
||||
#else
|
||||
// Directories, in order of preference. If we find a dir that
|
||||
// exists, we stop adding other less-preferred dirs
|
||||
const char* candidates[] = {
|
||||
const std::wstring candidates[] = {
|
||||
// Non-null only during unittest/regtest
|
||||
getenv("TEST_TMPDIR"),
|
||||
google::logging::internal::getenv(L"TEST_TMPDIR"),
|
||||
|
||||
// Explicitly-supplied temp dirs
|
||||
getenv("TMPDIR"),
|
||||
getenv("TMP"),
|
||||
google::logging::internal::getenv(L"TMPDIR"),
|
||||
google::logging::internal::getenv(L"TMP"),
|
||||
|
||||
// If all else fails
|
||||
"/tmp",
|
||||
L"/tmp",
|
||||
};
|
||||
|
||||
for (auto d : candidates) {
|
||||
if (!d) continue; // Empty env var
|
||||
for (auto dstr : candidates) {
|
||||
if (dstr.empty()) continue; // Empty env var
|
||||
|
||||
// Make sure we don't surprise anyone who's expecting a '/'
|
||||
string dstr = d;
|
||||
if (dstr[dstr.size() - 1] != '/') {
|
||||
dstr += "/";
|
||||
if (dstr[dstr.size() - 1] != L'/') {
|
||||
dstr += L"/";
|
||||
}
|
||||
list.push_back(dstr);
|
||||
|
||||
struct stat statbuf;
|
||||
if (!stat(d, &statbuf) && S_ISDIR(statbuf.st_mode)) {
|
||||
details::wstat statbuf;
|
||||
if (!details::stat(dstr.c_str(), &statbuf) && S_ISDIR(statbuf.st_mode)) {
|
||||
// We found a dir that exists - we're done.
|
||||
return;
|
||||
}
|
||||
@ -2288,48 +2409,65 @@ static void GetTempDirectories(vector<string>& list) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static std::unique_ptr<std::vector<std::string>> logging_directories_list;
|
||||
|
||||
const vector<string>& GetLoggingDirectories() {
|
||||
static std::unique_ptr<std::vector<std::wstring>> logging_directories_list;
|
||||
const vector<wstring>& GetLoggingDirectoriesW(const std::wstring &log_dir) {
|
||||
// Not strictly thread-safe but we're called early in InitGoogle().
|
||||
if (logging_directories_list == nullptr) {
|
||||
logging_directories_list = std::make_unique<std::vector<std::string>>();
|
||||
logging_directories_list = std::make_unique<std::vector<std::wstring>>();
|
||||
|
||||
if (!FLAGS_log_dir.empty()) {
|
||||
if (!log_dir.empty()) {
|
||||
// Ensure the specified path ends with a directory delimiter.
|
||||
if (std::find(std::begin(possible_dir_delim),
|
||||
std::end(possible_dir_delim),
|
||||
FLAGS_log_dir.back()) == std::end(possible_dir_delim)) {
|
||||
logging_directories_list->push_back(FLAGS_log_dir + "/");
|
||||
log_dir.back()) == std::end(possible_dir_delim)) {
|
||||
logging_directories_list->push_back(log_dir + L"/");
|
||||
} else {
|
||||
logging_directories_list->push_back(FLAGS_log_dir);
|
||||
logging_directories_list->push_back(log_dir);
|
||||
}
|
||||
} else {
|
||||
GetTempDirectories(*logging_directories_list);
|
||||
#ifdef GLOG_OS_WINDOWS
|
||||
char tmp[MAX_PATH];
|
||||
if (GetWindowsDirectoryA(tmp, MAX_PATH))
|
||||
wchar_t tmp[MAX_PATH];
|
||||
if (GetWindowsDirectoryW(tmp, MAX_PATH))
|
||||
logging_directories_list->push_back(tmp);
|
||||
logging_directories_list->push_back(".\\");
|
||||
logging_directories_list->push_back(L".\\");
|
||||
#else
|
||||
logging_directories_list->push_back("./");
|
||||
logging_directories_list->push_back(L"./");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return *logging_directories_list;
|
||||
}
|
||||
|
||||
|
||||
const vector<string> GetLoggingDirectories() {
|
||||
auto wdirs = GetLoggingDirectoriesW();
|
||||
vector<string> dirs;
|
||||
for (const auto wdir : wdirs) {
|
||||
dirs.push_back(logging::internal::StrConvert<wchar_t, char>(wdir));
|
||||
}
|
||||
return dirs;
|
||||
}
|
||||
|
||||
const vector<wstring>& GetLoggingDirectoriesW() {
|
||||
if (!FLAGS_log_wdir.empty()) {
|
||||
return GetLoggingDirectoriesW(FLAGS_log_wdir);
|
||||
} else {
|
||||
return GetLoggingDirectoriesW(logging::internal::StrConvert<char, wchar_t>(FLAGS_log_dir));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a set of existing temporary directories, which will be a
|
||||
// subset of the directories returned by GetLoggingDirectories().
|
||||
// Thread-safe.
|
||||
GLOG_NO_EXPORT
|
||||
void GetExistingTempDirectories(vector<string>& list) {
|
||||
void GetExistingTempDirectories(vector<wstring>& list) {
|
||||
GetTempDirectories(list);
|
||||
auto i_dir = list.begin();
|
||||
while (i_dir != list.end()) {
|
||||
// zero arg to access means test for existence; no constant
|
||||
// defined on windows
|
||||
if (access(i_dir->c_str(), 0)) {
|
||||
if (details::access(i_dir->c_str(), 0)) {
|
||||
i_dir = list.erase(i_dir);
|
||||
} else {
|
||||
++i_dir;
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <stdlib.h>
|
||||
|
||||
// printf macros for size_t, in the style of inttypes.h
|
||||
#ifdef _LP64
|
||||
@ -125,6 +126,59 @@ struct CrashReason {
|
||||
int depth{0};
|
||||
};
|
||||
|
||||
|
||||
static size_t CharConvert(wchar_t* dst, const char* src, size_t n) {
|
||||
return mbstowcs(dst, src, n);
|
||||
}
|
||||
|
||||
static size_t CharConvert(char* dst, const wchar_t* src, size_t n) {
|
||||
return wcstombs(dst, src, n);
|
||||
}
|
||||
|
||||
template <class ChSrc, class ChDst>
|
||||
std::basic_string<ChDst> StrConvert(const std::basic_string<ChSrc>& src)
|
||||
{
|
||||
auto converted_size = CharConvert(nullptr, src.c_str(), 0);
|
||||
if (converted_size == (size_t)-1) {
|
||||
return {};
|
||||
}
|
||||
std::basic_string<ChDst> dst(converted_size + 1, {});
|
||||
converted_size = CharConvert(&dst[0], src.c_str(), converted_size + 1);
|
||||
if (converted_size == (size_t)-1) {
|
||||
return {};
|
||||
}
|
||||
return dst.substr(0, dst.size() - 1);
|
||||
}
|
||||
|
||||
static std::basic_string<wchar_t> StrConvert(const wchar_t *src) {
|
||||
return src;
|
||||
}
|
||||
static std::basic_string<wchar_t> StrConvert(const char* src) {
|
||||
return StrConvert<char, wchar_t>(std::basic_string<char>(src));
|
||||
}
|
||||
|
||||
static std::string getenv(const char * name)
|
||||
{
|
||||
auto val = ::getenv(name);
|
||||
if(val != nullptr && val[0] != '\0') {
|
||||
return val;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
static std::wstring getenv(const wchar_t* name) {
|
||||
#ifdef GLOG_OS_WINDOWS
|
||||
auto val = ::_wgetenv(name);
|
||||
if(val != nullptr && val[0] != '\0') {
|
||||
return val;
|
||||
}
|
||||
return {};
|
||||
#else
|
||||
auto str_name = StrConvert<wchar_t, char>(name);
|
||||
auto str_val = getenv(str_name.c_str());
|
||||
return StrConvert<char, wchar_t>(str_val);
|
||||
#endif // GLOG_OS_WINDOWS
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace logging
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user