diff --git a/.gitignore b/.gitignore index 0b691d05733497faca9bcc9b683e9afe47db0155..dabb65654d753a27f0b4f787d68870f016017c45 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ build/ Debug/ -!/Release Release/ SOCKET_Debug/ SOCKET_Release/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6800bf0c78e3d7fe14358c2a49626f536edfe0e8..fcb600d1d973dde1651cb449f0a283d5fd52c2c1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,5 +25,6 @@ exclude: | (?x)^( .*?_i\.h| .*?_p\.c| - .*?\.md + .*?\.md | + 3rdparty\* ) diff --git a/DWeChatRobot/base64/README.md b/3rdparty/include/base64/README.md similarity index 100% rename from DWeChatRobot/base64/README.md rename to 3rdparty/include/base64/README.md diff --git a/DWeChatRobot/base64/base64.cpp b/3rdparty/include/base64/base64.cpp similarity index 100% rename from DWeChatRobot/base64/base64.cpp rename to 3rdparty/include/base64/base64.cpp diff --git a/DWeChatRobot/base64/base64.h b/3rdparty/include/base64/base64.h similarity index 100% rename from DWeChatRobot/base64/base64.h rename to 3rdparty/include/base64/base64.h diff --git a/DWeChatRobot/base64/pch.h b/3rdparty/include/base64/pch.h similarity index 100% rename from DWeChatRobot/base64/pch.h rename to 3rdparty/include/base64/pch.h diff --git a/3rdparty/include/glog/export.h b/3rdparty/include/glog/export.h new file mode 100644 index 0000000000000000000000000000000000000000..cc50a1f0e58b6d0102c8e2bc4a9a77e844099ef9 --- /dev/null +++ b/3rdparty/include/glog/export.h @@ -0,0 +1,42 @@ + +#ifndef GLOG_EXPORT_H +#define GLOG_EXPORT_H + +#ifdef GLOG_STATIC_DEFINE +#define GLOG_EXPORT +#define GLOG_NO_EXPORT +#else +#ifndef GLOG_EXPORT +#ifdef GOOGLE_GLOG_IS_A_DLL +/* We are building this library */ +#define GLOG_EXPORT +#else +/* We are using this library */ +#define GLOG_EXPORT +#endif +#endif + +#ifndef GLOG_NO_EXPORT +#define GLOG_NO_EXPORT +#endif +#endif + +#ifndef GLOG_DEPRECATED +#define GLOG_DEPRECATED __declspec(deprecated) +#endif + +#ifndef GLOG_DEPRECATED_EXPORT +#define GLOG_DEPRECATED_EXPORT GLOG_EXPORT GLOG_DEPRECATED +#endif + +#ifndef GLOG_DEPRECATED_NO_EXPORT +#define GLOG_DEPRECATED_NO_EXPORT GLOG_NO_EXPORT GLOG_DEPRECATED +#endif + +#if 0 /* DEFINE_NO_DEPRECATED */ +#ifndef GLOG_NO_DEPRECATED +#define GLOG_NO_DEPRECATED +#endif +#endif + +#endif /* GLOG_EXPORT_H */ diff --git a/3rdparty/include/glog/log_severity.h b/3rdparty/include/glog/log_severity.h new file mode 100644 index 0000000000000000000000000000000000000000..0dd3f13ae573477a4bbb02331d138faabb07afb8 --- /dev/null +++ b/3rdparty/include/glog/log_severity.h @@ -0,0 +1,104 @@ +// Copyright (c) 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef BASE_LOG_SEVERITY_H__ +#define BASE_LOG_SEVERITY_H__ + +// The recommended semantics of the log levels are as follows: +// +// INFO: +// Use for state changes or other major events, or to aid debugging. +// WARNING: +// Use for undesired but relatively expected events, which may indicate a +// problem +// ERROR: +// Use for undesired and unexpected events that the program can recover from. +// All ERRORs should be actionable - it should be appropriate to file a bug +// whenever an ERROR occurs in production. +// FATAL: +// Use for undesired and unexpected events that the program cannot recover +// from. + +// Variables of type LogSeverity are widely taken to lie in the range +// [0, NUM_SEVERITIES-1]. Be careful to preserve this assumption if +// you ever need to change their values or add a new severity. +typedef int LogSeverity; + +const int GLOG_INFO = 0, GLOG_WARNING = 1, GLOG_ERROR = 2, GLOG_FATAL = 3, + NUM_SEVERITIES = 4; +#ifndef GLOG_NO_ABBREVIATED_SEVERITIES +#ifdef ERROR +#error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail. +#endif +const int INFO = GLOG_INFO, WARNING = GLOG_WARNING, + ERROR = GLOG_ERROR, FATAL = GLOG_FATAL; +#endif + +// DFATAL is FATAL in debug mode, ERROR in normal mode +#ifdef NDEBUG +#define DFATAL_LEVEL ERROR +#else +#define DFATAL_LEVEL FATAL +#endif + +extern GLOG_EXPORT const char *const LogSeverityNames[NUM_SEVERITIES]; + +// NDEBUG usage helpers related to (RAW_)DCHECK: +// +// DEBUG_MODE is for small !NDEBUG uses like +// if (DEBUG_MODE) foo.CheckThatFoo(); +// instead of substantially more verbose +// #ifndef NDEBUG +// foo.CheckThatFoo(); +// #endif +// +// IF_DEBUG_MODE is for small !NDEBUG uses like +// IF_DEBUG_MODE( string error; ) +// DCHECK(Foo(&error)) << error; +// instead of substantially more verbose +// #ifndef NDEBUG +// string error; +// DCHECK(Foo(&error)) << error; +// #endif +// +#ifdef NDEBUG +enum +{ + DEBUG_MODE = 0 +}; +#define IF_DEBUG_MODE(x) +#else +enum +{ + DEBUG_MODE = 1 +}; +#define IF_DEBUG_MODE(x) x +#endif + +#endif // BASE_LOG_SEVERITY_H__ diff --git a/3rdparty/include/glog/logging.h b/3rdparty/include/glog/logging.h new file mode 100644 index 0000000000000000000000000000000000000000..d15603459a664d195b5a01a734bbdc1466707532 --- /dev/null +++ b/3rdparty/include/glog/logging.h @@ -0,0 +1,2101 @@ +// Copyright (c) 2022, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Ray Sidney +// +// This file contains #include information about logging-related stuff. +// Pretty much everybody needs to #include this file so that they can +// log various happenings. +// +#ifndef GLOG_LOGGING_H +#define GLOG_LOGGING_H + +#if 1 && __cplusplus >= 201103L +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if 0 +#include +#endif +#include + +#if defined(_MSC_VER) +#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \ + __pragma(warning(disable \ + : n)) +#define GLOG_MSVC_POP_WARNING() __pragma(warning(pop)) +#else +#define GLOG_MSVC_PUSH_DISABLE_WARNING(n) +#define GLOG_MSVC_POP_WARNING() +#endif + +#include + +#if 1 +#include +#endif + +// We care a lot about number of bits things take up. Unfortunately, +// systems define their bit-specific ints in a lot of different ways. +// We use our own way, and have a typedef to get there. +// Note: these commands below may look like "#if 1" or "#if 0", but +// that's because they were constructed that way at ./configure time. +// Look at logging.h.in to see how they're calculated (based on your config). +#if 1 +#include // the normal place uint16_t is defined +#endif +#if 1 +#include // the normal place u_int16_t is defined +#endif +#if 1 +#include // a third place for uint16_t or u_int16_t +#endif + +#if 0 +#include +#endif + +#if 1 && __cplusplus >= 201103L +#include +#elif defined(GLOG_OS_WINDOWS) +#include +#endif + +namespace google +{ + +#if 1 // the C99 format + typedef int32_t int32; + typedef uint32_t uint32; + typedef int64_t int64; + typedef uint64_t uint64; +#elif 0 // the BSD format + typedef int32_t int32; + typedef u_int32_t uint32; + typedef int64_t int64; + typedef u_int64_t uint64; +#elif 1 // the windows (vc7) format + typedef __int32 int32; + typedef unsigned __int32 uint32; + typedef __int64 int64; + typedef unsigned __int64 uint64; +#else +#error Do not know how to define a 32-bit integer quantity on your system +#endif + +#if !(0) + typedef ptrdiff_t ssize_t; +#endif + +#if !(0) + typedef int mode_t; +#endif + + typedef double WallTime; + + struct GLOG_EXPORT LogMessageTime + { + LogMessageTime(); + LogMessageTime(std::tm t); + LogMessageTime(std::time_t timestamp, WallTime now); + + const time_t ×tamp() const { return timestamp_; } + const int &sec() const { return time_struct_.tm_sec; } + const int32_t &usec() const { return usecs_; } + const int &(min)() const { return time_struct_.tm_min; } + const int &hour() const { return time_struct_.tm_hour; } + const int &day() const { return time_struct_.tm_mday; } + const int &month() const { return time_struct_.tm_mon; } + const int &year() const { return time_struct_.tm_year; } + const int &dayOfWeek() const { return time_struct_.tm_wday; } + const int &dayInYear() const { return time_struct_.tm_yday; } + const int &dst() const { return time_struct_.tm_isdst; } + const long int &gmtoff() const { return gmtoffset_; } + const std::tm &tm() const { return time_struct_; } + + private: + void init(const std::tm &t, std::time_t timestamp, WallTime now); + std::tm time_struct_; // Time of creation of LogMessage + time_t timestamp_; // Time of creation of LogMessage in seconds + int32_t usecs_; // Time of creation of LogMessage - microseconds part + long int gmtoffset_; + + void CalcGmtOffset(); + }; + +#ifdef GLOG_CUSTOM_PREFIX_SUPPORT + struct LogMessageInfo + { + explicit LogMessageInfo(const char *const severity_, + const char *const filename_, + const int &line_number_, + const int &thread_id_, + const LogMessageTime &time_) : severity(severity_), filename(filename_), line_number(line_number_), + thread_id(thread_id_), time(time_) + { + } + + const char *const severity; + const char *const filename; + const int &line_number; + const int &thread_id; + const LogMessageTime &time; + }; + + typedef void (*CustomPrefixCallback)(std::ostream &s, const LogMessageInfo &l, void *data); + +#endif + +} + +// The global value of GOOGLE_STRIP_LOG. All the messages logged to +// LOG(XXX) with severity less than GOOGLE_STRIP_LOG will not be displayed. +// If it can be determined at compile time that the message will not be +// printed, the statement will be compiled out. +// +// Example: to strip out all INFO and WARNING messages, use the value +// of 2 below. To make an exception for WARNING messages from a single +// file, add "#define GOOGLE_STRIP_LOG 1" to that file _before_ including +// base/logging.h +#ifndef GOOGLE_STRIP_LOG +#define GOOGLE_STRIP_LOG 0 +#endif + +// GCC can be told that a certain branch is not likely to be taken (for +// instance, a CHECK failure), and use that information in static analysis. +// Giving it this information can help it optimize for the common case in +// the absence of better information (ie. -fprofile-arcs). +// +#ifndef GOOGLE_PREDICT_BRANCH_NOT_TAKEN +#if 0 +#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) (__builtin_expect(x, 0)) +#else +#define GOOGLE_PREDICT_BRANCH_NOT_TAKEN(x) x +#endif +#endif + +#ifndef GOOGLE_PREDICT_FALSE +#if 0 +#define GOOGLE_PREDICT_FALSE(x) (__builtin_expect(x, 0)) +#else +#define GOOGLE_PREDICT_FALSE(x) x +#endif +#endif + +#ifndef GOOGLE_PREDICT_TRUE +#if 0 +#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) +#else +#define GOOGLE_PREDICT_TRUE(x) x +#endif +#endif + +// Make a bunch of macros for logging. The way to log things is to stream +// things to LOG(). E.g., +// +// LOG(INFO) << "Found " << num_cookies << " cookies"; +// +// You can capture log messages in a string, rather than reporting them +// immediately: +// +// vector errors; +// LOG_STRING(ERROR, &errors) << "Couldn't parse cookie #" << cookie_num; +// +// This pushes back the new error onto 'errors'; if given a NULL pointer, +// it reports the error via LOG(ERROR). +// +// You can also do conditional logging: +// +// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; +// +// You can also do occasional logging (log every n'th occurrence of an +// event): +// +// LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie"; +// +// The above will cause log messages to be output on the 1st, 11th, 21st, ... +// times it is executed. Note that the special google::COUNTER value is used +// to identify which repetition is happening. +// +// You can also do occasional conditional logging (log every n'th +// occurrence of an event, when condition is satisfied): +// +// LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER +// << "th big cookie"; +// +// You can log messages the first N times your code executes a line. E.g. +// +// LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie"; +// +// Outputs log messages for the first 20 times it is executed. +// +// Analogous SYSLOG, SYSLOG_IF, and SYSLOG_EVERY_N macros are available. +// These log to syslog as well as to the normal logs. If you use these at +// all, you need to be aware that syslog can drastically reduce performance, +// especially if it is configured for remote logging! Don't use these +// unless you fully understand this and have a concrete need to use them. +// Even then, try to minimize your use of them. +// +// There are also "debug mode" logging macros like the ones above: +// +// DLOG(INFO) << "Found cookies"; +// +// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies"; +// +// DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie"; +// +// All "debug mode" logging is compiled away to nothing for non-debug mode +// compiles. +// +// We also have +// +// LOG_ASSERT(assertion); +// DLOG_ASSERT(assertion); +// +// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion; +// +// There are "verbose level" logging macros. They look like +// +// VLOG(1) << "I'm printed when you run the program with --v=1 or more"; +// VLOG(2) << "I'm printed when you run the program with --v=2 or more"; +// +// These always log at the INFO log level (when they log at all). +// The verbose logging can also be turned on module-by-module. For instance, +// --vmodule=mapreduce=2,file=1,gfs*=3 --v=0 +// will cause: +// a. VLOG(2) and lower messages to be printed from mapreduce.{h,cc} +// b. VLOG(1) and lower messages to be printed from file.{h,cc} +// c. VLOG(3) and lower messages to be printed from files prefixed with "gfs" +// d. VLOG(0) and lower messages to be printed from elsewhere +// +// The wildcarding functionality shown by (c) supports both '*' (match +// 0 or more characters) and '?' (match any single character) wildcards. +// +// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as +// +// if (VLOG_IS_ON(2)) { +// // do some logging preparation and logging +// // that can't be accomplished with just VLOG(2) << ...; +// } +// +// There are also VLOG_IF, VLOG_EVERY_N and VLOG_IF_EVERY_N "verbose level" +// condition macros for sample cases, when some extra computation and +// preparation for logs is not needed. +// VLOG_IF(1, (size > 1024)) +// << "I'm printed when size is more than 1024 and when you run the " +// "program with --v=1 or more"; +// VLOG_EVERY_N(1, 10) +// << "I'm printed every 10th occurrence, and when you run the program " +// "with --v=1 or more. Present occurence is " << google::COUNTER; +// VLOG_IF_EVERY_N(1, (size > 1024), 10) +// << "I'm printed on every 10th occurence of case when size is more " +// " than 1024, when you run the program with --v=1 or more. "; +// "Present occurence is " << google::COUNTER; +// +// The supported severity levels for macros that allow you to specify one +// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL. +// Note that messages of a given severity are logged not only in the +// logfile for that severity, but also in all logfiles of lower severity. +// E.g., a message of severity FATAL will be logged to the logfiles of +// severity FATAL, ERROR, WARNING, and INFO. +// +// There is also the special severity of DFATAL, which logs FATAL in +// debug mode, ERROR in normal mode. +// +// Very important: logging a message at the FATAL severity level causes +// the program to terminate (after the message is logged). +// +// Unless otherwise specified, logs will be written to the filename +// "...log..", followed +// by the date, time, and pid (you can't prevent the date, time, and pid +// from being in the filename). +// +// The logging code takes two flags: +// --v=# set the verbose level +// --logtostderr log all the messages to stderr instead of to logfiles + +// LOG LINE PREFIX FORMAT +// +// Log lines have this form: +// +// Lyyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg... +// +// where the fields are defined as follows: +// +// L A single character, representing the log level +// (eg 'I' for INFO) +// yyyy The year +// mm The month (zero padded; ie May is '05') +// dd The day (zero padded) +// hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds +// threadid The space-padded thread ID as returned by GetTID() +// (this matches the PID on Linux) +// file The file name +// line The line number +// msg The user-supplied message +// +// Example: +// +// I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog +// I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395 +// +// NOTE: although the microseconds are useful for comparing events on +// a single machine, clocks on different machines may not be well +// synchronized. Hence, use caution when comparing the low bits of +// timestamps from different machines. + +#pragma push_macro("DECLARE_VARIABLE") +#pragma push_macro("DECLARE_bool") +#pragma push_macro("DECLARE_string") +#pragma push_macro("DECLARE_int32") +#pragma push_macro("DECLARE_uint32") + +#ifdef DECLARE_VARIABLE +#undef DECLARE_VARIABLE +#endif + +#ifdef DECLARE_bool +#undef DECLARE_bool +#endif + +#ifdef DECLARE_string +#undef DECLARE_string +#endif + +#ifdef DECLARE_int32 +#undef DECLARE_int32 +#endif + +#ifdef DECLARE_uint32 +#undef DECLARE_uint32 +#endif + +#ifndef DECLARE_VARIABLE +#define DECLARE_VARIABLE(type, shorttype, name, tn) \ + namespace fL##shorttype \ + { \ + extern GLOG_EXPORT type FLAGS_##name; \ + } \ + using fL##shorttype::FLAGS_##name + +// bool specialization +#define DECLARE_bool(name) \ + DECLARE_VARIABLE(bool, B, name, bool) + +// int32 specialization +#define DECLARE_int32(name) \ + DECLARE_VARIABLE(google::int32, I, name, int32) + +#if !defined(DECLARE_uint32) +// uint32 specialization +#define DECLARE_uint32(name) \ + DECLARE_VARIABLE(google::uint32, U, name, uint32) +#endif // !defined(DECLARE_uint32) && !(0) + +// Special case for string, because we have to specify the namespace +// std::string, which doesn't play nicely with our FLAG__namespace hackery. +#define DECLARE_string(name) \ + namespace fLS \ + { \ + extern GLOG_EXPORT std::string &FLAGS_##name; \ + } \ + using fLS::FLAGS_##name +#endif + +// Set whether appending a timestamp to the log file name +DECLARE_bool(timestamp_in_logfile_name); + +// Set whether log messages go to stdout instead of logfiles +DECLARE_bool(logtostdout); + +// Set color messages logged to stdout (if supported by terminal). +DECLARE_bool(colorlogtostdout); + +// Set whether log messages go to stderr instead of logfiles +DECLARE_bool(logtostderr); + +// Set whether log messages go to stderr in addition to logfiles. +DECLARE_bool(alsologtostderr); + +// Set color messages logged to stderr (if supported by terminal). +DECLARE_bool(colorlogtostderr); + +// Log messages at a level >= this flag are automatically sent to +// stderr in addition to log files. +DECLARE_int32(stderrthreshold); + +// Set whether the log file header should be written upon creating a file. +DECLARE_bool(log_file_header); + +// Set whether the log prefix should be prepended to each line of output. +DECLARE_bool(log_prefix); + +// Set whether the year should be included in the log prefix. +DECLARE_bool(log_year_in_prefix); + +// Log messages at a level <= this flag are buffered. +// Log messages at a higher level are flushed immediately. +DECLARE_int32(logbuflevel); + +// Sets the maximum number of seconds which logs may be buffered for. +DECLARE_int32(logbufsecs); + +// Log suppression level: messages logged at a lower level than this +// are suppressed. +DECLARE_int32(minloglevel); + +// If specified, logfiles are written into this directory instead of the +// default logging directory. +DECLARE_string(log_dir); + +// Set the log file mode. +DECLARE_int32(logfile_mode); + +// Sets the path of the directory into which to put additional links +// to the log files. +DECLARE_string(log_link); + +DECLARE_int32(v); // in vlog_is_on.cc + +DECLARE_string(vmodule); // also in vlog_is_on.cc + +// Sets the maximum log file size (in MB). +DECLARE_uint32(max_log_size); + +// Sets whether to avoid logging to the disk if the disk is full. +DECLARE_bool(stop_logging_if_full_disk); + +// Use UTC time for logging +DECLARE_bool(log_utc_time); + +// Log messages below the GOOGLE_STRIP_LOG level will be compiled away for +// security reasons. See LOG(severtiy) below. + +// A few definitions of macros that don't generate much code. Since +// LOG(INFO) and its ilk are used all over our code, it's +// better to have compact code for these operations. + +#if GOOGLE_STRIP_LOG == 0 +#define COMPACT_GOOGLE_LOG_INFO google::LogMessage( \ + __FILE__, __LINE__) +#define LOG_TO_STRING_INFO(message) google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_INFO, message) +#else +#define COMPACT_GOOGLE_LOG_INFO google::NullStream() +#define LOG_TO_STRING_INFO(message) google::NullStream() +#endif + +#if GOOGLE_STRIP_LOG <= 1 +#define COMPACT_GOOGLE_LOG_WARNING google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_WARNING) +#define LOG_TO_STRING_WARNING(message) google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_WARNING, message) +#else +#define COMPACT_GOOGLE_LOG_WARNING google::NullStream() +#define LOG_TO_STRING_WARNING(message) google::NullStream() +#endif + +#if GOOGLE_STRIP_LOG <= 2 +#define COMPACT_GOOGLE_LOG_ERROR google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_ERROR) +#define LOG_TO_STRING_ERROR(message) google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_ERROR, message) +#else +#define COMPACT_GOOGLE_LOG_ERROR google::NullStream() +#define LOG_TO_STRING_ERROR(message) google::NullStream() +#endif + +#if GOOGLE_STRIP_LOG <= 3 +#define COMPACT_GOOGLE_LOG_FATAL google::LogMessageFatal( \ + __FILE__, __LINE__) +#define LOG_TO_STRING_FATAL(message) google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_FATAL, message) +#else +#define COMPACT_GOOGLE_LOG_FATAL google::NullStreamFatal() +#define LOG_TO_STRING_FATAL(message) google::NullStreamFatal() +#endif + +#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) +#define DCHECK_IS_ON() 0 +#else +#define DCHECK_IS_ON() 1 +#endif + +// For DFATAL, we want to use LogMessage (as opposed to +// LogMessageFatal), to be consistent with the original behavior. +#if !DCHECK_IS_ON() +#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR +#elif GOOGLE_STRIP_LOG <= 3 +#define COMPACT_GOOGLE_LOG_DFATAL google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_FATAL) +#else +#define COMPACT_GOOGLE_LOG_DFATAL google::NullStreamFatal() +#endif + +#define GOOGLE_LOG_INFO(counter) google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, &google::LogMessage::SendToLog) +#define SYSLOG_INFO(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO, counter, \ + &google::LogMessage::SendToSyslogAndLog) +#define GOOGLE_LOG_WARNING(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \ + &google::LogMessage::SendToLog) +#define SYSLOG_WARNING(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_WARNING, counter, \ + &google::LogMessage::SendToSyslogAndLog) +#define GOOGLE_LOG_ERROR(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \ + &google::LogMessage::SendToLog) +#define SYSLOG_ERROR(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, counter, \ + &google::LogMessage::SendToSyslogAndLog) +#define GOOGLE_LOG_FATAL(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \ + &google::LogMessage::SendToLog) +#define SYSLOG_FATAL(counter) \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_FATAL, counter, \ + &google::LogMessage::SendToSyslogAndLog) +#define GOOGLE_LOG_DFATAL(counter) \ + google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \ + &google::LogMessage::SendToLog) +#define SYSLOG_DFATAL(counter) \ + google::LogMessage(__FILE__, __LINE__, google::DFATAL_LEVEL, counter, \ + &google::LogMessage::SendToSyslogAndLog) + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || defined(__CYGWIN32__) +// A very useful logging macro to log windows errors: +#define LOG_SYSRESULT(result) \ + if (FAILED(HRESULT_FROM_WIN32(result))) \ + { \ + LPSTR message = NULL; \ + LPSTR msg = reinterpret_cast(&message); \ + DWORD message_length = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | \ + FORMAT_MESSAGE_FROM_SYSTEM | \ + FORMAT_MESSAGE_IGNORE_INSERTS, \ + 0, result, 0, msg, 100, NULL); \ + if (message_length > 0) \ + { \ + google::LogMessage(__FILE__, __LINE__, google::GLOG_ERROR, 0, \ + &google::LogMessage::SendToLog) \ + .stream() \ + << reinterpret_cast(message); \ + LocalFree(message); \ + } \ + } +#endif + +// We use the preprocessor's merging operator, "##", so that, e.g., +// LOG(INFO) becomes the token GOOGLE_LOG_INFO. There's some funny +// subtle difference between ostream member streaming functions (e.g., +// ostream::operator<<(int) and ostream non-member streaming functions +// (e.g., ::operator<<(ostream&, string&): it turns out that it's +// impossible to stream something like a string directly to an unnamed +// ostream. We employ a neat hack by calling the stream() member +// function of LogMessage which seems to avoid the problem. +#define LOG(severity) COMPACT_GOOGLE_LOG_##severity.stream() +#define SYSLOG(severity) SYSLOG_##severity(0).stream() + +namespace google +{ + +// They need the definitions of integer types. +#include +#include + + // Initialize google's logging library. You will see the program name + // specified by argv0 in log outputs. + GLOG_EXPORT void InitGoogleLogging(const char *argv0); + +#ifdef GLOG_CUSTOM_PREFIX_SUPPORT + GLOG_EXPORT void InitGoogleLogging(const char *argv0, + CustomPrefixCallback prefix_callback, + void *prefix_callback_data = NULL); +#endif + + // Check if google's logging library has been initialized. + GLOG_EXPORT bool IsGoogleLoggingInitialized(); + + // Shutdown google's logging library. + GLOG_EXPORT void ShutdownGoogleLogging(); + +#if defined(__GNUC__) + typedef void (*logging_fail_func_t)() __attribute__((noreturn)); +#else + typedef void (*logging_fail_func_t)(); +#endif + + // Install a function which will be called after LOG(FATAL). + GLOG_EXPORT void InstallFailureFunction(logging_fail_func_t fail_func); + + // Enable/Disable old log cleaner. + GLOG_EXPORT void EnableLogCleaner(unsigned int overdue_days); + GLOG_EXPORT void DisableLogCleaner(); + GLOG_EXPORT void SetApplicationFingerprint(const std::string &fingerprint); + + class LogSink; // defined below + +// If a non-NULL sink pointer is given, we push this message to that sink. +// For LOG_TO_SINK we then do normal LOG(severity) logging as well. +// This is useful for capturing messages and passing/storing them +// somewhere more specific than the global log of the process. +// Argument types: +// LogSink* sink; +// LogSeverity severity; +// The cast is to disambiguate NULL arguments. +#define LOG_TO_SINK(sink, severity) \ + google::LogMessage( \ + __FILE__, __LINE__, \ + google::GLOG_##severity, \ + static_cast(sink), true) \ + .stream() +#define LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity) \ + google::LogMessage( \ + __FILE__, __LINE__, \ + google::GLOG_##severity, \ + static_cast(sink), false) \ + .stream() + +// If a non-NULL string pointer is given, we write this message to that string. +// We then do normal LOG(severity) logging as well. +// This is useful for capturing messages and storing them somewhere more +// specific than the global log of the process. +// Argument types: +// string* message; +// LogSeverity severity; +// The cast is to disambiguate NULL arguments. +// NOTE: LOG(severity) expands to LogMessage().stream() for the specified +// severity. +#define LOG_TO_STRING(severity, message) \ + LOG_TO_STRING_##severity(static_cast(message)).stream() + +// If a non-NULL pointer is given, we push the message onto the end +// of a vector of strings; otherwise, we report it with LOG(severity). +// This is handy for capturing messages and perhaps passing them back +// to the caller, rather than reporting them immediately. +// Argument types: +// LogSeverity severity; +// vector *outvec; +// The cast is to disambiguate NULL arguments. +#define LOG_STRING(severity, outvec) \ + LOG_TO_STRING_##severity(static_cast *>(outvec)).stream() + +#define LOG_IF(severity, condition) \ + static_cast(0), \ + !(condition) ? (void)0 : google::LogMessageVoidify() & LOG(severity) +#define SYSLOG_IF(severity, condition) \ + static_cast(0), \ + !(condition) ? (void)0 : google::LogMessageVoidify() & SYSLOG(severity) + +#define LOG_ASSERT(condition) \ + LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition +#define SYSLOG_ASSERT(condition) \ + SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition + +// CHECK dies with a fatal error if condition is not true. It is *not* +// controlled by DCHECK_IS_ON(), so the check will be executed regardless of +// compilation mode. Therefore, it is safe to do things like: +// CHECK(fp->Write(x) == 4) +#define CHECK(condition) \ + LOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \ + << "Check failed: " #condition " " + + // A container for a string pointer which can be evaluated to a bool - + // true iff the pointer is NULL. + struct CheckOpString + { + CheckOpString(std::string *str) : str_(str) {} + // No destructor: if str_ is non-NULL, we're about to LOG(FATAL), + // so there's no point in cleaning up str_. + operator bool() const + { + return GOOGLE_PREDICT_BRANCH_NOT_TAKEN(str_ != NULL); + } + std::string *str_; + }; + + // Function is overloaded for integral types to allow static const + // integrals declared in classes and not defined to be used as arguments to + // CHECK* macros. It's not encouraged though. + template + inline const T &GetReferenceableValue(const T &t) { return t; } + inline char GetReferenceableValue(char t) { return t; } + inline unsigned char GetReferenceableValue(unsigned char t) { return t; } + inline signed char GetReferenceableValue(signed char t) { return t; } + inline short GetReferenceableValue(short t) { return t; } + inline unsigned short GetReferenceableValue(unsigned short t) { return t; } + inline int GetReferenceableValue(int t) { return t; } + inline unsigned int GetReferenceableValue(unsigned int t) { return t; } + inline long GetReferenceableValue(long t) { return t; } + inline unsigned long GetReferenceableValue(unsigned long t) { return t; } +#if __cplusplus >= 201103L + inline long long GetReferenceableValue(long long t) + { + return t; + } + inline unsigned long long GetReferenceableValue(unsigned long long t) + { + return t; + } +#endif + + // This is a dummy class to define the following operator. + struct DummyClassToDefineOperator + { + }; + +} + +// Define global operator<< to declare using ::operator<<. +// This declaration will allow use to use CHECK macros for user +// defined classes which have operator<< (e.g., stl_logging.h). +inline std::ostream &operator<<( + std::ostream &out, const google::DummyClassToDefineOperator &) +{ + return out; +} + +namespace google +{ + + // This formats a value for a failing CHECK_XX statement. Ordinarily, + // it uses the definition for operator<<, with a few special cases below. + template + inline void MakeCheckOpValueString(std::ostream *os, const T &v) + { + (*os) << v; + } + + // Overrides for char types provide readable values for unprintable + // characters. + template <> + GLOG_EXPORT void MakeCheckOpValueString(std::ostream *os, const char &v); + template <> + GLOG_EXPORT void MakeCheckOpValueString(std::ostream *os, const signed char &v); + template <> + GLOG_EXPORT void MakeCheckOpValueString(std::ostream *os, const unsigned char &v); + +// This is required because nullptr is only present in c++ 11 and later. +#if 1 && __cplusplus >= 201103L + // Provide printable value for nullptr_t + template <> + GLOG_EXPORT void MakeCheckOpValueString(std::ostream *os, const std::nullptr_t &v); +#endif + + // Build the error message string. Specify no inlining for code size. + template + std::string *MakeCheckOpString(const T1 &v1, const T2 &v2, const char *exprtext); + + namespace base + { + namespace internal + { + + // If "s" is less than base_logging::INFO, returns base_logging::INFO. + // If "s" is greater than base_logging::FATAL, returns + // base_logging::ERROR. Otherwise, returns "s". + LogSeverity NormalizeSeverity(LogSeverity s); + + } // namespace internal + + // A helper class for formatting "expr (V1 vs. V2)" in a CHECK_XX + // statement. See MakeCheckOpString for sample usage. Other + // approaches were considered: use of a template method (e.g., + // base::BuildCheckOpString(exprtext, base::Print, &v1, + // base::Print, &v2), however this approach has complications + // related to volatile arguments and function-pointer arguments). + class GLOG_EXPORT CheckOpMessageBuilder + { + public: + // Inserts "exprtext" and " (" to the stream. + explicit CheckOpMessageBuilder(const char *exprtext); + // Deletes "stream_". + ~CheckOpMessageBuilder(); + // For inserting the first variable. + std::ostream *ForVar1() { return stream_; } + // For inserting the second variable (adds an intermediate " vs. "). + std::ostream *ForVar2(); + // Get the result (inserts the closing ")"). + std::string *NewString(); + + private: + std::ostringstream *stream_; + }; + + } // namespace base + + template + std::string *MakeCheckOpString(const T1 &v1, const T2 &v2, const char *exprtext) + { + base::CheckOpMessageBuilder comb(exprtext); + MakeCheckOpValueString(comb.ForVar1(), v1); + MakeCheckOpValueString(comb.ForVar2(), v2); + return comb.NewString(); + } + +// Helper functions for CHECK_OP macro. +// The (int, int) specialization works around the issue that the compiler +// will not instantiate the template version of the function on values of +// unnamed enum type - see comment below. +#define DEFINE_CHECK_OP_IMPL(name, op) \ + template \ + inline std::string *name##Impl(const T1 &v1, const T2 &v2, \ + const char *exprtext) \ + { \ + if (GOOGLE_PREDICT_TRUE(v1 op v2)) \ + return NULL; \ + else \ + return MakeCheckOpString(v1, v2, exprtext); \ + } \ + inline std::string *name##Impl(int v1, int v2, const char *exprtext) \ + { \ + return name##Impl(v1, v2, exprtext); \ + } + + // We use the full name Check_EQ, Check_NE, etc. in case the file including + // base/logging.h provides its own #defines for the simpler names EQ, NE, etc. + // This happens if, for example, those are used as token names in a + // yacc grammar. + DEFINE_CHECK_OP_IMPL(Check_EQ, ==) // Compilation error with CHECK_EQ(NULL, x)? + DEFINE_CHECK_OP_IMPL(Check_NE, !=) // Use CHECK(x == NULL) instead. + DEFINE_CHECK_OP_IMPL(Check_LE, <=) + DEFINE_CHECK_OP_IMPL(Check_LT, <) + DEFINE_CHECK_OP_IMPL(Check_GE, >=) + DEFINE_CHECK_OP_IMPL(Check_GT, >) +#undef DEFINE_CHECK_OP_IMPL + + // Helper macro for binary operators. + // Don't use this macro directly in your code, use CHECK_EQ et al below. + +#if defined(STATIC_ANALYSIS) +// Only for static analysis tool to know that it is equivalent to assert +#define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1)op(val2)) +#elif DCHECK_IS_ON() + // In debug mode, avoid constructing CheckOpStrings if possible, + // to reduce the overhead of CHECK statments by 2x. + // Real DCHECK-heavy tests have seen 1.5x speedups. + + // The meaning of "string" might be different between now and + // when this macro gets invoked (e.g., if someone is experimenting + // with other string implementations that get defined after this + // file is included). Save the current meaning now and use it + // in the macro. + typedef std::string _Check_string; +#define CHECK_OP_LOG(name, op, val1, val2, log) \ + while (google::_Check_string *_result = \ + google::Check##name##Impl( \ + google::GetReferenceableValue(val1), \ + google::GetReferenceableValue(val2), \ + #val1 " " #op " " #val2)) \ + log(__FILE__, __LINE__, \ + google::CheckOpString(_result)) \ + .stream() +#else +// In optimized mode, use CheckOpString to hint to compiler that +// the while condition is unlikely. +#define CHECK_OP_LOG(name, op, val1, val2, log) \ + while (google::CheckOpString _result = \ + google::Check##name##Impl( \ + google::GetReferenceableValue(val1), \ + google::GetReferenceableValue(val2), \ + #val1 " " #op " " #val2)) \ + log(__FILE__, __LINE__, _result).stream() +#endif // STATIC_ANALYSIS, DCHECK_IS_ON() + +#if GOOGLE_STRIP_LOG <= 3 +#define CHECK_OP(name, op, val1, val2) \ + CHECK_OP_LOG(name, op, val1, val2, google::LogMessageFatal) +#else +#define CHECK_OP(name, op, val1, val2) \ + CHECK_OP_LOG(name, op, val1, val2, google::NullStreamFatal) +#endif // STRIP_LOG <= 3 + + // Equality/Inequality checks - compare two values, and log a FATAL message + // including the two values when the result is not as expected. The values + // must have operator<<(ostream, ...) defined. + // + // You may append to the error message like so: + // CHECK_NE(1, 2) << ": The world must be ending!"; + // + // We are very careful to ensure that each argument is evaluated exactly + // once, and that anything which is legal to pass as a function argument is + // legal here. In particular, the arguments may be temporary expressions + // which will end up being destroyed at the end of the apparent statement, + // for example: + // CHECK_EQ(string("abc")[1], 'b'); + // + // WARNING: These don't compile correctly if one of the arguments is a pointer + // and the other is NULL. To work around this, simply static_cast NULL to the + // type of the desired pointer. + +#define CHECK_EQ(val1, val2) CHECK_OP(_EQ, ==, val1, val2) +#define CHECK_NE(val1, val2) CHECK_OP(_NE, !=, val1, val2) +#define CHECK_LE(val1, val2) CHECK_OP(_LE, <=, val1, val2) +#define CHECK_LT(val1, val2) CHECK_OP(_LT, <, val1, val2) +#define CHECK_GE(val1, val2) CHECK_OP(_GE, >=, val1, val2) +#define CHECK_GT(val1, val2) CHECK_OP(_GT, >, val1, val2) + + // Check that the input is non NULL. This very useful in constructor + // initializer lists. + +#define CHECK_NOTNULL(val) \ + google::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val)) + +// Helper functions for string comparisons. +// To avoid bloat, the definitions are in logging.cc. +#define DECLARE_CHECK_STROP_IMPL(func, expected) \ + GLOG_EXPORT std::string *Check##func##expected##Impl( \ + const char *s1, const char *s2, const char *names); + DECLARE_CHECK_STROP_IMPL(strcmp, true) + DECLARE_CHECK_STROP_IMPL(strcmp, false) + DECLARE_CHECK_STROP_IMPL(strcasecmp, true) + DECLARE_CHECK_STROP_IMPL(strcasecmp, false) +#undef DECLARE_CHECK_STROP_IMPL + +// Helper macro for string comparisons. +// Don't use this macro directly in your code, use CHECK_STREQ et al below. +#define CHECK_STROP(func, op, expected, s1, s2) \ + while (google::CheckOpString _result = \ + google::Check##func##expected##Impl((s1), (s2), \ + #s1 " " #op " " #s2)) \ + LOG(FATAL) << *_result.str_ + + // String (char*) equality/inequality checks. + // CASE versions are case-insensitive. + // + // Note that "s1" and "s2" may be temporary strings which are destroyed + // by the compiler at the end of the current "full expression" + // (e.g. CHECK_STREQ(Foo().c_str(), Bar().c_str())). + +#define CHECK_STREQ(s1, s2) CHECK_STROP(strcmp, ==, true, s1, s2) +#define CHECK_STRNE(s1, s2) CHECK_STROP(strcmp, !=, false, s1, s2) +#define CHECK_STRCASEEQ(s1, s2) CHECK_STROP(strcasecmp, ==, true, s1, s2) +#define CHECK_STRCASENE(s1, s2) CHECK_STROP(strcasecmp, !=, false, s1, s2) + +#define CHECK_INDEX(I, A) CHECK(I < (sizeof(A) / sizeof(A[0]))) +#define CHECK_BOUND(B, A) CHECK(B <= (sizeof(A) / sizeof(A[0]))) + +#define CHECK_DOUBLE_EQ(val1, val2) \ + do \ + { \ + CHECK_LE((val1), (val2) + 0.000000000000001L); \ + CHECK_GE((val1), (val2)-0.000000000000001L); \ + } while (0) + +#define CHECK_NEAR(val1, val2, margin) \ + do \ + { \ + CHECK_LE((val1), (val2) + (margin)); \ + CHECK_GE((val1), (val2) - (margin)); \ + } while (0) + + // perror()..googly style! + // + // PLOG() and PLOG_IF() and PCHECK() behave exactly like their LOG* and + // CHECK equivalents with the addition that they postpend a description + // of the current state of errno to their output lines. + +#define PLOG(severity) GOOGLE_PLOG(severity, 0).stream() + +#define GOOGLE_PLOG(severity, counter) \ + google::ErrnoLogMessage( \ + __FILE__, __LINE__, google::GLOG_##severity, counter, \ + &google::LogMessage::SendToLog) + +#define PLOG_IF(severity, condition) \ + static_cast(0), \ + !(condition) ? (void)0 : google::LogMessageVoidify() & PLOG(severity) + +// A CHECK() macro that postpends errno if the condition is false. E.g. +// +// if (poll(fds, nfds, timeout) == -1) { PCHECK(errno == EINTR); ... } +#define PCHECK(condition) \ + PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN(!(condition))) \ + << "Check failed: " #condition " " + +// A CHECK() macro that lets you assert the success of a function that +// returns -1 and sets errno in case of an error. E.g. +// +// CHECK_ERR(mkdir(path, 0700)); +// +// or +// +// int fd = open(filename, flags); CHECK_ERR(fd) << ": open " << filename; +#define CHECK_ERR(invocation) \ + PLOG_IF(FATAL, GOOGLE_PREDICT_BRANCH_NOT_TAKEN((invocation) == -1)) \ + << #invocation + +// Use macro expansion to create, for each use of LOG_EVERY_N(), static +// variables with the __LINE__ expansion as part of the variable name. +#define LOG_EVERY_N_VARNAME(base, line) LOG_EVERY_N_VARNAME_CONCAT(base, line) +#define LOG_EVERY_N_VARNAME_CONCAT(base, line) base##line + +#define LOG_OCCURRENCES LOG_EVERY_N_VARNAME(occurrences_, __LINE__) +#define LOG_OCCURRENCES_MOD_N LOG_EVERY_N_VARNAME(occurrences_mod_n_, __LINE__) + +#if 1 && __cplusplus >= 201103L +#define GLOG_CONSTEXPR constexpr +#else +#define GLOG_CONSTEXPR const +#endif + +#define LOG_TIME_PERIOD LOG_EVERY_N_VARNAME(timePeriod_, __LINE__) +#define LOG_PREVIOUS_TIME_RAW LOG_EVERY_N_VARNAME(previousTimeRaw_, __LINE__) +#define LOG_TIME_DELTA LOG_EVERY_N_VARNAME(deltaTime_, __LINE__) +#define LOG_CURRENT_TIME LOG_EVERY_N_VARNAME(currentTime_, __LINE__) +#define LOG_PREVIOUS_TIME LOG_EVERY_N_VARNAME(previousTime_, __LINE__) + +#if defined(__has_feature) +#if __has_feature(thread_sanitizer) +#define GLOG_SANITIZE_THREAD 1 +#endif +#endif + +#if !defined(GLOG_SANITIZE_THREAD) && defined(__SANITIZE_THREAD__) && __SANITIZE_THREAD__ +#define GLOG_SANITIZE_THREAD 1 +#endif + +#if defined(GLOG_SANITIZE_THREAD) +#define GLOG_IFDEF_THREAD_SANITIZER(X) X +#else +#define GLOG_IFDEF_THREAD_SANITIZER(X) +#endif + +#if defined(GLOG_SANITIZE_THREAD) +} // namespace google + +// We need to identify the static variables as "benign" races +// to avoid noisy reports from TSAN. +extern "C" void AnnotateBenignRaceSized( + const char *file, + int line, + const volatile void *mem, + size_t size, + const char *description); + +namespace google +{ +#endif + +#if __cplusplus >= 201103L && 1 && 1 // Have and +#define SOME_KIND_OF_LOG_EVERY_T(severity, seconds) \ + GLOG_CONSTEXPR std::chrono::nanoseconds LOG_TIME_PERIOD = std::chrono::duration_cast(std::chrono::duration(seconds)); \ + static std::atomic LOG_PREVIOUS_TIME_RAW; \ + GLOG_IFDEF_THREAD_SANITIZER( \ + AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_TIME_PERIOD, sizeof(google::int64), "")); \ + GLOG_IFDEF_THREAD_SANITIZER( \ + AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_PREVIOUS_TIME_RAW, sizeof(google::int64), "")); \ + const auto LOG_CURRENT_TIME = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()); \ + const auto LOG_PREVIOUS_TIME = LOG_PREVIOUS_TIME_RAW.load(std::memory_order_relaxed); \ + const auto LOG_TIME_DELTA = LOG_CURRENT_TIME - std::chrono::nanoseconds(LOG_PREVIOUS_TIME); \ + if (LOG_TIME_DELTA > LOG_TIME_PERIOD) \ + LOG_PREVIOUS_TIME_RAW.store(std::chrono::duration_cast(LOG_CURRENT_TIME).count(), std::memory_order_relaxed); \ + if (LOG_TIME_DELTA > LOG_TIME_PERIOD) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_##severity) \ + .stream() +#elif defined(GLOG_OS_WINDOWS) +#define SOME_KIND_OF_LOG_EVERY_T(severity, seconds) \ + GLOG_CONSTEXPR LONGLONG LOG_TIME_PERIOD = (seconds)*LONGLONG(1000000000); \ + static LARGE_INTEGER LOG_PREVIOUS_TIME; \ + LONGLONG LOG_TIME_DELTA; \ + { \ + LARGE_INTEGER currTime; \ + LARGE_INTEGER freq; \ + QueryPerformanceCounter(&currTime); \ + QueryPerformanceFrequency(&freq); \ + InterlockedCompareExchange64(&LOG_PREVIOUS_TIME.QuadPart, currTime.QuadPart, 0); \ + LOG_TIME_DELTA = (currTime.QuadPart - LOG_PREVIOUS_TIME.QuadPart) * LONGLONG(1000000000) / freq.QuadPart; \ + if (LOG_TIME_DELTA > LOG_TIME_PERIOD) \ + InterlockedExchange64(&LOG_PREVIOUS_TIME.QuadPart, currTime.QuadPart); \ + } \ + if (LOG_TIME_DELTA > LOG_TIME_PERIOD) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_##severity) \ + .stream() +#else +#define SOME_KIND_OF_LOG_EVERY_T(severity, seconds) \ + GLOG_CONSTEXPR google::int64 LOG_TIME_PERIOD(seconds * 1000000000); \ + static google::int64 LOG_PREVIOUS_TIME; \ + google::int64 LOG_TIME_DELTA = 0; \ + { \ + timespec currentTime = {}; \ + clock_gettime(CLOCK_MONOTONIC, ¤tTime); \ + LOG_TIME_DELTA = (currentTime.tv_sec * 1000000000 + currentTime.tv_nsec) - LOG_PREVIOUS_TIME; \ + } \ + if (LOG_TIME_DELTA > LOG_TIME_PERIOD) \ + __sync_add_and_fetch(&LOG_PREVIOUS_TIME, LOG_TIME_DELTA); \ + if (LOG_TIME_DELTA > LOG_TIME_PERIOD) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_##severity) \ + .stream() +#endif + +#if 1 && __cplusplus >= 201103L +#define SOME_KIND_OF_LOG_EVERY_N(severity, n, what_to_do) \ + static std::atomic LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), "")); \ + ++LOG_OCCURRENCES; \ + if (++LOG_OCCURRENCES_MOD_N > n) \ + LOG_OCCURRENCES_MOD_N -= n; \ + if (LOG_OCCURRENCES_MOD_N == 1) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_##severity, LOG_OCCURRENCES, \ + &what_to_do) \ + .stream() + +#define SOME_KIND_OF_LOG_IF_EVERY_N(severity, condition, n, what_to_do) \ + static std::atomic LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), "")); \ + ++LOG_OCCURRENCES; \ + if ((condition) && \ + ((LOG_OCCURRENCES_MOD_N = (LOG_OCCURRENCES_MOD_N + 1) % n) == (1 % n))) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_##severity, LOG_OCCURRENCES, \ + &what_to_do) \ + .stream() + +#define SOME_KIND_OF_PLOG_EVERY_N(severity, n, what_to_do) \ + static std::atomic LOG_OCCURRENCES(0), LOG_OCCURRENCES_MOD_N(0); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES_MOD_N, sizeof(int), "")); \ + ++LOG_OCCURRENCES; \ + if (++LOG_OCCURRENCES_MOD_N > n) \ + LOG_OCCURRENCES_MOD_N -= n; \ + if (LOG_OCCURRENCES_MOD_N == 1) \ + google::ErrnoLogMessage( \ + __FILE__, __LINE__, google::GLOG_##severity, LOG_OCCURRENCES, \ + &what_to_do) \ + .stream() + +#define SOME_KIND_OF_LOG_FIRST_N(severity, n, what_to_do) \ + static std::atomic LOG_OCCURRENCES(0); \ + GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized(__FILE__, __LINE__, &LOG_OCCURRENCES, sizeof(int), "")); \ + if (LOG_OCCURRENCES <= n) \ + ++LOG_OCCURRENCES; \ + if (LOG_OCCURRENCES <= n) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_##severity, LOG_OCCURRENCES, \ + &what_to_do) \ + .stream() + +#elif defined(GLOG_OS_WINDOWS) + +#define SOME_KIND_OF_LOG_EVERY_N(severity, n, what_to_do) \ + static volatile unsigned LOG_OCCURRENCES = 0; \ + static volatile unsigned LOG_OCCURRENCES_MOD_N = 0; \ + InterlockedIncrement(&LOG_OCCURRENCES); \ + if (InterlockedIncrement(&LOG_OCCURRENCES_MOD_N) > n) \ + InterlockedExchangeSubtract(&LOG_OCCURRENCES_MOD_N, n); \ + if (LOG_OCCURRENCES_MOD_N == 1) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_##severity, LOG_OCCURRENCES, \ + &what_to_do) \ + .stream() + +#define SOME_KIND_OF_LOG_IF_EVERY_N(severity, condition, n, what_to_do) \ + static volatile unsigned LOG_OCCURRENCES = 0; \ + static volatile unsigned LOG_OCCURRENCES_MOD_N = 0; \ + InterlockedIncrement(&LOG_OCCURRENCES); \ + if ((condition) && \ + ((InterlockedIncrement(&LOG_OCCURRENCES_MOD_N), \ + (LOG_OCCURRENCES_MOD_N > n && InterlockedExchangeSubtract(&LOG_OCCURRENCES_MOD_N, n))), \ + LOG_OCCURRENCES_MOD_N == 1)) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_##severity, LOG_OCCURRENCES, \ + &what_to_do) \ + .stream() + +#define SOME_KIND_OF_PLOG_EVERY_N(severity, n, what_to_do) \ + static volatile unsigned LOG_OCCURRENCES = 0; \ + static volatile unsigned LOG_OCCURRENCES_MOD_N = 0; \ + InterlockedIncrement(&LOG_OCCURRENCES); \ + if (InterlockedIncrement(&LOG_OCCURRENCES_MOD_N) > n) \ + InterlockedExchangeSubtract(&LOG_OCCURRENCES_MOD_N, n); \ + if (LOG_OCCURRENCES_MOD_N == 1) \ + google::ErrnoLogMessage( \ + __FILE__, __LINE__, google::GLOG_##severity, LOG_OCCURRENCES, \ + &what_to_do) \ + .stream() + +#define SOME_KIND_OF_LOG_FIRST_N(severity, n, what_to_do) \ + static volatile unsigned LOG_OCCURRENCES = 0; \ + if (LOG_OCCURRENCES <= n) \ + InterlockedIncrement(&LOG_OCCURRENCES); \ + if (LOG_OCCURRENCES <= n) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_##severity, LOG_OCCURRENCES, \ + &what_to_do) \ + .stream() + +#else + +#define SOME_KIND_OF_LOG_EVERY_N(severity, n, what_to_do) \ + static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \ + __sync_add_and_fetch(&LOG_OCCURRENCES, 1); \ + if (__sync_add_and_fetch(&LOG_OCCURRENCES_MOD_N, 1) > n) \ + __sync_sub_and_fetch(&LOG_OCCURRENCES_MOD_N, n); \ + if (LOG_OCCURRENCES_MOD_N == 1) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_##severity, LOG_OCCURRENCES, \ + &what_to_do) \ + .stream() + +#define SOME_KIND_OF_LOG_IF_EVERY_N(severity, condition, n, what_to_do) \ + static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \ + __sync_add_and_fetch(&LOG_OCCURRENCES, 1); \ + if ((condition) && \ + (__sync_add_and_fetch(&LOG_OCCURRENCES_MOD_N, 1) || true) && \ + ((LOG_OCCURRENCES_MOD_N >= n && __sync_sub_and_fetch(&LOG_OCCURRENCES_MOD_N, n)) || true) && \ + LOG_OCCURRENCES_MOD_N == (1 % n)) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_##severity, LOG_OCCURRENCES, \ + &what_to_do) \ + .stream() + +#define SOME_KIND_OF_PLOG_EVERY_N(severity, n, what_to_do) \ + static int LOG_OCCURRENCES = 0, LOG_OCCURRENCES_MOD_N = 0; \ + __sync_add_and_fetch(&LOG_OCCURRENCES, 1); \ + if (__sync_add_and_fetch(&LOG_OCCURRENCES_MOD_N, 1) > n) \ + __sync_sub_and_fetch(&LOG_OCCURRENCES_MOD_N, n); \ + if (LOG_OCCURRENCES_MOD_N == 1) \ + google::ErrnoLogMessage( \ + __FILE__, __LINE__, google::GLOG_##severity, LOG_OCCURRENCES, \ + &what_to_do) \ + .stream() + +#define SOME_KIND_OF_LOG_FIRST_N(severity, n, what_to_do) \ + static int LOG_OCCURRENCES = 0; \ + if (LOG_OCCURRENCES <= n) \ + __sync_add_and_fetch(&LOG_OCCURRENCES, 1); \ + if (LOG_OCCURRENCES <= n) \ + google::LogMessage( \ + __FILE__, __LINE__, google::GLOG_##severity, LOG_OCCURRENCES, \ + &what_to_do) \ + .stream() +#endif + + namespace glog_internal_namespace_ + { + template + struct CompileAssert + { + }; + struct CrashReason; + + // Returns true if FailureSignalHandler is installed. + // Needs to be exported since it's used by the signalhandler_unittest. + GLOG_EXPORT bool IsFailureSignalHandlerInstalled(); + } // namespace glog_internal_namespace_ + +#define LOG_EVERY_N(severity, n) \ + SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToLog) + +#define LOG_EVERY_T(severity, T) SOME_KIND_OF_LOG_EVERY_T(severity, (T)) + +#define SYSLOG_EVERY_N(severity, n) \ + SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToSyslogAndLog) + +#define PLOG_EVERY_N(severity, n) \ + SOME_KIND_OF_PLOG_EVERY_N(severity, (n), google::LogMessage::SendToLog) + +#define LOG_FIRST_N(severity, n) \ + SOME_KIND_OF_LOG_FIRST_N(severity, (n), google::LogMessage::SendToLog) + +#define LOG_IF_EVERY_N(severity, condition, n) \ + SOME_KIND_OF_LOG_IF_EVERY_N(severity, (condition), (n), google::LogMessage::SendToLog) + + // We want the special COUNTER value available for LOG_EVERY_X()'ed messages + enum PRIVATE_Counter + { + COUNTER + }; + +#ifdef GLOG_NO_ABBREVIATED_SEVERITIES +// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets +// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us +// to keep using this syntax, we define this macro to do the same thing +// as COMPACT_GOOGLE_LOG_ERROR. +#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR +#define SYSLOG_0 SYSLOG_ERROR +#define LOG_TO_STRING_0 LOG_TO_STRING_ERROR + // Needed for LOG_IS_ON(ERROR). + const LogSeverity GLOG_0 = GLOG_ERROR; +#else +// Users may include windows.h after logging.h without +// GLOG_NO_ABBREVIATED_SEVERITIES nor WIN32_LEAN_AND_MEAN. +// For this case, we cannot detect if ERROR is defined before users +// actually use ERROR. Let's make an undefined symbol to warn users. +#define GLOG_ERROR_MSG ERROR_macro_is_defined_Define_GLOG_NO_ABBREVIATED_SEVERITIES_before_including_logging_h_See_the_document_for_detail +#define COMPACT_GOOGLE_LOG_0 GLOG_ERROR_MSG +#define SYSLOG_0 GLOG_ERROR_MSG +#define LOG_TO_STRING_0 GLOG_ERROR_MSG +#define GLOG_0 GLOG_ERROR_MSG +#endif + + // Plus some debug-logging macros that get compiled to nothing for production + +#if DCHECK_IS_ON() + +#define DLOG(severity) LOG(severity) +#define DVLOG(verboselevel) VLOG(verboselevel) +#define DLOG_IF(severity, condition) LOG_IF(severity, condition) +#define DLOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n) +#define DLOG_IF_EVERY_N(severity, condition, n) \ + LOG_IF_EVERY_N(severity, condition, n) +#define DLOG_ASSERT(condition) LOG_ASSERT(condition) + +// debug-only checking. executed if DCHECK_IS_ON(). +#define DCHECK(condition) CHECK(condition) +#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2) +#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2) +#define DCHECK_LE(val1, val2) CHECK_LE(val1, val2) +#define DCHECK_LT(val1, val2) CHECK_LT(val1, val2) +#define DCHECK_GE(val1, val2) CHECK_GE(val1, val2) +#define DCHECK_GT(val1, val2) CHECK_GT(val1, val2) +#define DCHECK_NOTNULL(val) CHECK_NOTNULL(val) +#define DCHECK_STREQ(str1, str2) CHECK_STREQ(str1, str2) +#define DCHECK_STRCASEEQ(str1, str2) CHECK_STRCASEEQ(str1, str2) +#define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2) +#define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2) + +#else // !DCHECK_IS_ON() + +#define DLOG(severity) \ + static_cast(0), \ + true ? (void)0 : google::LogMessageVoidify() & LOG(severity) + +#define DVLOG(verboselevel) \ + static_cast(0), \ + (true || !VLOG_IS_ON(verboselevel)) ? (void)0 : google::LogMessageVoidify() & LOG(INFO) + +#define DLOG_IF(severity, condition) \ + static_cast(0), \ + (true || !(condition)) ? (void)0 : google::LogMessageVoidify() & LOG(severity) + +#define DLOG_EVERY_N(severity, n) \ + static_cast(0), \ + true ? (void)0 : google::LogMessageVoidify() & LOG(severity) + +#define DLOG_IF_EVERY_N(severity, condition, n) \ + static_cast(0), \ + (true || !(condition)) ? (void)0 : google::LogMessageVoidify() & LOG(severity) + +#define DLOG_ASSERT(condition) \ + static_cast(0), \ + true ? (void)0 : LOG_ASSERT(condition) + +// MSVC warning C4127: conditional expression is constant +#define DCHECK(condition) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() \ + CHECK(condition) + +#define DCHECK_EQ(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() \ + CHECK_EQ(val1, val2) + +#define DCHECK_NE(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() \ + CHECK_NE(val1, val2) + +#define DCHECK_LE(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() \ + CHECK_LE(val1, val2) + +#define DCHECK_LT(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() \ + CHECK_LT(val1, val2) + +#define DCHECK_GE(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() \ + CHECK_GE(val1, val2) + +#define DCHECK_GT(val1, val2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() \ + CHECK_GT(val1, val2) + +// You may see warnings in release mode if you don't use the return +// value of DCHECK_NOTNULL. Please just use DCHECK for such cases. +#define DCHECK_NOTNULL(val) (val) + +#define DCHECK_STREQ(str1, str2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() \ + CHECK_STREQ(str1, str2) + +#define DCHECK_STRCASEEQ(str1, str2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() \ + CHECK_STRCASEEQ(str1, str2) + +#define DCHECK_STRNE(str1, str2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() \ + CHECK_STRNE(str1, str2) + +#define DCHECK_STRCASENE(str1, str2) \ + GLOG_MSVC_PUSH_DISABLE_WARNING(4127) \ + while (false) \ + GLOG_MSVC_POP_WARNING() \ + CHECK_STRCASENE(str1, str2) + +#endif // DCHECK_IS_ON() + + // Log only in verbose mode. + +#define VLOG(verboselevel) LOG_IF(INFO, VLOG_IS_ON(verboselevel)) + +#define VLOG_IF(verboselevel, condition) \ + LOG_IF(INFO, (condition) && VLOG_IS_ON(verboselevel)) + +#define VLOG_EVERY_N(verboselevel, n) \ + LOG_IF_EVERY_N(INFO, VLOG_IS_ON(verboselevel), n) + +#define VLOG_IF_EVERY_N(verboselevel, condition, n) \ + LOG_IF_EVERY_N(INFO, (condition) && VLOG_IS_ON(verboselevel), n) + + namespace base_logging + { + + // LogMessage::LogStream is a std::ostream backed by this streambuf. + // This class ignores overflow and leaves two bytes at the end of the + // buffer to allow for a '\n' and '\0'. + class GLOG_EXPORT LogStreamBuf : public std::streambuf + { + public: + // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\0'. + LogStreamBuf(char *buf, int len) + { + setp(buf, buf + len - 2); + } + + // This effectively ignores overflow. + int_type overflow(int_type ch) + { + return ch; + } + + // Legacy public ostrstream method. + size_t pcount() const { return static_cast(pptr() - pbase()); } + char *pbase() const { return std::streambuf::pbase(); } + }; + + } // namespace base_logging + + // + // This class more or less represents a particular log message. You + // create an instance of LogMessage and then stream stuff to it. + // When you finish streaming to it, ~LogMessage is called and the + // full message gets streamed to the appropriate destination. + // + // You shouldn't actually use LogMessage's constructor to log things, + // though. You should use the LOG() macro (and variants thereof) + // above. + class GLOG_EXPORT LogMessage + { + public: + enum + { + // Passing kNoLogPrefix for the line number disables the + // log-message prefix. Useful for using the LogMessage + // infrastructure as a printing utility. See also the --log_prefix + // flag for controlling the log-message prefix on an + // application-wide basis. + kNoLogPrefix = -1 + }; + + // LogStream inherit from non-DLL-exported class (std::ostrstream) + // and VC++ produces a warning for this situation. + // However, MSDN says "C4275 can be ignored in Microsoft Visual C++ + // 2005 if you are deriving from a type in the Standard C++ Library" + // http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx + // Let's just ignore the warning. + GLOG_MSVC_PUSH_DISABLE_WARNING(4275) + class GLOG_EXPORT LogStream : public std::ostream + { + GLOG_MSVC_POP_WARNING() + public: + LogStream(char *buf, int len, int64 ctr) + : std::ostream(NULL), + streambuf_(buf, len), + ctr_(ctr), + self_(this) + { + rdbuf(&streambuf_); + } + + int64 ctr() const { return ctr_; } + void set_ctr(int64 ctr) { ctr_ = ctr; } + LogStream *self() const { return self_; } + + // Legacy std::streambuf methods. + size_t pcount() const { return streambuf_.pcount(); } + char *pbase() const { return streambuf_.pbase(); } + char *str() const { return pbase(); } + + private: + LogStream(const LogStream &); + LogStream &operator=(const LogStream &); + base_logging::LogStreamBuf streambuf_; + int64 ctr_; // Counter hack (for the LOG_EVERY_X() macro) + LogStream *self_; // Consistency check hack + }; + + public: + // icc 8 requires this typedef to avoid an internal compiler error. + typedef void (LogMessage::*SendMethod)(); + + LogMessage(const char *file, int line, LogSeverity severity, int64 ctr, + SendMethod send_method); + + // Two special constructors that generate reduced amounts of code at + // LOG call sites for common cases. + + // Used for LOG(INFO): Implied are: + // severity = INFO, ctr = 0, send_method = &LogMessage::SendToLog. + // + // Using this constructor instead of the more complex constructor above + // saves 19 bytes per call site. + LogMessage(const char *file, int line); + + // Used for LOG(severity) where severity != INFO. Implied + // are: ctr = 0, send_method = &LogMessage::SendToLog + // + // Using this constructor instead of the more complex constructor above + // saves 17 bytes per call site. + LogMessage(const char *file, int line, LogSeverity severity); + + // Constructor to log this message to a specified sink (if not NULL). + // Implied are: ctr = 0, send_method = &LogMessage::SendToSinkAndLog if + // also_send_to_log is true, send_method = &LogMessage::SendToSink otherwise. + LogMessage(const char *file, int line, LogSeverity severity, LogSink *sink, + bool also_send_to_log); + + // Constructor where we also give a vector pointer + // for storing the messages (if the pointer is not NULL). + // Implied are: ctr = 0, send_method = &LogMessage::SaveOrSendToLog. + LogMessage(const char *file, int line, LogSeverity severity, + std::vector *outvec); + + // Constructor where we also give a string pointer for storing the + // message (if the pointer is not NULL). Implied are: ctr = 0, + // send_method = &LogMessage::WriteToStringAndLog. + LogMessage(const char *file, int line, LogSeverity severity, + std::string *message); + + // A special constructor used for check failures + LogMessage(const char *file, int line, const CheckOpString &result); + + ~LogMessage(); + + // Flush a buffered message to the sink set in the constructor. Always + // called by the destructor, it may also be called from elsewhere if + // needed. Only the first call is actioned; any later ones are ignored. + void Flush(); + + // An arbitrary limit on the length of a single log message. This + // is so that streaming can be done more efficiently. + static const size_t kMaxLogMessageLen; + + // Theses should not be called directly outside of logging.*, + // only passed as SendMethod arguments to other LogMessage methods: + void SendToLog(); // Actually dispatch to the logs + void SendToSyslogAndLog(); // Actually dispatch to syslog and the logs + + // Call abort() or similar to perform LOG(FATAL) crash. + static void __declspec(noreturn) Fail(); + + std::ostream &stream(); + + int preserved_errno() const; + + // Must be called without the log_mutex held. (L < log_mutex) + static int64 num_messages(int severity); + + const LogMessageTime &getLogMessageTime() const; + + struct LogMessageData; + + private: + // Fully internal SendMethod cases: + void SendToSinkAndLog(); // Send to sink if provided and dispatch to the logs + void SendToSink(); // Send to sink if provided, do nothing otherwise. + + // Write to string if provided and dispatch to the logs. + void WriteToStringAndLog(); + + void SaveOrSendToLog(); // Save to stringvec if provided, else to logs + + void Init(const char *file, int line, LogSeverity severity, + void (LogMessage::*send_method)()); + + // Used to fill in crash information during LOG(FATAL) failures. + void RecordCrashReason(glog_internal_namespace_::CrashReason *reason); + + // Counts of messages sent at each priority: + static int64 num_messages_[NUM_SEVERITIES]; // under log_mutex + + // We keep the data in a separate struct so that each instance of + // LogMessage uses less stack space. + LogMessageData *allocated_; + LogMessageData *data_; + LogMessageTime logmsgtime_; + + friend class LogDestination; + + LogMessage(const LogMessage &); + void operator=(const LogMessage &); + }; + + // This class happens to be thread-hostile because all instances share + // a single data buffer, but since it can only be created just before + // the process dies, we don't worry so much. + class GLOG_EXPORT LogMessageFatal : public LogMessage + { + public: + LogMessageFatal(const char *file, int line); + LogMessageFatal(const char *file, int line, const CheckOpString &result); + __declspec(noreturn) ~LogMessageFatal(); + }; + + // A non-macro interface to the log facility; (useful + // when the logging level is not a compile-time constant). + inline void LogAtLevel(int const severity, std::string const &msg) + { + LogMessage(__FILE__, __LINE__, severity).stream() << msg; + } + +// A macro alternative of LogAtLevel. New code may want to use this +// version since there are two advantages: 1. this version outputs the +// file name and the line number where this macro is put like other +// LOG macros, 2. this macro can be used as C++ stream. +#define LOG_AT_LEVEL(severity) google::LogMessage(__FILE__, __LINE__, severity).stream() + +// Check if it's compiled in C++11 mode. +// +// GXX_EXPERIMENTAL_CXX0X is defined by gcc and clang up to at least +// gcc-4.7 and clang-3.1 (2011-12-13). __cplusplus was defined to 1 +// in gcc before 4.7 (Crosstool 16) and clang before 3.1, but is +// defined according to the language version in effect thereafter. +// Microsoft Visual Studio 14 (2015) sets __cplusplus==199711 despite +// reasonably good C++11 support, so we set LANG_CXX for it and +// newer versions (_MSC_VER >= 1900). +#if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L || \ + (defined(_MSC_VER) && _MSC_VER >= 1900)) && \ + !defined(__UCLIBCXX_MAJOR__) + // Helper for CHECK_NOTNULL(). + // + // In C++11, all cases can be handled by a single function. Since the value + // category of the argument is preserved (also for rvalue references), + // member initializer lists like the one below will compile correctly: + // + // Foo() + // : x_(CHECK_NOTNULL(MethodReturningUniquePtr())) {} + template + T CheckNotNull(const char *file, int line, const char *names, T &&t) + { + if (t == nullptr) + { + LogMessageFatal(file, line, new std::string(names)); + } + return std::forward(t); + } + +#else + + // A small helper for CHECK_NOTNULL(). + template + T *CheckNotNull(const char *file, int line, const char *names, T *t) + { + if (t == NULL) + { + LogMessageFatal(file, line, new std::string(names)); + } + return t; + } +#endif + + // Allow folks to put a counter in the LOG_EVERY_X()'ed messages. This + // only works if ostream is a LogStream. If the ostream is not a + // LogStream you'll get an assert saying as much at runtime. + GLOG_EXPORT std::ostream &operator<<(std::ostream &os, + const PRIVATE_Counter &); + + // Derived class for PLOG*() above. + class GLOG_EXPORT ErrnoLogMessage : public LogMessage + { + public: + ErrnoLogMessage(const char *file, int line, LogSeverity severity, int64 ctr, + void (LogMessage::*send_method)()); + + // Postpends ": strerror(errno) [errno]". + ~ErrnoLogMessage(); + + private: + ErrnoLogMessage(const ErrnoLogMessage &); + void operator=(const ErrnoLogMessage &); + }; + + // This class is used to explicitly ignore values in the conditional + // logging macros. This avoids compiler warnings like "value computed + // is not used" and "statement has no effect". + + class GLOG_EXPORT LogMessageVoidify + { + public: + LogMessageVoidify() {} + // This has to be an operator with a precedence lower than << but + // higher than ?: + void operator&(std::ostream &) {} + }; + + // Flushes all log files that contains messages that are at least of + // the specified severity level. Thread-safe. + GLOG_EXPORT void FlushLogFiles(LogSeverity min_severity); + + // Flushes all log files that contains messages that are at least of + // the specified severity level. Thread-hostile because it ignores + // locking -- used for catastrophic failures. + GLOG_EXPORT void FlushLogFilesUnsafe(LogSeverity min_severity); + + // + // Set the destination to which a particular severity level of log + // messages is sent. If base_filename is "", it means "don't log this + // severity". Thread-safe. + // + GLOG_EXPORT void SetLogDestination(LogSeverity severity, + const char *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 + // you don't call this function, the symlink basename is the + // invocation name of the program. Thread-safe. + // + GLOG_EXPORT void SetLogSymlink(LogSeverity severity, + const char *symlink_basename); + + // + // Used to send logs to some other kind of destination + // Users should subclass LogSink and override send to do whatever they want. + // Implementations must be thread-safe because a shared instance will + // be called from whichever thread ran the LOG(XXX) line. + class GLOG_EXPORT LogSink + { + public: + virtual ~LogSink(); + + // Sink's logging logic (message_len is such as to exclude '\n' at the end). + // This method can't use LOG() or CHECK() as logging system mutex(s) are held + // during this call. + virtual void send(LogSeverity severity, const char *full_filename, + const char *base_filename, int line, + const LogMessageTime &logmsgtime, const char *message, + size_t message_len); + // Provide an overload for compatibility purposes + GLOG_DEPRECATED + virtual void send(LogSeverity severity, const char *full_filename, + const char *base_filename, int line, const std::tm *t, + const char *message, size_t message_len); + + // Redefine this to implement waiting for + // the sink's logging logic to complete. + // It will be called after each send() returns, + // but before that LogMessage exits or crashes. + // By default this function does nothing. + // Using this function one can implement complex logic for send() + // that itself involves logging; and do all this w/o causing deadlocks and + // inconsistent rearrangement of log messages. + // E.g. if a LogSink has thread-specific actions, the send() method + // can simply add the message to a queue and wake up another thread that + // handles real logging while itself making some LOG() calls; + // WaitTillSent() can be implemented to wait for that logic to complete. + // See our unittest for an example. + virtual void WaitTillSent(); + + // Returns the normal text output of the log message. + // Can be useful to implement send(). + static std::string ToString(LogSeverity severity, const char *file, int line, + const LogMessageTime &logmsgtime, + const char *message, size_t message_len); + }; + + // Add or remove a LogSink as a consumer of logging data. Thread-safe. + GLOG_EXPORT void AddLogSink(LogSink *destination); + GLOG_EXPORT void RemoveLogSink(LogSink *destination); + + // + // Specify an "extension" added to the filename specified via + // SetLogDestination. This applies to all severity levels. It's + // often used to append the port we're listening on to the logfile + // name. Thread-safe. + // + GLOG_EXPORT void SetLogFilenameExtension( + const char *filename_extension); + + // + // Make it so that all log messages of at least a particular severity + // are logged to stderr (in addition to logging to the usual log + // file(s)). Thread-safe. + // + GLOG_EXPORT void SetStderrLogging(LogSeverity min_severity); + + // + // Make it so that all log messages go only to stderr. Thread-safe. + // + GLOG_EXPORT void LogToStderr(); + + // + // Make it so that all log messages of at least a particular severity are + // logged via email to a list of addresses (in addition to logging to the + // usual log file(s)). The list of addresses is just a string containing + // the email addresses to send to (separated by spaces, say). Thread-safe. + // + GLOG_EXPORT void SetEmailLogging(LogSeverity min_severity, + const char *addresses); + + // A simple function that sends email. dest is a commma-separated + // list of addressess. Thread-safe. + GLOG_EXPORT bool SendEmail(const char *dest, const char *subject, + const char *body); + + GLOG_EXPORT const std::vector &GetLoggingDirectories(); + + // For tests only: Clear the internal [cached] list of logging directories to + // force a refresh the next time GetLoggingDirectories is called. + // Thread-hostile. + void TestOnly_ClearLoggingDirectoriesList(); + + // Returns a set of existing temporary directories, which will be a + // subset of the directories returned by GetLoggingDirectories(). + // Thread-safe. + GLOG_EXPORT void GetExistingTempDirectories( + std::vector *list); + + // Print any fatal message again -- useful to call from signal handler + // so that the last thing in the output is the fatal message. + // Thread-hostile, but a race is unlikely. + GLOG_EXPORT void ReprintFatalMessage(); + + // Truncate a log file that may be the append-only output of multiple + // processes and hence can't simply be renamed/reopened (typically a + // stdout/stderr). If the file "path" is > "limit" bytes, copy the + // last "keep" bytes to offset 0 and truncate the rest. Since we could + // be racing with other writers, this approach has the potential to + // lose very small amounts of data. For security, only follow symlinks + // if the path is /proc/self/fd/* + GLOG_EXPORT void TruncateLogFile(const char *path, uint64 limit, uint64 keep); + + // Truncate stdout and stderr if they are over the value specified by + // --max_log_size; keep the final 1MB. This function has the same + // race condition as TruncateLogFile. + GLOG_EXPORT void TruncateStdoutStderr(); + + // Return the string representation of the provided LogSeverity level. + // Thread-safe. + GLOG_EXPORT const char *GetLogSeverityName(LogSeverity severity); + + // --------------------------------------------------------------------- + // Implementation details that are not useful to most clients + // --------------------------------------------------------------------- + + // A Logger is the interface used by logging modules to emit entries + // to a log. A typical implementation will dump formatted data to a + // sequence of files. We also provide interfaces that will forward + // the data to another thread so that the invoker never blocks. + // Implementations should be thread-safe since the logging system + // will write to them from multiple threads. + + namespace base + { + + class GLOG_EXPORT Logger + { + public: + virtual ~Logger(); + + // Writes "message[0,message_len-1]" corresponding to an event that + // occurred at "timestamp". If "force_flush" is true, the log file + // is flushed immediately. + // + // The input message has already been formatted as deemed + // appropriate by the higher level logging facility. For example, + // textual log messages already contain timestamps, and the + // file:linenumber header. + virtual void Write(bool force_flush, + time_t timestamp, + const char *message, + size_t message_len) = 0; + + // Flush any buffered messages + virtual void Flush() = 0; + + // Get the current LOG file size. + // The returned value is approximate since some + // logged data may not have been flushed to disk yet. + virtual uint32 LogSize() = 0; + }; + + // Get the logger for the specified severity level. The logger + // remains the property of the logging module and should not be + // deleted by the caller. Thread-safe. + extern GLOG_EXPORT Logger *GetLogger(LogSeverity level); + + // Set the logger for the specified severity level. The logger + // becomes the property of the logging module and should not + // be deleted by the caller. Thread-safe. + extern GLOG_EXPORT void SetLogger(LogSeverity level, Logger *logger); + + } + + // glibc has traditionally implemented two incompatible versions of + // strerror_r(). There is a poorly defined convention for picking the + // version that we want, but it is not clear whether it even works with + // all versions of glibc. + // So, instead, we provide this wrapper that automatically detects the + // version that is in use, and then implements POSIX semantics. + // N.B. In addition to what POSIX says, we also guarantee that "buf" will + // be set to an empty string, if this function failed. This means, in most + // cases, you do not need to check the error code and you can directly + // use the value of "buf". It will never have an undefined value. + // DEPRECATED: Use StrError(int) instead. + GLOG_EXPORT int posix_strerror_r(int err, char *buf, size_t len); + + // A thread-safe replacement for strerror(). Returns a string describing the + // given POSIX error code. + GLOG_EXPORT std::string StrError(int err); + + // A class for which we define operator<<, which does nothing. + class GLOG_EXPORT NullStream : public LogMessage::LogStream + { + public: + // Initialize the LogStream so the messages can be written somewhere + // (they'll never be actually displayed). This will be needed if a + // NullStream& is implicitly converted to LogStream&, in which case + // the overloaded NullStream::operator<< will not be invoked. + NullStream() : LogMessage::LogStream(message_buffer_, 1, 0) {} + NullStream(const char * /*file*/, int /*line*/, + const CheckOpString & /*result*/) : LogMessage::LogStream(message_buffer_, 1, 0) {} + NullStream &stream() { return *this; } + + private: + // A very short buffer for messages (which we discard anyway). This + // will be needed if NullStream& converted to LogStream& (e.g. as a + // result of a conditional expression). + char message_buffer_[2]; + }; + + // Do nothing. This operator is inline, allowing the message to be + // compiled away. The message will not be compiled away if we do + // something like (flag ? LOG(INFO) : LOG(ERROR)) << message; when + // SKIP_LOG=WARNING. In those cases, NullStream will be implicitly + // converted to LogStream and the message will be computed and then + // quietly discarded. + template + inline NullStream &operator<<(NullStream &str, const T &) { return str; } + + // Similar to NullStream, but aborts the program (without stack + // trace), like LogMessageFatal. + class GLOG_EXPORT NullStreamFatal : public NullStream + { + public: + NullStreamFatal() {} + NullStreamFatal(const char *file, int line, const CheckOpString &result) : NullStream(file, line, result) {} +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4722) +#endif // _MSC_VER + __declspec(noreturn) ~NullStreamFatal() throw() + { + _exit(EXIT_FAILURE); + } +#if defined(_MSC_VER) +#pragma warning(pop) +#endif // _MSC_VER + }; + + // Install a signal handler that will dump signal information and a stack + // trace when the program crashes on certain signals. We'll install the + // signal handler for the following signals. + // + // SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGBUS, and SIGTERM. + // + // By default, the signal handler will write the failure dump to the + // standard error. You can customize the destination by installing your + // own writer function by InstallFailureWriter() below. + // + // Note on threading: + // + // The function should be called before threads are created, if you want + // to use the failure signal handler for all threads. The stack trace + // will be shown only for the thread that receives the signal. In other + // words, stack traces of other threads won't be shown. + GLOG_EXPORT void InstallFailureSignalHandler(); + + // Installs a function that is used for writing the failure dump. "data" + // is the pointer to the beginning of a message to be written, and "size" + // is the size of the message. You should not expect the data is + // terminated with '\0'. + GLOG_EXPORT void InstallFailureWriter( + void (*writer)(const char *data, size_t size)); +} + +#pragma pop_macro("DECLARE_VARIABLE") +#pragma pop_macro("DECLARE_bool") +#pragma pop_macro("DECLARE_string") +#pragma pop_macro("DECLARE_int32") +#pragma pop_macro("DECLARE_uint32") + +#endif // GLOG_LOGGING_H diff --git a/3rdparty/include/glog/platform.h b/3rdparty/include/glog/platform.h new file mode 100644 index 0000000000000000000000000000000000000000..7893c45d173413a389463aae0af36f963cddb92a --- /dev/null +++ b/3rdparty/include/glog/platform.h @@ -0,0 +1,60 @@ +// Copyright (c) 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Shinichiro Hamaji +// +// Detect supported platforms. + +#ifndef GLOG_PLATFORM_H +#define GLOG_PLATFORM_H + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +#define GLOG_OS_WINDOWS +#elif defined(__CYGWIN__) || defined(__CYGWIN32__) +#define GLOG_OS_CYGWIN +#elif defined(linux) || defined(__linux) || defined(__linux__) +#ifndef GLOG_OS_LINUX +#define GLOG_OS_LINUX +#endif +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) +#define GLOG_OS_MACOSX +#elif defined(__FreeBSD__) +#define GLOG_OS_FREEBSD +#elif defined(__NetBSD__) +#define GLOG_OS_NETBSD +#elif defined(__OpenBSD__) +#define GLOG_OS_OPENBSD +#elif defined(__EMSCRIPTEN__) +#define GLOG_OS_EMSCRIPTEN +#else +// TODO(hamaji): Add other platforms. +#error Platform not supported by glog. Please consider to contribute platform information by submitting a pull request on Github. +#endif + +#endif // GLOG_PLATFORM_H diff --git a/3rdparty/include/glog/raw_logging.h b/3rdparty/include/glog/raw_logging.h new file mode 100644 index 0000000000000000000000000000000000000000..9b4fec2f4fffedc23f1240999bbfb9c3469b4ecb --- /dev/null +++ b/3rdparty/include/glog/raw_logging.h @@ -0,0 +1,187 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Maxim Lifantsev +// +// 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 GLOG_RAW_LOGGING_H +#define GLOG_RAW_LOGGING_H + +#include + +namespace google +{ + +#include +#include +#include + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wvariadic-macros" +#endif + +// This is similar to LOG(severity) << format... and VLOG(level) << format.., +// but +// * it is to be used ONLY by low-level modules that can't use normal LOG() +// * it is desiged to be a low-level logger that does not allocate any +// memory and does not need any locks, hence: +// * it logs straight and ONLY to STDERR w/o buffering +// * it uses an explicit format and arguments list +// * it will silently chop off really long message strings +// Usage example: +// RAW_LOG(ERROR, "Failed foo with %i: %s", status, error); +// RAW_VLOG(3, "status is %i", status); +// These will print an almost standard log lines like this to stderr only: +// E20200821 211317 file.cc:123] RAW: Failed foo with 22: bad_file +// I20200821 211317 file.cc:142] RAW: status is 20 +#define RAW_LOG(severity, ...) \ + do \ + { \ + switch (google::GLOG_##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 !defined(STRIP_LOG) || STRIP_LOG == 0 +#define RAW_VLOG(verboselevel, ...) \ + do \ + { \ + if (VLOG_IS_ON(verboselevel)) \ + { \ + RAW_LOG_INFO(__VA_ARGS__); \ + } \ + } while (0) +#else +#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__) +#endif // STRIP_LOG == 0 + +#if !defined(STRIP_LOG) || STRIP_LOG == 0 +#define RAW_LOG_INFO(...) google::RawLog__(google::GLOG_INFO, \ + __FILE__, __LINE__, __VA_ARGS__) +#else +#define RAW_LOG_INFO(...) google::RawLogStub__(0, __VA_ARGS__) +#endif // STRIP_LOG == 0 + +#if !defined(STRIP_LOG) || STRIP_LOG <= 1 +#define RAW_LOG_WARNING(...) google::RawLog__(google::GLOG_WARNING, \ + __FILE__, __LINE__, __VA_ARGS__) +#else +#define RAW_LOG_WARNING(...) google::RawLogStub__(0, __VA_ARGS__) +#endif // STRIP_LOG <= 1 + +#if !defined(STRIP_LOG) || STRIP_LOG <= 2 +#define RAW_LOG_ERROR(...) google::RawLog__(google::GLOG_ERROR, \ + __FILE__, __LINE__, __VA_ARGS__) +#else +#define RAW_LOG_ERROR(...) google::RawLogStub__(0, __VA_ARGS__) +#endif // STRIP_LOG <= 2 + +#if !defined(STRIP_LOG) || STRIP_LOG <= 3 +#define RAW_LOG_FATAL(...) google::RawLog__(google::GLOG_FATAL, \ + __FILE__, __LINE__, __VA_ARGS__) +#else +#define RAW_LOG_FATAL(...) \ + do \ + { \ + google::RawLogStub__(0, __VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } 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. +// We do not want to provide args list here to encourage this usage: +// if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args); +// so that the args are not computed when not needed. +#define RAW_CHECK(condition, message) \ + do \ + { \ + if (!(condition)) \ + { \ + RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \ + } \ + } while (0) + +// Debug versions of RAW_LOG and RAW_CHECK +#ifndef NDEBUG + +#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__) +#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message) + +#else // NDEBUG + +#define RAW_DLOG(severity, ...) \ + while (false) \ + RAW_LOG(severity, __VA_ARGS__) +#define RAW_DCHECK(condition, message) \ + while (false) \ + RAW_CHECK(condition, message) + +#endif // NDEBUG + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + + // 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. + // This does not allocate memory or acquire locks. + GLOG_EXPORT void RawLog__(LogSeverity severity, const char *file, int line, + const char *format, ...); + +} + +#endif // GLOG_RAW_LOGGING_H diff --git a/3rdparty/include/glog/stl_logging.h b/3rdparty/include/glog/stl_logging.h new file mode 100644 index 0000000000000000000000000000000000000000..60a330bf8da441eb997a2424d76e8f20d950f1eb --- /dev/null +++ b/3rdparty/include/glog/stl_logging.h @@ -0,0 +1,234 @@ +// Copyright (c) 2003, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Stream output operators for STL containers; to be used for logging *only*. +// Inclusion of this file lets you do: +// +// list x; +// LOG(INFO) << "data: " << x; +// vector v1, v2; +// CHECK_EQ(v1, v2); +// +// If you want to use this header file with hash maps or slist, you +// need to define macros before including this file: +// +// - GLOG_STL_LOGGING_FOR_UNORDERED - and +// - GLOG_STL_LOGGING_FOR_TR1_UNORDERED - +// - GLOG_STL_LOGGING_FOR_EXT_HASH - +// - GLOG_STL_LOGGING_FOR_EXT_SLIST - +// + +#ifndef UTIL_GTL_STL_LOGGING_INL_H_ +#define UTIL_GTL_STL_LOGGING_INL_H_ + +#if !1 +#error We do not support stl_logging for this compiler +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if defined(GLOG_STL_LOGGING_FOR_UNORDERED) && __cplusplus >= 201103L +#include +#include +#endif + +#ifdef GLOG_STL_LOGGING_FOR_TR1_UNORDERED +#include +#include +#endif + +#ifdef GLOG_STL_LOGGING_FOR_EXT_HASH +#include +#include +#endif +#ifdef GLOG_STL_LOGGING_FOR_EXT_SLIST +#include +#endif + +// Forward declare these two, and define them after all the container streams +// operators so that we can recurse from pair -> container -> container -> pair +// properly. +template +std::ostream &operator<<(std::ostream &out, const std::pair &p); + +namespace google +{ + + template + void PrintSequence(std::ostream &out, Iter begin, Iter end); + +} + +#define OUTPUT_TWO_ARG_CONTAINER(Sequence) \ + template \ + inline std::ostream &operator<<(std::ostream &out, \ + const Sequence &seq) \ + { \ + google::PrintSequence(out, seq.begin(), seq.end()); \ + return out; \ + } + +OUTPUT_TWO_ARG_CONTAINER(std::vector) +OUTPUT_TWO_ARG_CONTAINER(std::deque) +OUTPUT_TWO_ARG_CONTAINER(std::list) +#ifdef GLOG_STL_LOGGING_FOR_EXT_SLIST +OUTPUT_TWO_ARG_CONTAINER(__gnu_cxx::slist) +#endif + +#undef OUTPUT_TWO_ARG_CONTAINER + +#define OUTPUT_THREE_ARG_CONTAINER(Sequence) \ + template \ + inline std::ostream &operator<<(std::ostream &out, \ + const Sequence &seq) \ + { \ + google::PrintSequence(out, seq.begin(), seq.end()); \ + return out; \ + } + +OUTPUT_THREE_ARG_CONTAINER(std::set) +OUTPUT_THREE_ARG_CONTAINER(std::multiset) + +#undef OUTPUT_THREE_ARG_CONTAINER + +#define OUTPUT_FOUR_ARG_CONTAINER(Sequence) \ + template \ + inline std::ostream &operator<<(std::ostream &out, \ + const Sequence &seq) \ + { \ + google::PrintSequence(out, seq.begin(), seq.end()); \ + return out; \ + } + +OUTPUT_FOUR_ARG_CONTAINER(std::map) +OUTPUT_FOUR_ARG_CONTAINER(std::multimap) +#if defined(GLOG_STL_LOGGING_FOR_UNORDERED) && __cplusplus >= 201103L +OUTPUT_FOUR_ARG_CONTAINER(std::unordered_set) +OUTPUT_FOUR_ARG_CONTAINER(std::unordered_multiset) +#endif +#ifdef GLOG_STL_LOGGING_FOR_TR1_UNORDERED +OUTPUT_FOUR_ARG_CONTAINER(std::tr1::unordered_set) +OUTPUT_FOUR_ARG_CONTAINER(std::tr1::unordered_multiset) +#endif +#ifdef GLOG_STL_LOGGING_FOR_EXT_HASH +OUTPUT_FOUR_ARG_CONTAINER(__gnu_cxx::hash_set) +OUTPUT_FOUR_ARG_CONTAINER(__gnu_cxx::hash_multiset) +#endif + +#undef OUTPUT_FOUR_ARG_CONTAINER + +#define OUTPUT_FIVE_ARG_CONTAINER(Sequence) \ + template \ + inline std::ostream &operator<<(std::ostream &out, \ + const Sequence &seq) \ + { \ + google::PrintSequence(out, seq.begin(), seq.end()); \ + return out; \ + } + +#if defined(GLOG_STL_LOGGING_FOR_UNORDERED) && __cplusplus >= 201103L +OUTPUT_FIVE_ARG_CONTAINER(std::unordered_map) +OUTPUT_FIVE_ARG_CONTAINER(std::unordered_multimap) +#endif +#ifdef GLOG_STL_LOGGING_FOR_TR1_UNORDERED +OUTPUT_FIVE_ARG_CONTAINER(std::tr1::unordered_map) +OUTPUT_FIVE_ARG_CONTAINER(std::tr1::unordered_multimap) +#endif +#ifdef GLOG_STL_LOGGING_FOR_EXT_HASH +OUTPUT_FIVE_ARG_CONTAINER(__gnu_cxx::hash_map) +OUTPUT_FIVE_ARG_CONTAINER(__gnu_cxx::hash_multimap) +#endif + +#undef OUTPUT_FIVE_ARG_CONTAINER + +template +inline std::ostream &operator<<(std::ostream &out, + const std::pair &p) +{ + out << '(' << p.first << ", " << p.second << ')'; + return out; +} + +namespace google +{ + + template + inline void PrintSequence(std::ostream &out, Iter begin, Iter end) + { + // Output at most 100 elements -- appropriate if used for logging. + for (int i = 0; begin != end && i < 100; ++i, ++begin) + { + if (i > 0) + out << ' '; + out << *begin; + } + if (begin != end) + { + out << " ..."; + } + } + +} + +// Note that this is technically undefined behavior! We are adding things into +// the std namespace for a reason though -- we are providing new operations on +// types which are themselves defined with this namespace. Without this, these +// operator overloads cannot be found via ADL. If these definitions are not +// found via ADL, they must be #included before they're used, which requires +// this header to be included before apparently independent other headers. +// +// For example, base/logging.h defines various template functions to implement +// CHECK_EQ(x, y) and stream x and y into the log in the event the check fails. +// It does so via the function template MakeCheckOpValueString: +// template +// void MakeCheckOpValueString(strstream* ss, const T& v) { +// (*ss) << v; +// } +// Because 'glog/logging.h' is included before 'glog/stl_logging.h', +// subsequent CHECK_EQ(v1, v2) for vector<...> typed variable v1 and v2 can only +// find these operator definitions via ADL. +// +// Even this solution has problems -- it may pull unintended operators into the +// namespace as well, allowing them to also be found via ADL, and creating code +// that only works with a particular order of includes. Long term, we need to +// move all of the *definitions* into namespace std, bet we need to ensure no +// one references them first. This lets us take that step. We cannot define them +// in both because that would create ambiguous overloads when both are found. +namespace std +{ + using ::operator<<; +} + +#endif // UTIL_GTL_STL_LOGGING_INL_H_ diff --git a/3rdparty/include/glog/vlog_is_on.h b/3rdparty/include/glog/vlog_is_on.h new file mode 100644 index 0000000000000000000000000000000000000000..3686ae08c4c4e29749700ebff6f255cb5478287d --- /dev/null +++ b/3rdparty/include/glog/vlog_is_on.h @@ -0,0 +1,120 @@ +// Copyright (c) 1999, 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Ray Sidney and many others +// +// Defines the VLOG_IS_ON macro that controls the variable-verbosity +// conditional logging. +// +// It's used by VLOG and VLOG_IF in logging.h +// and by RAW_VLOG in raw_logging.h to trigger the logging. +// +// It can also be used directly e.g. like this: +// if (VLOG_IS_ON(2)) { +// // do some logging preparation and logging +// // that can't be accomplished e.g. via just VLOG(2) << ...; +// } +// +// The truth value that VLOG_IS_ON(level) returns is determined by +// the three verbosity level flags: +// --v= Gives the default maximal active V-logging level; +// 0 is the default. +// Normally positive values are used for V-logging levels. +// --vmodule= Gives the per-module maximal V-logging levels to override +// the value given by --v. +// E.g. "my_module=2,foo*=3" would change the logging level +// for all code in source files "my_module.*" and "foo*.*" +// ("-inl" suffixes are also disregarded for this matching). +// +// SetVLOGLevel helper function is provided to do limited dynamic control over +// V-logging by overriding the per-module settings given via --vmodule flag. +// +// CAVEAT: --vmodule functionality is not available in non gcc compilers. +// + +#ifndef BASE_VLOG_IS_ON_H_ +#define BASE_VLOG_IS_ON_H_ + +#include + +#if defined(__GNUC__) +// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site. +// (Normally) the first time every VLOG_IS_ON(n) site is hit, +// we determine what variable will dynamically control logging at this site: +// it's either FLAGS_v or an appropriate internal variable +// matching the current source file that represents results of +// parsing of --vmodule flag and/or SetVLOGLevel calls. +#define VLOG_IS_ON(verboselevel) \ + __extension__({ \ + static google::SiteFlag vlocal__ = {NULL, NULL, 0, NULL}; \ + google::int32 verbose_level__ = (verboselevel); \ + (vlocal__.level == NULL ? google::InitVLOG3__(&vlocal__, &FLAGS_v, \ + __FILE__, verbose_level__) \ + : *vlocal__.level >= verbose_level__); \ + }) +#else +// GNU extensions not available, so we do not support --vmodule. +// Dynamic value of FLAGS_v always controls the logging level. +#define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel)) +#endif + +// Set VLOG(_IS_ON) level for module_pattern to log_level. +// This lets us dynamically control what is normally set by the --vmodule flag. +// Returns the level that previously applied to module_pattern. +// NOTE: To change the log level for VLOG(_IS_ON) sites +// that have already executed after/during InitGoogleLogging, +// one needs to supply the exact --vmodule pattern that applied to them. +// (If no --vmodule pattern applied to them +// the value of FLAGS_v will continue to control them.) +extern GLOG_EXPORT int SetVLOGLevel(const char *module_pattern, int log_level); + +// Various declarations needed for VLOG_IS_ON above: ========================= + +struct SiteFlag +{ + google::int32 *level; + const char *base_name; + size_t base_len; + SiteFlag *next; +}; + +// Helper routine which determines the logging info for a particalur VLOG site. +// site_flag is the address of the site-local pointer to the controlling +// verbosity level +// site_default is the default to use for *site_flag +// fname is the current source file name +// verbose_level is the argument to VLOG_IS_ON +// We will return the return value for VLOG_IS_ON +// and if possible set *site_flag appropriately. +extern GLOG_EXPORT bool InitVLOG3__( + google::SiteFlag *site_flag, + google::int32 *site_default, const char *fname, + google::int32 verbose_level); + +#endif // BASE_VLOG_IS_ON_H_ diff --git a/DWeChatRobot/json/README.md b/3rdparty/include/json/README.md similarity index 100% rename from DWeChatRobot/json/README.md rename to 3rdparty/include/json/README.md diff --git a/DWeChatRobot/mongoose/README.md b/3rdparty/include/mongoose/README.md similarity index 74% rename from DWeChatRobot/mongoose/README.md rename to 3rdparty/include/mongoose/README.md index 8cdb0ef6eaeec414b4eca52d2b4d4c620b0977e2..ccf2813cd250f137e4d766ccde8297e321a2dff7 100644 --- a/DWeChatRobot/mongoose/README.md +++ b/3rdparty/include/mongoose/README.md @@ -1,8 +1,8 @@ -# 注意 -此处源码来自以下仓库: -[mongoose](https://github.com/cesanta/mongoose) - -需要自行克隆该仓库并将mongoose.c和mongoose.h拷贝到此处 - -# Thanks +# 注意 +此处源码来自以下仓库: +[mongoose](https://github.com/cesanta/mongoose) + +需要自行克隆该仓库并将mongoose.c和mongoose.h拷贝到此处 + +# Thanks [mongoose](https://github.com/cesanta/mongoose) \ No newline at end of file diff --git a/DWeChatRobot/DWeChatRobot.vcxproj b/DWeChatRobot/DWeChatRobot.vcxproj index a400ccabcace7d2c8af2bbb5a02c41d830ee8a26..aef9a4353b6c8886ce73b8539bf4ebbca033b569 100644 --- a/DWeChatRobot/DWeChatRobot.vcxproj +++ b/DWeChatRobot/DWeChatRobot.vcxproj @@ -128,19 +128,23 @@ true $(ProjectName) - $(IncludePath) + $(IncludePath);../3rdparty/include + ../3rdparty/lib;$(LibraryPath) true SWeChatRobot - $(IncludePath) + $(IncludePath);../3rdparty/include $(Configuration)\ $(SolutionDir)Debug\socket\ + ../3rdparty/lib;$(LibraryPath) false $(ProjectName) true + $(VC_IncludePath);$(WindowsSDK_IncludePath);../3rdparty/include + ../3rdparty/lib;$(LibraryPath) false @@ -148,6 +152,8 @@ $(Configuration)\ $(SolutionDir)Release\socket\ true + $(VC_IncludePath);$(WindowsSDK_IncludePath);;../3rdparty/include + ../3rdparty/lib;$(LibraryPath) true @@ -352,11 +358,11 @@ xcopy /y /d "$(OutDir)..\..\Python\http\wxDriver.py" "$(SolutionDir)build\http + - diff --git a/DWeChatRobot/DWeChatRobot.vcxproj.filters b/DWeChatRobot/DWeChatRobot.vcxproj.filters index dd0761f334bfbf9523c60773668d4dcfb62aa922..e841e10d35fb89f9a37b202e98515ff847d34a64 100644 --- a/DWeChatRobot/DWeChatRobot.vcxproj.filters +++ b/DWeChatRobot/DWeChatRobot.vcxproj.filters @@ -374,9 +374,6 @@ 缇ょ浉鍏砛鑾峰彇缇ゆ垚鍛樻樀绉 - - wxsocket - 娴忚鍣ㄧ浉鍏砛鎵撳紑娴忚鍣 @@ -392,5 +389,8 @@ 娴忚鍣ㄧ浉鍏砛鑾峰彇A8Key + + wxsocket + diff --git a/DWeChatRobot/ReceiveMessage.cpp b/DWeChatRobot/ReceiveMessage.cpp index e749de942dde5ea464fc9969dd378ee3420e9415..3f23143f0877adc066a4d94b679b057b1d68a4f5 100644 --- a/DWeChatRobot/ReceiveMessage.cpp +++ b/DWeChatRobot/ReceiveMessage.cpp @@ -137,6 +137,9 @@ void SendSocketMessageInThread(SocketMessageStruct *param) return; } string jstr = jMsg.dump() + "\n"; + LOG(INFO) << "msgid: " << jMsg["msgid"].get() << " send begin." << endl; + LOG(INFO) << "type: " << jMsg["type"].get() << ", sender: " << jMsg["wxid"].get() << endl; + LOG(INFO) << "content: " << jMsg["message"].get() << endl; #ifdef USE_COM // 通过连接点,将消息广播给客户端;将广播过程放在线程中完成,客户端才可以等待图片、语音落地 VARIANT vsaValue = (_variant_t)utf8_to_unicode(jstr.c_str()).c_str(); @@ -145,6 +148,7 @@ void SendSocketMessageInThread(SocketMessageStruct *param) PostComMessage(jMsg["pid"].get(), WX_MESSAGE, msgid, &vsaValue); #endif SendSocketMessage(jstr.c_str(), jstr.size()); + LOG(INFO) << "msgid: " << jMsg["msgid"].get() << " send end." << endl; } static void dealMessage(DWORD messageAddr) diff --git a/DWeChatRobot/comclient.cpp b/DWeChatRobot/comclient.cpp index ee3d2080c84af007da36878c20649f70d4630ba5..4ee957335e37daa5de8ba1568c2fa68c72ae03d6 100644 --- a/DWeChatRobot/comclient.cpp +++ b/DWeChatRobot/comclient.cpp @@ -56,6 +56,7 @@ BOOL PostComMessage(DWORD pid, int msgtype, unsigned long long msgid, VARIANT *m } else { + CoUninitialize(); return false; } CoUninitialize(); diff --git a/DWeChatRobot/dllmain.cpp b/DWeChatRobot/dllmain.cpp index 4d3660d01295b73631f1671b388a346bde369fa6..1ea53e5ce0e130f2937c89fdc327a335d3130d9c 100644 --- a/DWeChatRobot/dllmain.cpp +++ b/DWeChatRobot/dllmain.cpp @@ -1,16 +1,18 @@ 锘// dllmain.cpp : 瀹氫箟 DLL 搴旂敤绋嬪簭鐨勫叆鍙g偣銆 #include "pch.h" -BOOL APIENTRY DllMain( HMODULE hModule, - DWORD ul_reason_for_call, - LPVOID lpReserved - ) +BOOL APIENTRY DllMain(HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { - if (ProcessIsWeChat()) { + gLogInit(); + LOG(INFO) << "Robot Start, isWxLogin: " << isWxLogin() << ", pid: " << GetCurrentProcessId() << endl; + if (ProcessIsWeChat()) + { #ifndef USE_SOCKET #ifdef _DEBUG PrintProcAddr(); @@ -24,11 +26,13 @@ BOOL APIENTRY DllMain( HMODULE hModule, break; case DLL_THREAD_DETACH: break; - case DLL_PROCESS_DETACH: { + case DLL_PROCESS_DETACH: + { UnHookAll(); + LOG(INFO) << "Robot Stop"; + google::ShutdownGoogleLogging(); break; } } return TRUE; } - diff --git a/DWeChatRobot/pch.cpp b/DWeChatRobot/pch.cpp index d68cbd6f26618e2e97383808c99f7a59d3a35911..332108d0fa48d8ec5118b760c92c558e9c7df9d5 100644 --- a/DWeChatRobot/pch.cpp +++ b/DWeChatRobot/pch.cpp @@ -304,3 +304,52 @@ DWORD OffsetFromIdaAddr(DWORD idaAddr) { return idaAddr - IDA_BASE; } + +void SignalHandler(const char *data, size_t size) +{ +#ifdef USE_SOCKET + string dllname = "SWeChatRobot"; +#else + string dllname = "DWeChatRobot"; +#endif // USE_SOCKET + char szFileFullPath[MAX_PATH] = {0}; + HMODULE hd = GetModuleHandleA(dllname.c_str()); + GetModuleFileNameA(hd, szFileFullPath, MAX_PATH); + string szFile(szFileFullPath); + size_t pos = szFile.find_last_of('\\'); + string szFilePath = szFile.substr(0, pos + 1); + std::string glog_file = szFilePath + "\\log\\error.log"; + std::ofstream fs(glog_file, std::ios::app); + std::string str = std::string(data, size); + fs << str; + fs.close(); + LOG(INFO) << str; + google::ShutdownGoogleLogging(); +} + +void gLogInit() +{ +#ifdef USE_SOCKET + string dllname = "SWeChatRobot"; +#else + string dllname = "DWeChatRobot"; +#endif // USE_SOCKET +#ifdef _DEBUG + FLAGS_colorlogtostderr = true; // log淇℃伅鍖哄垎棰滆壊 + FLAGS_logtostderr = 1; +#endif + google::SetStderrLogging(google::GLOG_INFO); // 杈撳嚭log鐨勬渶浣庣瓑绾ф槸 INFO (鍙互璁剧疆涓篧ARNING鎴栬呮洿楂) + google::InstallFailureSignalHandler(); // 閰嶇疆瀹夎绋嬪簭宕╂簝澶辫触淇″彿澶勭悊鍣 + google::InstallFailureWriter(&SignalHandler); // 瀹夎閰嶇疆绋嬪簭澶辫触淇″彿鐨勪俊鎭墦鍗拌繃绋嬶紝璁剧疆鍥炶皟鍑芥暟 + google::InitGoogleLogging(dllname.c_str()); +#ifndef _DEBUG + char szFileFullPath[MAX_PATH] = {0}; + HMODULE hd = GetModuleHandleA(dllname.c_str()); + GetModuleFileNameA(hd, szFileFullPath, MAX_PATH); + string szFile(szFileFullPath); + size_t pos = szFile.find_last_of('\\'); + string szFilePath = szFile.substr(0, pos + 1) + "log\\"; + FindOrCreateDirectory(gb2312_to_unicode(szFilePath.c_str()).c_str()); + google::SetLogDestination(google::GLOG_INFO, szFilePath.c_str()); +#endif +} diff --git a/DWeChatRobot/pch.h b/DWeChatRobot/pch.h index 6df5476bb46859ea6bd9de95131f438e771fa64d..9872d9d06ea9664871589d6c8614d729fb1e5e19 100644 --- a/DWeChatRobot/pch.h +++ b/DWeChatRobot/pch.h @@ -8,18 +8,21 @@ #define PCH_H // 娣诲姞瑕佸湪姝ゅ棰勭紪璇戠殑鏍囧ご +#define GLOG_NO_ABBREVIATED_SEVERITIES #include "framework.h" #include #include #include #include #include -#include #include +#include #include #include "wxdata.h" #include "wxapi.h" #include "base64/base64.h" +#include +#pragma comment(lib, "glog.lib") #endif // PCH_H #ifdef USE_SOCKET diff --git a/DWeChatRobot/wxapi.h b/DWeChatRobot/wxapi.h index bfeb81b1689b71e4685d9deda67954c2d967c696..32f40c55cce331748dbc00f4e356cedf8a0184e5 100644 --- a/DWeChatRobot/wxapi.h +++ b/DWeChatRobot/wxapi.h @@ -60,6 +60,7 @@ void PrintProcAddr(); wstring GetTimeW(long long timestamp); BOOL ProcessIsWeChat(); BOOL FindOrCreateDirectory(const wchar_t *pszPath); +void gLogInit(); template vector split(T1 str, T2 letter) diff --git a/README.md b/README.md index 9cb5531b8590b7095372e616fd847cbd6b23977e..37be115f825f816824c1d44881c7e98c7948a26d 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ CWeChatRobot.exe /regserver CWeChatRobot.exe /unregserver ``` # 璋冪敤 -**Python锛** +**Python锛** 鍙傝僛wxRobot.py](/Python/com/wxRobot.py) **C#锛** 鍙傝僛ComWechatRobotCsharp](https://github.com/RingoStudio/ComWechatRobotCsharp)锛屾劅璋RingoStudio 鐨勮础鐚 diff --git a/Release/CWeChatRobot.exe b/Release/CWeChatRobot.exe deleted file mode 100644 index 8ffeb82cc613da300451c65cecfcd18f0bb5be2b..0000000000000000000000000000000000000000 Binary files a/Release/CWeChatRobot.exe and /dev/null differ diff --git a/Release/DWeChatRobot.dll b/Release/DWeChatRobot.dll deleted file mode 100644 index b6ca167a7b5b4e92b1bf0fd8ac587558169b6b89..0000000000000000000000000000000000000000 Binary files a/Release/DWeChatRobot.dll and /dev/null differ diff --git a/Release/WeChatTools.exe b/Release/WeChatTools.exe deleted file mode 100644 index 2cf90716483f00dca4788071249451cfd8f7f9c1..0000000000000000000000000000000000000000 Binary files a/Release/WeChatTools.exe and /dev/null differ diff --git a/Release/socket/SWeChatRobot.dll b/Release/socket/SWeChatRobot.dll deleted file mode 100644 index 6e2d94925fbc1a2ce45b1e8b684cec5e9ef03872..0000000000000000000000000000000000000000 Binary files a/Release/socket/SWeChatRobot.dll and /dev/null differ diff --git a/Release/socket/wxDriver.dll b/Release/socket/wxDriver.dll deleted file mode 100644 index 5b0e826fff16b1fdea90cd69a8e6e9c6a775e7ff..0000000000000000000000000000000000000000 Binary files a/Release/socket/wxDriver.dll and /dev/null differ diff --git a/Release/socket/wxDriver.py b/Release/socket/wxDriver.py deleted file mode 100644 index b65ca66f71994906ac0486a90036e27cf594f899..0000000000000000000000000000000000000000 --- a/Release/socket/wxDriver.py +++ /dev/null @@ -1,306 +0,0 @@ -import ctypes -import json -import copy -import threading -import requests -import base64 -import socketserver - -if ctypes.sizeof(ctypes.c_void_p) == ctypes.sizeof(ctypes.c_ulonglong): - driver = ctypes.cdll.LoadLibrary('./wxDriver64.dll') -else: - driver = ctypes.cdll.LoadLibrary('./wxDriver.dll') - -new_wechat = driver.new_wechat -new_wechat.argtypes = None -new_wechat.restype = ctypes.c_int - -start_listen = driver.start_listen -start_listen.argtypes = [ctypes.c_int,ctypes.c_int] -start_listen.restype = ctypes.c_int - -stop_listen = driver.stop_listen -stop_listen.argtypes = [ctypes.c_int] -stop_listen.restype = ctypes.c_int - -class WECHAT_HTTP_APIS: - # login check - WECHAT_IS_LOGIN = 0 # 鐧诲綍妫鏌 - - # self info - WECHAT_GET_SELF_INFO = 1 # 鑾峰彇涓汉淇℃伅 - - # send message - WECHAT_MSG_SEND_TEXT = 2 # 鍙戦佹枃鏈 - WECHAT_MSG_SEND_AT = 3 # 鍙戦佺兢鑹剧壒 - WECHAT_MSG_SEND_CARD = 4 # 鍒嗕韩濂藉弸鍚嶇墖 - WECHAT_MSG_SEND_IMAGE = 5 # 鍙戦佸浘鐗 - WECHAT_MSG_SEND_FILE = 6 # 鍙戦佹枃浠 - WECHAT_MSG_SEND_ARTICLE = 7 # 鍙戦亁ml鏂囩珷 - WECHAT_MSG_SEND_APP = 8 # 鍙戦佸皬绋嬪簭 - - # receive message - WECHAT_MSG_START_HOOK = 9 # 寮鍚帴鏀舵秷鎭疕OOK锛屽彧鏀寔socket鐩戝惉 - WECHAT_MSG_STOP_HOOK = 10 # 鍏抽棴鎺ユ敹娑堟伅HOOK - WECHAT_MSG_START_IMAGE_HOOK = 11 # 寮鍚浘鐗囨秷鎭疕OOK - WECHAT_MSG_STOP_IMAGE_HOOK = 12 # 鍏抽棴鍥剧墖娑堟伅HOOK - WECHAT_MSG_START_VOICE_HOOK = 13 # 寮鍚闊虫秷鎭疕OOK - WECHAT_MSG_STOP_VOICE_HOOK = 14 # 鍏抽棴璇煶娑堟伅HOOK - - # contact - WECHAT_CONTACT_GET_LIST = 15 # 鑾峰彇鑱旂郴浜哄垪琛 - WECHAT_CONTACT_CHECK_STATUS = 16 # 妫鏌ユ槸鍚﹁濂藉弸鍒犻櫎 - WECHAT_CONTACT_DEL = 17 # 鍒犻櫎濂藉弸 - WECHAT_CONTACT_SEARCH_BY_CACHE = 18 # 浠庡唴瀛樹腑鑾峰彇濂藉弸淇℃伅 - WECHAT_CONTACT_SEARCH_BY_NET = 19 # 缃戠粶鎼滅储鐢ㄦ埛淇℃伅 - WECHAT_CONTACT_ADD_BY_WXID = 20 # wxid鍔犲ソ鍙 - WECHAT_CONTACT_ADD_BY_V3 = 21 # v3鏁版嵁鍔犲ソ鍙 - WECHAT_CONTACT_ADD_BY_PUBLIC_ID = 22 # 鍏虫敞鍏紬鍙 - WECHAT_CONTACT_VERIFY_APPLY = 23 # 閫氳繃濂藉弸璇锋眰 - WECHAT_CONTACT_EDIT_REMARK = 24 # 淇敼澶囨敞 - - # chatroom - WECHAT_CHATROOM_GET_MEMBER_LIST = 25 # 鑾峰彇缇ゆ垚鍛樺垪琛 - WECHAT_CHATROOM_GET_MEMBER_NICKNAME = 26 # 鑾峰彇鎸囧畾缇ゆ垚鍛樻樀绉 - WECHAT_CHATROOM_DEL_MEMBER = 27 # 鍒犻櫎缇ゆ垚鍛 - WECHAT_CHATROOM_ADD_MEMBER = 28 # 娣诲姞缇ゆ垚鍛 - WECHAT_CHATROOM_SET_ANNOUNCEMENT = 29 # 璁剧疆缇ゅ叕鍛 - WECHAT_CHATROOM_SET_CHATROOM_NAME = 30 # 璁剧疆缇よ亰鍚嶇О - WECHAT_CHATROOM_SET_SELF_NICKNAME = 31 # 璁剧疆缇ゅ唴涓汉鏄电О - - # database - WECHAT_DATABASE_GET_HANDLES = 32 # 鑾峰彇鏁版嵁搴撳彞鏌 - WECHAT_DATABASE_BACKUP = 33 # 澶囦唤鏁版嵁搴 - WECHAT_DATABASE_QUERY = 34 # 鏁版嵁搴撴煡璇 - - # version - WECHAT_SET_VERSION = 35 # 淇敼寰俊鐗堟湰鍙 - - # log - WECHAT_LOG_START_HOOK = 36 # 寮鍚棩蹇椾俊鎭疕OOK - WECHAT_LOG_STOP_HOOK = 37 # 鍏抽棴鏃ュ織淇℃伅HOOK - -APIS = WECHAT_HTTP_APIS - -# http api 鍙傛暟妯℃澘 -class WECHAT_HTTP_API_PARAM_TEMPLATES: - __HTTP_API_PARAM_TEMPLATE = { - # login check - APIS.WECHAT_IS_LOGIN: {}, - - - # self info - APIS.WECHAT_GET_SELF_INFO: {}, - - - # send message - APIS.WECHAT_MSG_SEND_TEXT: {"wxid": "", - "msg": ""}, - # wxids闇瑕佷互`,`鍒嗛殧锛屼緥濡俙wxid1,wxid2,wxid3` - APIS.WECHAT_MSG_SEND_AT: {"chatroom_id":"", - "wxids": "", - "msg": "", - "auto_nickname": 1}, - APIS.WECHAT_MSG_SEND_CARD: {"receiver":"", - "shared_wxid":"", - "nickname":""}, - APIS.WECHAT_MSG_SEND_IMAGE: {"receiver":"", - "img_path":""}, - APIS.WECHAT_MSG_SEND_FILE: {"receiver":"", - "file_path":""}, - APIS.WECHAT_MSG_SEND_ARTICLE: {"wxid":"", - "title":"", - "abstract":"", - "url":"", - "img_path":""}, - APIS.WECHAT_MSG_SEND_APP: {"wxid":"", - "appid":""}, - - - # receive message - APIS.WECHAT_MSG_START_HOOK: {"port": 10808}, - APIS.WECHAT_MSG_STOP_HOOK: {}, - APIS.WECHAT_MSG_START_IMAGE_HOOK: {"save_path":""}, - APIS.WECHAT_MSG_STOP_IMAGE_HOOK: {}, - APIS.WECHAT_MSG_START_VOICE_HOOK: {"save_path":""}, - APIS.WECHAT_MSG_STOP_VOICE_HOOK: {}, - - - # contact - APIS.WECHAT_CONTACT_GET_LIST: {}, - APIS.WECHAT_CONTACT_CHECK_STATUS: {"wxid":""}, - APIS.WECHAT_CONTACT_DEL: {"wxid":""}, - APIS.WECHAT_CONTACT_SEARCH_BY_CACHE: {"wxid":""}, - APIS.WECHAT_CONTACT_SEARCH_BY_NET: {"keyword":""}, - APIS.WECHAT_CONTACT_ADD_BY_WXID: {"wxid":"", - "msg":""}, - APIS.WECHAT_CONTACT_ADD_BY_V3: {"v3":"", - "msg":"", - "add_type": 0x6}, - APIS.WECHAT_CONTACT_ADD_BY_PUBLIC_ID: {"public_id":""}, - APIS.WECHAT_CONTACT_VERIFY_APPLY: {"v3":"", - "v4":""}, - APIS.WECHAT_CONTACT_EDIT_REMARK: {"wxid":"", - "remark":""}, - - - # chatroom - APIS.WECHAT_CHATROOM_GET_MEMBER_LIST: {"chatroom_id":""}, - APIS.WECHAT_CHATROOM_GET_MEMBER_NICKNAME: {"chatroom_id":"", - "wxid":""}, - # wxids闇瑕佷互`,`鍒嗛殧锛屼緥濡俙wxid1,wxid2,wxid3` - APIS.WECHAT_CHATROOM_DEL_MEMBER: {"chatroom_id":"", - "wxids":""}, - # wxids闇瑕佷互`,`鍒嗛殧锛屼緥濡俙wxid1,wxid2,wxid3` - APIS.WECHAT_CHATROOM_ADD_MEMBER: {"chatroom_id":"", - "wxids":""}, - APIS.WECHAT_CHATROOM_SET_ANNOUNCEMENT: {"chatroom_id":"", - "announcement":""}, - APIS.WECHAT_CHATROOM_SET_CHATROOM_NAME: {"chatroom_id":"", - "chatroom_name":""}, - APIS.WECHAT_CHATROOM_SET_SELF_NICKNAME: {"chatroom_id":"", - "nickname":""}, - - - # database - APIS.WECHAT_DATABASE_GET_HANDLES: {}, - APIS.WECHAT_DATABASE_BACKUP: {"db_handle":0, - "save_path":""}, - APIS.WECHAT_DATABASE_QUERY: {"db_handle":0, - "sql":""}, - - - # version - APIS.WECHAT_SET_VERSION: {"version": "3.7.0.30"}, - - - # log - APIS.WECHAT_LOG_START_HOOK: {}, - APIS.WECHAT_LOG_STOP_HOOK: {}, - } - - def get_http_template(self, api_number): - try: - return copy.deepcopy(self.__HTTP_API_PARAM_TEMPLATE[api_number]) - except KeyError: - raise ValueError("There is no interface numbered %s." % api_number) - -get_http_template = WECHAT_HTTP_API_PARAM_TEMPLATES().get_http_template - -class ReceiveMsgSocketServer(socketserver.BaseRequestHandler): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - def handle(self): - conn = self.request - while True: - try: - ptr_data = b"" - while True: - data = conn.recv(1024) - ptr_data += data - if len(data) == 0 or data[-1] == 0xA: - break - msg = json.loads(ptr_data.decode('utf-8')) - ReceiveMsgSocketServer.msg_callback(msg) - except OSError: - break - except json.JSONDecodeError: - pass - conn.sendall("200 OK".encode()) - conn.close() - - @staticmethod - def msg_callback(msg): - # 闄勫姞淇℃伅鏄痯rotobuf鏍煎紡锛岄渶瑕佽嚜琛屽鐞 - msg['extrainfo'] = base64.b64decode(msg['extrainfo']) - # TODO: 鍦ㄨ繖閲屽啓棰濆鐨勬秷鎭鐞嗛昏緫 - - print(msg) - -def post_wechat_http_api(api,port,data = {}): - url = "http://127.0.0.1:{}/api/?type={}".format(port,api) - resp = requests.post(url = url,data = json.dumps(data)) - return resp.json() - -def get_wechat_http_api(api,port,data = {}): - url = "http://127.0.0.1:{}/api/?type={}".format(port,api) - resp = requests.get(url = url,params = data) - return resp.json() - -def get_wechat_pid_list() -> list: - import psutil - pid_list = [] - process_list = psutil.pids() - for pid in process_list: - try: - if psutil.Process(pid).name() == 'WeChat.exe': - pid_list.append(pid) - except psutil.NoSuchProcess: - pass - return pid_list - -def start_socket_server(port: int = 10808, - request_handler = ReceiveMsgSocketServer, - main_thread: bool = True) -> int or None: - ip_port = ("127.0.0.1", port) - try: - s = socketserver.ThreadingTCPServer(ip_port, request_handler) - if main_thread: - s.serve_forever() - else: - socket_server = threading.Thread(target=s.serve_forever) - socket_server.setDaemon(True) - socket_server.start() - return socket_server.ident - except KeyboardInterrupt: - pass - except Exception as e: - print(e) - return None - -def test(test_port): - post_wechat_http_api(APIS.WECHAT_LOG_START_HOOK,port = test_port) - if post_wechat_http_api(APIS.WECHAT_IS_LOGIN,port = test_port)["is_login"] == 1: - print(post_wechat_http_api(APIS.WECHAT_GET_SELF_INFO,port = test_port)) - - data = {"wxid":"filehelper","msg":"hello http"} - post_wechat_http_api(APIS.WECHAT_MSG_SEND_TEXT,data = data,port = test_port) - - data = {"receiver":'filehelper',"shared_wxid":"filehelper","nickname":"鏂囦欢浼犺緭鍔╂墜"} - post_wechat_http_api(APIS.WECHAT_MSG_SEND_CARD,data = data,port = test_port) - - data = {"receiver":'filehelper',"img_path":r"D:\VS2019C++\MyWeChatRobot\test\娴嬭瘯鍥剧墖.png"} - post_wechat_http_api(APIS.WECHAT_MSG_SEND_IMAGE,data = data,port = test_port) - - data = {"receiver":'filehelper',"file_path":r"D:\VS2019C++\MyWeChatRobot\test\娴嬭瘯鏂囦欢"} - post_wechat_http_api(APIS.WECHAT_MSG_SEND_FILE,data = data,port = test_port) - - data = {"wxid":'filehelper', - "title":"鐧惧害", - "abstract":"鐧惧害涓涓嬶紝浣犲氨鐭ラ亾", - "url":"https://www.baidu.com/", - "img_path":""} - post_wechat_http_api(APIS.WECHAT_MSG_SEND_ARTICLE,data = data,port = test_port) - - print(post_wechat_http_api(APIS.WECHAT_CONTACT_GET_LIST,port = test_port)) - data = {"wxid":"filehelper"} - print(post_wechat_http_api(APIS.WECHAT_CONTACT_CHECK_STATUS,data = data,port = test_port)) - dbs = post_wechat_http_api(APIS.WECHAT_DATABASE_GET_HANDLES,port = test_port) - db_handle = dbs['data'][0]['handle'] - sql = "select * from Contact limit 1;" - data = {"db_handle":db_handle,"sql":sql} - res = post_wechat_http_api(APIS.WECHAT_DATABASE_QUERY,data = data,port = test_port) - print(res) - post_wechat_http_api(APIS.WECHAT_LOG_STOP_HOOK,port = test_port) - -if __name__ == '__main__': - port = 8000 - pids = get_wechat_pid_list() - if len(pids) == 0: - pids.append(new_wechat()) - start_listen(pids[0],port) - post_wechat_http_api(APIS.WECHAT_LOG_START_HOOK,8000) - post_wechat_http_api(APIS.WECHAT_MSG_START_HOOK,8000,{"port":10808}) - start_socket_server() - stop_listen(pids[0]) diff --git a/Release/socket/wxDriver64.dll b/Release/socket/wxDriver64.dll deleted file mode 100644 index 16f279adce0a1768bc05bb5af582997cedb35cf9..0000000000000000000000000000000000000000 Binary files a/Release/socket/wxDriver64.dll and /dev/null differ