OR-Tools  8.2
base/logging.cc
Go to the documentation of this file.
1// Copyright 2010-2018 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#define _GNU_SOURCE 1 // needed for O_NOFOLLOW and pread()/pwrite()
17
18#include <algorithm>
19#include <cassert>
20#include <iomanip>
21#include <mutex> // for std::call_once and std::once_flag. // NOLINT
22#include <string>
23
24#if defined(_MSC_VER)
25#include <io.h> // lseek
26#include <string.h> /* for _strnicmp(), strerror_s() */
27#include <time.h> /* for localtime_s() */
28#include <windows.h>
29#else
30#include <pwd.h>
31#include <sys/utsname.h> // For uname.
32#include <syslog.h>
33#include <unistd.h> // For _exit.
34#endif
35#include <errno.h> // for errno
36#include <fcntl.h>
37#include <stdarg.h>
38#include <stdlib.h>
39#include <sys/stat.h>
40#include <sys/types.h>
41
42#include <climits>
43#include <cstdio>
44#include <iostream>
45#include <sstream>
46#include <vector>
47
48#include "absl/debugging/stacktrace.h"
49#include "absl/time/time.h"
53
54ABSL_DECLARE_FLAG(bool, log_prefix);
55ABSL_DECLARE_FLAG(bool, logtostderr);
56
57namespace {
58std::once_flag init_done;
59} // namespace
60
62 std::call_once(init_done, [] { google::InitGoogleLogging("swig_helper"); });
63 absl::SetFlag(&FLAGS_logtostderr, true);
64 absl::SetFlag(&FLAGS_log_prefix, false);
65}
66
67using std::dec;
68using std::hex;
69using std::min;
70using std::ostream;
71using std::ostringstream;
72using std::setfill;
73using std::setw;
74using std::string;
75using std::vector;
76
77using std::fclose;
78using std::fflush;
79using std::FILE;
80using std::fprintf;
81using std::fwrite;
82using std::perror;
83
84#ifdef _WIN32
85#define fdopen _fdopen
86#define strcasecmp _stricmp
87#endif
88
89#if defined(_MSC_VER)
90#ifndef __MINGW32__
91enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
92#endif
93
94inline char* strerror_r(int errnum, char* buf, size_t buflen) {
95 strerror_s(buf, buflen, errnum);
96 return buf;
97}
98
99inline struct tm* localtime_r(const time_t* timep, struct tm* result) {
100 localtime_s(result, timep);
101 return result;
102}
103#endif
104
105ABSL_FLAG(bool, logtostderr, false,
106 "log messages go to stderr instead of logfiles");
107ABSL_FLAG(bool, alsologtostderr, false,
108 "log messages go to stderr in addition to logfiles");
109ABSL_FLAG(bool, colorlogtostderr, false,
110 "color messages logged to stderr (if supported by terminal)");
111#if defined(__linux__)
112ABSL_FLAG(bool, drop_log_memory, true,
113 "Drop in-memory buffers of log contents. "
114 "Logs can grow very quickly and they are rarely read before they "
115 "need to be evicted from memory. Instead, drop them from memory "
116 "as soon as they are flushed to disk.");
117#endif
118
119// By default, errors (including fatal errors) get logged to stderr as
120// well as the file.
121//
122// The default is ERROR instead of FATAL so that users can see problems
123// when they run a program without having to look in another file.
124ABSL_FLAG(int, stderrthreshold, google::GLOG_ERROR,
125 "log messages at or above this level are copied to stderr in "
126 "addition to logfiles. This flag obsoletes --alsologtostderr.");
127
128ABSL_FLAG(bool, log_prefix, true,
129 "Prepend the log prefix to the start of each log line");
130ABSL_FLAG(int, minloglevel, 0,
131 "Messages logged at a lower level than this don't "
132 "actually get logged anywhere");
133ABSL_FLAG(int, logbuflevel, 0,
134 "Buffer log messages logged at this level or lower"
135 " (-1 means don't buffer; 0 means buffer INFO only;"
136 " ...)");
137ABSL_FLAG(int, logbufsecs, 30,
138 "Buffer log messages for at most this many seconds");
139
140// Compute the default value for --log_dir
141static const char* DefaultLogDir() {
142 const char* env;
143 env = getenv("GOOGLE_LOG_DIR");
144 if (env != NULL && env[0] != '\0') {
145 return env;
146 }
147 env = getenv("TEST_TMPDIR");
148 if (env != NULL && env[0] != '\0') {
149 return env;
150 }
151 return "";
152}
153
154ABSL_FLAG(int, logfile_mode, 0664, "Log file mode/permissions.");
155
156ABSL_FLAG(std::string, log_dir, DefaultLogDir(),
157 "If specified, logfiles are written into this directory instead "
158 "of the default logging directory.");
159ABSL_FLAG(std::string, log_link, "",
160 "Put additional links to the log "
161 "files in this directory");
162
163ABSL_FLAG(int, max_log_size, 1800,
164 "approx. maximum log file size (in MB). A value of 0 will "
165 "be silently overridden to 1.");
166
167ABSL_FLAG(bool, stop_logging_if_full_disk, false,
168 "Stop attempting to log to disk if the disk is full.");
169
170ABSL_FLAG(std::string, log_backtrace_at, "",
171 "Emit a backtrace when logging at file:linenum.");
172
173#if defined(_MSC_VER)
174#define PATH_SEPARATOR '\\'
175#else
176#define PATH_SEPARATOR '/'
177#endif
178
179#ifdef _MSC_VER
180#include <basetsd.h>
181#define ssize_t SSIZE_T
182static ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
183 off_t orig_offset = lseek(fd, 0, SEEK_CUR);
184 if (orig_offset == (off_t)-1) return -1;
185 if (lseek(fd, offset, SEEK_CUR) == (off_t)-1) return -1;
186 ssize_t len = read(fd, buf, count);
187 if (len < 0) return len;
188 if (lseek(fd, orig_offset, SEEK_SET) == (off_t)-1) return -1;
189 return len;
190}
191
192static ssize_t pwrite(int fd, void* buf, size_t count, off_t offset) {
193 off_t orig_offset = lseek(fd, 0, SEEK_CUR);
194 if (orig_offset == (off_t)-1) return -1;
195 if (lseek(fd, offset, SEEK_CUR) == (off_t)-1) return -1;
196 ssize_t len = write(fd, buf, count);
197 if (len < 0) return len;
198 if (lseek(fd, orig_offset, SEEK_SET) == (off_t)-1) return -1;
199 return len;
200}
201#endif // _MSC_VER
202
203static void GetHostName(string* hostname) {
204#if !defined(_MSC_VER)
205 struct utsname buf;
206 if (0 != uname(&buf)) {
207 // ensure null termination on failure
208 *buf.nodename = '\0';
209 }
210 *hostname = buf.nodename;
211#else // _MSC_VER
212 char buf[MAX_COMPUTERNAME_LENGTH + 1];
213 DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
214 if (GetComputerNameA(buf, &len)) {
215 *hostname = buf;
216 } else {
217 hostname->clear();
218 }
219#endif // _MSC_VER
220}
221
222// Returns true iff terminal supports using colors in output.
224 bool term_supports_color = false;
225#ifdef _MSC_VER
226 // on Windows TERM variable is usually not set, but the console does
227 // support colors.
228 term_supports_color = true;
229#else
230 // On non-Windows platforms, we rely on the TERM variable.
231 const char* const term = getenv("TERM");
232 if (term != NULL && term[0] != '\0') {
233 term_supports_color =
234 !strcmp(term, "xterm") || !strcmp(term, "xterm-color") ||
235 !strcmp(term, "xterm-256color") || !strcmp(term, "screen-256color") ||
236 !strcmp(term, "konsole") || !strcmp(term, "konsole-16color") ||
237 !strcmp(term, "konsole-256color") || !strcmp(term, "screen") ||
238 !strcmp(term, "linux") || !strcmp(term, "cygwin");
239 }
240#endif
241 return term_supports_color;
242}
243
244namespace google {
245
247
249 assert(severity >= 0 && severity < NUM_SEVERITIES);
250 GLogColor color = COLOR_DEFAULT;
251 switch (severity) {
252 case GLOG_INFO:
253 color = COLOR_DEFAULT;
254 break;
255 case GLOG_WARNING:
256 color = COLOR_YELLOW;
257 break;
258 case GLOG_ERROR:
259 case GLOG_FATAL:
260 color = COLOR_RED;
261 break;
262 default:
263 // should never get here.
264 assert(false);
265 }
266 return color;
267}
268
269#ifdef _MSC_VER
270
271// Returns the character attribute for the given color.
272static WORD GetColorAttribute(GLogColor color) {
273 switch (color) {
274 case COLOR_RED:
275 return FOREGROUND_RED;
276 case COLOR_GREEN:
277 return FOREGROUND_GREEN;
278 case COLOR_YELLOW:
279 return FOREGROUND_RED | FOREGROUND_GREEN;
280 default:
281 return 0;
282 }
283}
284
285#else // _MSC_VER
286
287// Returns the ANSI color code for the given color.
288static const char* GetAnsiColorCode(GLogColor color) {
289 switch (color) {
290 case COLOR_RED:
291 return "1";
292 case COLOR_GREEN:
293 return "2";
294 case COLOR_YELLOW:
295 return "3";
296 case COLOR_DEFAULT:
297 return "";
298 }
299 return NULL; // stop warning about return type.
300}
301
302#endif // !_MSC_VER
303
304// Safely get max_log_size, overriding to 1 if it somehow gets defined as 0
306 return (absl::GetFlag(FLAGS_max_log_size) > 0
307 ? absl::GetFlag(FLAGS_max_log_size)
308 : 1);
309}
310
311// An arbitrary limit on the length of a single log message. This
312// is so that streaming can be done more efficiently.
313const size_t LogMessage::kMaxLogMessageLen = 30000;
314
317
318 int preserved_errno_; // preserved errno
319 // Buffer space; contains complete message text.
322 char severity_; // What level is this LogMessage logged at?
323 int line_; // line number where logging call is.
324 void (LogMessage::*send_method_)(); // Call this in destructor to send
325 union { // At most one of these is used: union to keep the size low.
326 LogSink* sink_; // NULL or sink to send message to
327 std::vector<std::string>* outvec_; // NULL or vector to push message onto
328 std::string* message_; // NULL or string to write message into
329 };
330 time_t timestamp_; // Time of creation of LogMessage
331 struct ::tm tm_time_; // Time of creation of LogMessage
332 size_t num_prefix_chars_; // # of chars of prefix in this message
333 size_t num_chars_to_log_; // # of chars of msg to send to log
334 size_t num_chars_to_syslog_; // # of chars of msg to send to syslog
335 const char* basename_; // basename of file that called LOG
336 const char* fullname_; // fullname of file that called LOG
337 bool has_been_flushed_; // false => data has not been flushed
338 bool first_fatal_; // true => this was first fatal msg
339
340 private:
342 void operator=(const LogMessageData&);
343};
344
345// A absl::Mutex that allows only one thread to log at a time, to keep things
346// from getting jumbled. Some other very uncommon logging operations (like
347// changing the destination file for log messages of a given severity) also
348// lock this absl::Mutex. Please be sure that anybody who might possibly need
349// to lock it does so.
350static absl::Mutex log_mutex;
351
352// Number of messages sent at each severity. Under log_mutex.
353int64 LogMessage::num_messages_[NUM_SEVERITIES] = {0, 0, 0, 0};
354
355// Globally disable log writing (if disk is full)
356static bool stop_writing = false;
357
358const char* const LogSeverityNames[NUM_SEVERITIES] = {"INFO", "WARNING",
359 "ERROR", "FATAL"};
360
361// Has the user called SetExitOnDFatal(true)?
362static bool exit_on_dfatal = true;
363
364const char* GetLogSeverityName(LogSeverity severity) {
365 return LogSeverityNames[severity];
366}
367
369
370namespace {
371
372// Encapsulates all file-system related state
373class LogFileObject : public base::Logger {
374 public:
375 LogFileObject(LogSeverity severity, const char* base_filename);
376 ~LogFileObject();
377
378 virtual void Write(bool force_flush, // Should we force a flush here?
379 time_t timestamp, // Timestamp for this entry
380 const char* message, int message_len);
381
382 // Configuration options
383 void SetBasename(const char* basename);
384 void SetExtension(const char* ext);
385 void SetSymlinkBasename(const char* symlink_basename);
386
387 // Normal flushing routine
388 virtual void Flush();
389
390 // It is the actual file length for the system loggers,
391 // i.e., INFO, ERROR, etc.
392 virtual uint32 LogSize() {
393 absl::MutexLock l(&lock_);
394 return file_length_;
395 }
396
397 // Internal flush routine. Exposed so that FlushLogFilesUnsafe()
398 // can avoid grabbing a lock. Usually Flush() calls it after
399 // acquiring lock_.
400 void FlushUnlocked();
401
402 private:
403 static const uint32 kRolloverAttemptFrequency = 0x20;
404
405 absl::Mutex lock_;
406 bool base_filename_selected_;
407 string base_filename_;
408 string symlink_basename_;
409 string filename_extension_; // option users can specify (eg to add port#)
410 FILE* file_;
411 LogSeverity severity_;
412 uint32 bytes_since_flush_;
413 uint32 dropped_mem_length_;
414 uint32 file_length_;
415 unsigned int rollover_attempt_;
416 int64 next_flush_time_; // cycle count at which to flush log
417
418 // Actually create a logfile using the value of base_filename_ and the
419 // supplied argument time_pid_string
420 // REQUIRES: lock_ is held
421 bool CreateLogfile(const string& time_pid_string);
422};
423
424} // namespace
425
427 public:
428 friend class LogMessage;
429 friend void ReprintFatalMessage();
432
433 // These methods are just forwarded to by their global versions.
434 static void SetLogDestination(LogSeverity severity,
435 const char* base_filename);
436 static void SetLogSymlink(LogSeverity severity, const char* symlink_basename);
437 static void AddLogSink(LogSink* destination);
438 static void RemoveLogSink(LogSink* destination);
439 static void SetLogFilenameExtension(const char* filename_extension);
440 static void SetStderrLogging(LogSeverity min_severity);
441 static void LogToStderr();
442 // Flush all log files that are at least at the given severity level
443 static void FlushLogFiles(int min_severity);
444 static void FlushLogFilesUnsafe(int min_severity);
445
446 // we set the maximum size of our packet to be 1400, the logic being
447 // to prevent fragmentation.
448 // Really this number is arbitrary.
449 static const int kNetworkBytes = 1400;
450
451 static const string& hostname();
452 static const bool& terminal_supports_color() {
453 return terminal_supports_color_;
454 }
455
456 static void DeleteLogDestinations();
457
458 private:
459 LogDestination(LogSeverity severity, const char* base_filename);
460 ~LogDestination() {}
461
462 // Take a log message of a particular severity and log it to stderr
463 // iff it's of a high enough severity to deserve it.
464 static void MaybeLogToStderr(LogSeverity severity, const char* message,
465 size_t len);
466
467 // Take a log message of a particular severity and log it to a file
468 // iff the base filename is not "" (which means "don't log to me")
469 static void MaybeLogToLogfile(LogSeverity severity, time_t timestamp,
470 const char* message, size_t len);
471 // Take a log message of a particular severity and log it to the file
472 // for that severity and also for all files with severity less than
473 // this severity.
474 static void LogToAllLogfiles(LogSeverity severity, time_t timestamp,
475 const char* message, size_t len);
476
477 // Send logging info to all registered sinks.
478 static void LogToSinks(LogSeverity severity, const char* full_filename,
479 const char* base_filename, int line,
480 const struct ::tm* tm_time, const char* message,
481 size_t message_len);
482
483 // Wait for all registered sinks via WaitTillSent
484 // including the optional one in "data".
485 static void WaitForSinks(LogMessage::LogMessageData* data);
486
487 static LogDestination* log_destination(LogSeverity severity);
488
489 LogFileObject fileobject_;
490 base::Logger* logger_; // Either &fileobject_, or wrapper around it
491
492 static LogDestination* log_destinations_[NUM_SEVERITIES];
493 static string addresses_;
494 static string hostname_;
495 static bool terminal_supports_color_;
496
497 // arbitrary global logging destinations.
498 static vector<LogSink*>* sinks_;
499
500 // Protects the vector sinks_,
501 // but not the LogSink objects its elements reference.
502 static absl::Mutex sink_mutex_;
503
504 // Disallow
505 LogDestination(const LogDestination&);
506 LogDestination& operator=(const LogDestination&);
507};
508
509string LogDestination::addresses_; // NOLINT
510string LogDestination::hostname_; // NOLINT
511
512vector<LogSink*>* LogDestination::sinks_ = NULL;
513absl::Mutex LogDestination::sink_mutex_;
514bool LogDestination::terminal_supports_color_ = TerminalSupportsColor();
515
516/* static */
518 if (hostname_.empty()) {
519 GetHostName(&hostname_);
520 if (hostname_.empty()) {
521 hostname_ = "(unknown)";
522 }
523 }
524 return hostname_;
525}
526
527LogDestination::LogDestination(LogSeverity severity, const char* base_filename)
528 : fileobject_(severity, base_filename), logger_(&fileobject_) {}
529
530inline void LogDestination::FlushLogFilesUnsafe(int min_severity) {
531 // assume we have the log_mutex or we simply don't care
532 // about it
533 for (int i = min_severity; i < NUM_SEVERITIES; i++) {
534 LogDestination* log = log_destinations_[i];
535 if (log != NULL) {
536 // Flush the base fileobject_ logger directly instead of going
537 // through any wrappers to reduce chance of deadlock.
538 log->fileobject_.FlushUnlocked();
539 }
540 }
541}
542
543inline void LogDestination::FlushLogFiles(int min_severity) {
544 // Prevent any subtle race conditions by wrapping a absl::Mutex lock around
545 // all this stuff.
546 absl::MutexLock l(&log_mutex);
547 for (int i = min_severity; i < NUM_SEVERITIES; i++) {
548 LogDestination* log = log_destination(i);
549 if (log != NULL) {
550 log->logger_->Flush();
551 }
552 }
553}
554
556 const char* base_filename) {
557 assert(severity >= 0 && severity < NUM_SEVERITIES);
558 // Prevent any subtle race conditions by wrapping a absl::Mutex lock around
559 // all this stuff.
560 absl::MutexLock l(&log_mutex);
561 log_destination(severity)->fileobject_.SetBasename(base_filename);
562}
563
565 const char* symlink_basename) {
566 CHECK_GE(severity, 0);
567 CHECK_LT(severity, NUM_SEVERITIES);
568 absl::MutexLock l(&log_mutex);
569 log_destination(severity)->fileobject_.SetSymlinkBasename(symlink_basename);
570}
571
572inline void LogDestination::AddLogSink(LogSink* destination) {
573 // Prevent any subtle race conditions by wrapping a absl::Mutex lock around
574 // all this stuff.
575 absl::MutexLock l(&sink_mutex_);
576 if (!sinks_) sinks_ = new vector<LogSink*>;
577 sinks_->push_back(destination);
578}
579
580inline void LogDestination::RemoveLogSink(LogSink* destination) {
581 // Prevent any subtle race conditions by wrapping a absl::Mutex lock around
582 // all this stuff.
583 absl::MutexLock l(&sink_mutex_);
584 // This doesn't keep the sinks in order, but who cares?
585 if (sinks_) {
586 for (int i = sinks_->size() - 1; i >= 0; i--) {
587 if ((*sinks_)[i] == destination) {
588 (*sinks_)[i] = (*sinks_)[sinks_->size() - 1];
589 sinks_->pop_back();
590 break;
591 }
592 }
593 }
594}
595
596inline void LogDestination::SetLogFilenameExtension(const char* ext) {
597 // Prevent any subtle race conditions by wrapping a absl::Mutex lock around
598 // all this stuff.
599 absl::MutexLock l(&log_mutex);
600 for (int severity = 0; severity < NUM_SEVERITIES; ++severity) {
601 log_destination(severity)->fileobject_.SetExtension(ext);
602 }
603}
604
606 assert(min_severity >= 0 && min_severity < NUM_SEVERITIES);
607 // Prevent any subtle race conditions by wrapping a absl::Mutex lock around
608 // all this stuff.
609 absl::MutexLock l(&log_mutex);
610 absl::SetFlag(&FLAGS_stderrthreshold, min_severity);
611}
612
614 // *Don't* put this stuff in a absl::Mutex lock, since SetStderrLogging &
615 // SetLogDestination already do the locking!
616 SetStderrLogging(0); // thus everything is "also" logged to stderr
617 for (int i = 0; i < NUM_SEVERITIES; ++i) {
618 SetLogDestination(i, ""); // "" turns off logging to a logfile
619 }
620}
621
622static void ColoredWriteToStderr(LogSeverity severity, const char* message,
623 size_t len) {
625 absl::GetFlag(FLAGS_colorlogtostderr))
626 ? SeverityToColor(severity)
628
629 // Avoid using cerr from this module since we may get called during
630 // exit code, and cerr may be partially or fully destroyed by then.
631 if (COLOR_DEFAULT == color) {
632 fwrite(message, len, 1, stderr);
633 return;
634 }
635#ifdef _MSC_VER
636 const HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
637
638 // Gets the current text color.
639 CONSOLE_SCREEN_BUFFER_INFO buffer_info;
640 GetConsoleScreenBufferInfo(stderr_handle, &buffer_info);
641 const WORD old_color_attrs = buffer_info.wAttributes;
642
643 // We need to flush the stream buffers into the console before each
644 // SetConsoleTextAttribute call lest it affect the text that is already
645 // printed but has not yet reached the console.
646 fflush(stderr);
647 SetConsoleTextAttribute(stderr_handle,
648 GetColorAttribute(color) | FOREGROUND_INTENSITY);
649 fwrite(message, len, 1, stderr);
650 fflush(stderr);
651 // Restores the text color.
652 SetConsoleTextAttribute(stderr_handle, old_color_attrs);
653#else // !_MSC_VER
654 fprintf(stderr, "\033[0;3%sm", GetAnsiColorCode(color));
655 fwrite(message, len, 1, stderr);
656 fprintf(stderr, "\033[m"); // Resets the terminal to default.
657#endif // !_MSC_VER
658}
659
660static void WriteToStderr(const char* message, size_t len) {
661 // Avoid using cerr from this module since we may get called during
662 // exit code, and cerr may be partially or fully destroyed by then.
663 fwrite(message, len, 1, stderr);
664}
665
666inline void LogDestination::MaybeLogToStderr(LogSeverity severity,
667 const char* message, size_t len) {
668 if ((severity >= absl::GetFlag(FLAGS_stderrthreshold)) ||
669 absl::GetFlag(FLAGS_alsologtostderr)) {
670 ColoredWriteToStderr(severity, message, len);
671#ifdef _MSC_VER
672 // On Windows, also output to the debugger
673 ::OutputDebugStringA(string(message, len).c_str());
674#endif
675 }
676}
677
678inline void LogDestination::MaybeLogToLogfile(LogSeverity severity,
679 time_t timestamp,
680 const char* message, size_t len) {
681 const bool should_flush = severity > absl::GetFlag(FLAGS_logbuflevel);
682 LogDestination* destination = log_destination(severity);
683 destination->logger_->Write(should_flush, timestamp, message, len);
684}
685
686inline void LogDestination::LogToAllLogfiles(LogSeverity severity,
687 time_t timestamp,
688 const char* message, size_t len) {
689 if (absl::GetFlag(FLAGS_logtostderr)) { // global flag: never log to file
690 ColoredWriteToStderr(severity, message, len);
691 } else {
692 for (int i = severity; i >= 0; --i)
693 LogDestination::MaybeLogToLogfile(i, timestamp, message, len);
694 }
695}
696
697inline void LogDestination::LogToSinks(LogSeverity severity,
698 const char* full_filename,
699 const char* base_filename, int line,
700 const struct ::tm* tm_time,
701 const char* message,
702 size_t message_len) {
703 absl::ReaderMutexLock l(&sink_mutex_);
704 if (sinks_) {
705 for (int i = sinks_->size() - 1; i >= 0; i--) {
706 (*sinks_)[i]->send(severity, full_filename, base_filename, line, tm_time,
707 message, message_len);
708 }
709 }
710}
711
712inline void LogDestination::WaitForSinks(LogMessage::LogMessageData* data) {
713 absl::ReaderMutexLock l(&sink_mutex_);
714 if (sinks_) {
715 for (int i = sinks_->size() - 1; i >= 0; i--) {
716 (*sinks_)[i]->WaitTillSent();
717 }
718 }
719 const bool send_to_sink =
720 (data->send_method_ == &LogMessage::SendToSink) ||
721 (data->send_method_ == &LogMessage::SendToSinkAndLog);
722 if (send_to_sink && data->sink_ != NULL) {
723 data->sink_->WaitTillSent();
724 }
725}
726
727LogDestination* LogDestination::log_destinations_[NUM_SEVERITIES];
728
729inline LogDestination* LogDestination::log_destination(LogSeverity severity) {
730 assert(severity >= 0 && severity < NUM_SEVERITIES);
731 if (!log_destinations_[severity]) {
732 log_destinations_[severity] = new LogDestination(severity, NULL);
733 }
734 return log_destinations_[severity];
735}
736
738 for (int severity = 0; severity < NUM_SEVERITIES; ++severity) {
739 delete log_destinations_[severity];
740 log_destinations_[severity] = NULL;
741 }
742 absl::MutexLock l(&sink_mutex_);
743 delete sinks_;
744 sinks_ = NULL;
745}
746
747namespace {
748
749LogFileObject::LogFileObject(LogSeverity severity, const char* base_filename)
750 : base_filename_selected_(base_filename != NULL),
751 base_filename_((base_filename != NULL) ? base_filename : ""),
752 symlink_basename_(logging_internal::ProgramInvocationShortName()),
753 filename_extension_(),
754 file_(NULL),
755 severity_(severity),
756 bytes_since_flush_(0),
757 dropped_mem_length_(0),
758 file_length_(0),
759 rollover_attempt_(kRolloverAttemptFrequency - 1),
760 next_flush_time_(0) {
761 assert(severity >= 0);
762 assert(severity < NUM_SEVERITIES);
763}
764
765LogFileObject::~LogFileObject() {
766 absl::MutexLock l(&lock_);
767 if (file_ != NULL) {
768 fclose(file_);
769 file_ = NULL;
770 }
771}
772
773void LogFileObject::SetBasename(const char* basename) {
774 absl::MutexLock l(&lock_);
775 base_filename_selected_ = true;
776 if (base_filename_ != basename) {
777 // Get rid of old log file since we are changing names
778 if (file_ != NULL) {
779 fclose(file_);
780 file_ = NULL;
781 rollover_attempt_ = kRolloverAttemptFrequency - 1;
782 }
783 base_filename_ = basename;
784 }
785}
786
787void LogFileObject::SetExtension(const char* ext) {
788 absl::MutexLock l(&lock_);
789 if (filename_extension_ != ext) {
790 // Get rid of old log file since we are changing names
791 if (file_ != NULL) {
792 fclose(file_);
793 file_ = NULL;
794 rollover_attempt_ = kRolloverAttemptFrequency - 1;
795 }
796 filename_extension_ = ext;
797 }
798}
799
800void LogFileObject::SetSymlinkBasename(const char* symlink_basename) {
801 absl::MutexLock l(&lock_);
802 symlink_basename_ = symlink_basename;
803}
804
805void LogFileObject::Flush() {
806 absl::MutexLock l(&lock_);
807 FlushUnlocked();
808}
809
810void LogFileObject::FlushUnlocked() {
811 if (file_ != NULL) {
812 fflush(file_);
813 bytes_since_flush_ = 0;
814 }
815 // Figure out when we are due for another flush.
816 const int64 next = (absl::GetFlag(FLAGS_logbufsecs) *
817 static_cast<int64>(1000000)); // in usec
818 next_flush_time_ =
820}
821
822bool LogFileObject::CreateLogfile(const string& time_pid_string) {
823 string string_filename =
824 base_filename_ + filename_extension_ + time_pid_string;
825 const char* filename = string_filename.c_str();
826 int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL,
827 absl::GetFlag(FLAGS_logfile_mode));
828 if (fd == -1) return false;
829#if !defined(_MSC_VER)
830 // Mark the file close-on-exec. We don't really care if this fails
831 fcntl(fd, F_SETFD, FD_CLOEXEC);
832#endif
833
834 file_ = fdopen(fd, "a"); // Make a FILE*.
835 if (file_ == NULL) { // Man, we're screwed!
836 close(fd);
837 unlink(filename); // Erase the half-baked evidence: an unusable log file
838 return false;
839 }
840
841 // We try to create a symlink called <program_name>.<severity>,
842 // which is easier to use. (Every time we create a new logfile,
843 // we destroy the old symlink and create a new one, so it always
844 // points to the latest logfile.) If it fails, we're sad but it's
845 // no error.
846 if (!symlink_basename_.empty()) {
847 // take directory from filename
848 const char* slash = strrchr(filename, PATH_SEPARATOR);
849 const string linkname =
850 symlink_basename_ + '.' + LogSeverityNames[severity_];
851 string linkpath;
852 if (slash)
853 linkpath = string(filename, slash - filename + 1); // get dirname
854 linkpath += linkname;
855 unlink(linkpath.c_str()); // delete old one if it exists
856
857#if !defined(_MSC_VER)
858 // We must have unistd.h.
859 // Make the symlink be relative (in the same dir) so that if the
860 // entire log directory gets relocated the link is still valid.
861 const char* linkdest = slash ? (slash + 1) : filename;
862 if (symlink(linkdest, linkpath.c_str()) != 0) {
863 // silently ignore failures
864 }
865
866 // Make an additional link to the log file in a place specified by
867 // absl::GetFlag(FLAGS_log_link), if indicated
868 if (!absl::GetFlag(FLAGS_log_link).empty()) {
869 linkpath = absl::GetFlag(FLAGS_log_link) + "/" + linkname;
870 unlink(linkpath.c_str()); // delete old one if it exists
871 if (symlink(filename, linkpath.c_str()) != 0) {
872 // silently ignore failures
873 }
874 }
875#endif // !_MSC_VER
876 }
877
878 return true; // Everything worked
879}
880
881void LogFileObject::Write(bool force_flush, time_t timestamp,
882 const char* message, int message_len) {
883 absl::MutexLock l(&lock_);
884
885 // We don't log if the base_name_ is "" (which means "don't write")
886 if (base_filename_selected_ && base_filename_.empty()) {
887 return;
888 }
889
890 if (static_cast<int>(file_length_ >> 20) >= MaxLogSize()) {
891 if (file_ != NULL) fclose(file_);
892 file_ = NULL;
893 file_length_ = bytes_since_flush_ = dropped_mem_length_ = 0;
894 rollover_attempt_ = kRolloverAttemptFrequency - 1;
895 }
896
897 // If there's no destination file, make one before outputting
898 if (file_ == NULL) {
899 // Try to rollover the log file every 32 log messages. The only time
900 // this could matter would be when we have trouble creating the log
901 // file. If that happens, we'll lose lots of log messages, of course!
902 if (++rollover_attempt_ != kRolloverAttemptFrequency) return;
903 rollover_attempt_ = 0;
904
905 struct ::tm tm_time;
906 localtime_r(&timestamp, &tm_time);
907
908 // The logfile's filename will have the date/time & pid in it
909 ostringstream time_pid_stream;
910 time_pid_stream.fill('0');
911 time_pid_stream << 1900 + tm_time.tm_year << setw(2) << 1 + tm_time.tm_mon
912 << setw(2) << tm_time.tm_mday << '-' << setw(2)
913 << tm_time.tm_hour << setw(2) << tm_time.tm_min << setw(2)
914 << tm_time.tm_sec << '.'
916 const string& time_pid_string = time_pid_stream.str();
917
918 if (base_filename_selected_) {
919 if (!CreateLogfile(time_pid_string)) {
920 perror("Could not create log file");
921 fprintf(stderr, "COULD NOT CREATE LOGFILE '%s'!\n",
922 time_pid_string.c_str());
923 return;
924 }
925 } else {
926 // If no base filename for logs of this severity has been set, use a
927 // default base filename of
928 // "<program name>.<hostname>.<user name>.log.<severity level>.". So
929 // logfiles will have names like
930 // webserver.examplehost.root.log.INFO.19990817-150000.4354, where
931 // 19990817 is a date (1999 August 17), 150000 is a time (15:00:00),
932 // and 4354 is the pid of the logging process. The date & time reflect
933 // when the file was created for output.
934 //
935 // Where does the file get put? Successively try the directories
936 // "/tmp", and "."
937 string stripped_filename(logging_internal::ProgramInvocationShortName());
938 string hostname;
939 GetHostName(&hostname);
940
941 string uidname = logging_internal::MyUserName();
942 // We should not call CHECK() here because this function can be
943 // called after holding on to log_mutex. We don't want to
944 // attempt to hold on to the same absl::Mutex, and get into a
945 // deadlock. Simply use a name like invalid-user.
946 if (uidname.empty()) uidname = "invalid-user";
947
948 stripped_filename = stripped_filename + '.' + hostname + '.' + uidname +
949 ".log." + LogSeverityNames[severity_] + '.';
950 // We're going to (potentially) try to put logs in several different dirs
951 const vector<string>& log_dirs = GetLoggingDirectories();
952
953 // Go through the list of dirs, and try to create the log file in each
954 // until we succeed or run out of options
955 bool success = false;
956 for (vector<string>::const_iterator dir = log_dirs.begin();
957 dir != log_dirs.end(); ++dir) {
958 base_filename_ = *dir + "/" + stripped_filename;
959 if (CreateLogfile(time_pid_string)) {
960 success = true;
961 break;
962 }
963 }
964 // If we never succeeded, we have to give up
965 if (success == false) {
966 perror("Could not create logging file");
967 fprintf(stderr, "COULD NOT CREATE A LOGGINGFILE %s!",
968 time_pid_string.c_str());
969 return;
970 }
971 }
972
973 // Write a header message into the log file
974 ostringstream file_header_stream;
975 file_header_stream.fill('0');
976 file_header_stream << "Log file created at: " << 1900 + tm_time.tm_year
977 << '/' << setw(2) << 1 + tm_time.tm_mon << '/' << setw(2)
978 << tm_time.tm_mday << ' ' << setw(2) << tm_time.tm_hour
979 << ':' << setw(2) << tm_time.tm_min << ':' << setw(2)
980 << tm_time.tm_sec << '\n'
981 << "Running on machine: " << LogDestination::hostname()
982 << '\n'
983 << "Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu "
984 << "threadid file:line] msg" << '\n';
985 const string& file_header_string = file_header_stream.str();
986
987 const int header_len = file_header_string.size();
988 fwrite(file_header_string.data(), 1, header_len, file_);
989 file_length_ += header_len;
990 bytes_since_flush_ += header_len;
991 }
992
993 // Write to LOG file
994 if (!stop_writing) {
995 // fwrite() doesn't return an error when the disk is full, for
996 // messages that are less than 4096 bytes. When the disk is full,
997 // it returns the message length for messages that are less than
998 // 4096 bytes. fwrite() returns 4096 for message lengths that are
999 // greater than 4096, thereby indicating an error.
1000 errno = 0;
1001 fwrite(message, 1, message_len, file_);
1002 if (absl::GetFlag(FLAGS_stop_logging_if_full_disk) &&
1003 errno == ENOSPC) { // disk full, stop writing to disk
1004 stop_writing = true; // until the disk is
1005 return;
1006 } else {
1007 file_length_ += message_len;
1008 bytes_since_flush_ += message_len;
1009 }
1010 } else {
1011 if (logging_internal::CycleClock_Now() >= next_flush_time_)
1012 stop_writing = false; // check to see if disk has free space.
1013 return; // no need to flush
1014 }
1015
1016 // See important msgs *now*. Also, flush logs at least every 10^6 chars,
1017 // or every "absl::GetFlag(FLAGS_logbufsecs)" seconds.
1018 if (force_flush || (bytes_since_flush_ >= 1000000) ||
1019 (logging_internal::CycleClock_Now() >= next_flush_time_)) {
1020 FlushUnlocked();
1021#if defined(__linux__)
1022 // Only consider files >= 3MiB
1023 if (absl::GetFlag(FLAGS_drop_log_memory) && file_length_ >= (3 << 20)) {
1024 // Don't evict the most recent 1-2MiB so as not to impact a tailer
1025 // of the log file and to avoid page rounding issue on linux < 4.7
1026 uint32 total_drop_length = (file_length_ & ~((1 << 20) - 1)) - (1 << 20);
1027 uint32 this_drop_length = total_drop_length - dropped_mem_length_;
1028 if (this_drop_length >= (2 << 20)) {
1029 // Only advise when >= 2MiB to drop
1030 posix_fadvise(fileno(file_), dropped_mem_length_, this_drop_length,
1031 POSIX_FADV_DONTNEED);
1032 dropped_mem_length_ = total_drop_length;
1033 }
1034 }
1035#endif
1036 }
1037}
1038
1039} // namespace
1040
1041// Static log data space to avoid alloc failures in a LOG(FATAL)
1042//
1043// Since multiple threads may call LOG(FATAL), and we want to preserve
1044// the data from the first call, we allocate two sets of space. One
1045// for exclusive use by the first thread, and one for shared use by
1046// all other threads.
1047static absl::Mutex fatal_msg_lock;
1049static bool fatal_msg_exclusive = true;
1052
1053// Static thread-local log data space to use, because typically at most one
1054// LogMessageData object exists (in this case glog makes zero heap memory
1055// allocations).
1056static thread_local bool thread_data_available = true;
1057
1058static thread_local std::aligned_storage<
1061
1062LogMessage::LogMessageData::LogMessageData()
1063 : stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {}
1064
1065LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
1066 int ctr, void (LogMessage::*send_method)())
1067 : allocated_(NULL) {
1068 Init(file, line, severity, send_method);
1069 data_->stream_.set_ctr(ctr);
1070}
1071
1072LogMessage::LogMessage(const char* file, int line, const CheckOpString& result)
1073 : allocated_(NULL) {
1074 Init(file, line, GLOG_FATAL, &LogMessage::SendToLog);
1075 stream() << "Check failed: " << (*result.str_) << " ";
1076}
1077
1078LogMessage::LogMessage(const char* file, int line) : allocated_(NULL) {
1079 Init(file, line, GLOG_INFO, &LogMessage::SendToLog);
1080}
1081
1082LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
1083 : allocated_(NULL) {
1084 Init(file, line, severity, &LogMessage::SendToLog);
1085}
1086
1087LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
1088 LogSink* sink, bool also_send_to_log)
1089 : allocated_(NULL) {
1090 Init(file, line, severity,
1091 also_send_to_log ? &LogMessage::SendToSinkAndLog
1092 : &LogMessage::SendToSink);
1093 data_->sink_ = sink; // override Init()'s setting to NULL
1094}
1095
1096LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
1097 vector<string>* outvec)
1098 : allocated_(NULL) {
1099 Init(file, line, severity, &LogMessage::SaveOrSendToLog);
1100 data_->outvec_ = outvec; // override Init()'s setting to NULL
1101}
1102
1103LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
1104 string* message)
1105 : allocated_(NULL) {
1106 Init(file, line, severity, &LogMessage::WriteToStringAndLog);
1107 data_->message_ = message; // override Init()'s setting to NULL
1108}
1109
1110void LogMessage::Init(const char* file, int line, LogSeverity severity,
1111 void (LogMessage::*send_method)()) {
1112 allocated_ = NULL;
1113 if (severity != GLOG_FATAL || !exit_on_dfatal) {
1114 // No need for locking, because this is thread local.
1116 thread_data_available = false;
1117 data_ = new (&thread_msg_data) LogMessageData;
1118 } else {
1119 allocated_ = new LogMessageData();
1120 data_ = allocated_;
1121 }
1122 data_->first_fatal_ = false;
1123 } else {
1124 absl::MutexLock l(&fatal_msg_lock);
1125 if (fatal_msg_exclusive) {
1126 fatal_msg_exclusive = false;
1127 data_ = &fatal_msg_data_exclusive;
1128 data_->first_fatal_ = true;
1129 } else {
1130 data_ = &fatal_msg_data_shared;
1131 data_->first_fatal_ = false;
1132 }
1133 }
1134
1135 stream().fill('0');
1136 data_->preserved_errno_ = errno;
1137 data_->severity_ = severity;
1138 data_->line_ = line;
1139 data_->send_method_ = send_method;
1140 data_->sink_ = NULL;
1141 data_->outvec_ = NULL;
1142 double now = ToUDate(absl::Now());
1143 data_->timestamp_ = static_cast<time_t>(now);
1144 localtime_r(&data_->timestamp_, &data_->tm_time_);
1145 int usecs = static_cast<int>((now - data_->timestamp_) * 1000000);
1146
1147 data_->num_chars_to_log_ = 0;
1148 data_->num_chars_to_syslog_ = 0;
1150 data_->fullname_ = file;
1151 data_->has_been_flushed_ = false;
1152
1153 // If specified, prepend a prefix to each line. For example:
1154 // I1018 160715 f5d4fbb0 logging.cc:1153]
1155 // (log level, GMT month, date, time, thread_id, file basename, line)
1156 // We exclude the thread_id for the default thread.
1157 if (absl::GetFlag(FLAGS_log_prefix) && (line != kNoLogPrefix)) {
1158 stream() << LogSeverityNames[severity][0] << setw(2)
1159 << 1 + data_->tm_time_.tm_mon << setw(2) << data_->tm_time_.tm_mday
1160 << ' ' << setw(2) << data_->tm_time_.tm_hour << ':' << setw(2)
1161 << data_->tm_time_.tm_min << ':' << setw(2)
1162 << data_->tm_time_.tm_sec << "." << setw(6) << usecs << ' '
1163 << setfill(' ') << setw(5) << logging_internal::GetTID()
1164 << setfill('0') << ' ' << data_->basename_ << ':' << data_->line_
1165 << "] ";
1166 }
1167 data_->num_prefix_chars_ = data_->stream_.pcount();
1168
1169 if (!absl::GetFlag(FLAGS_log_backtrace_at).empty()) {
1170 char fileline[128];
1171 snprintf(fileline, sizeof(fileline), "%s:%d", data_->basename_, line);
1172 if (!strcmp(absl::GetFlag(FLAGS_log_backtrace_at).c_str(), fileline)) {
1173 string stacktrace;
1175 stream() << " (stacktrace:\n" << stacktrace << ") ";
1176 }
1177 }
1178}
1179
1181 Flush();
1182#ifdef GLOG_THREAD_LOCAL_STORAGE
1183 if (data_ == static_cast<void*>(&thread_msg_data)) {
1184 data_->~LogMessageData();
1185 thread_data_available = true;
1186 } else {
1187 delete allocated_;
1188 }
1189#else // !defined(GLOG_THREAD_LOCAL_STORAGE)
1190 delete allocated_;
1191#endif // defined(GLOG_THREAD_LOCAL_STORAGE)
1192}
1193
1194int LogMessage::preserved_errno() const { return data_->preserved_errno_; }
1195
1196ostream& LogMessage::stream() { return data_->stream_; }
1197
1198// Flush buffered message, called by the destructor, or any other function
1199// that needs to synchronize the log.
1201 if (data_->has_been_flushed_ ||
1202 data_->severity_ < absl::GetFlag(FLAGS_minloglevel))
1203 return;
1204
1205 data_->num_chars_to_log_ = data_->stream_.pcount();
1206 data_->num_chars_to_syslog_ =
1207 data_->num_chars_to_log_ - data_->num_prefix_chars_;
1208
1209 // Do we need to add a \n to the end of this message?
1210 bool append_newline =
1211 (data_->message_text_[data_->num_chars_to_log_ - 1] != '\n');
1212 char original_final_char = '\0';
1213
1214 // If we do need to add a \n, we'll do it by violating the memory of the
1215 // ostrstream buffer. This is quick, and we'll make sure to undo our
1216 // modification before anything else is done with the ostrstream. It
1217 // would be preferable not to do things this way, but it seems to be
1218 // the best way to deal with this.
1219 if (append_newline) {
1220 original_final_char = data_->message_text_[data_->num_chars_to_log_];
1221 data_->message_text_[data_->num_chars_to_log_++] = '\n';
1222 }
1223
1224 // Prevent any subtle race conditions by wrapping a absl::Mutex lock around
1225 // the actual logging action per se.
1226 {
1227 absl::MutexLock l(&log_mutex);
1228 (this->*(data_->send_method_))();
1229 ++num_messages_[static_cast<int>(data_->severity_)];
1230 }
1231 LogDestination::WaitForSinks(data_);
1232
1233 if (append_newline) {
1234 // Fix the ostrstream back how it was before we screwed with it.
1235 // It's 99.44% certain that we don't need to worry about doing this.
1236 data_->message_text_[data_->num_chars_to_log_ - 1] = original_final_char;
1237 }
1238
1239 // If errno was already set before we enter the logging call, we'll
1240 // set it back to that value when we return from the logging call.
1241 // It happens often that we log an error message after a syscall
1242 // failure, which can potentially set the errno to some other
1243 // values. We would like to preserve the original errno.
1244 if (data_->preserved_errno_ != 0) {
1245 errno = data_->preserved_errno_;
1246 }
1247
1248 // Note that this message is now safely logged. If we're asked to flush
1249 // again, as a result of destruction, say, we'll do nothing on future calls.
1250 data_->has_been_flushed_ = true;
1251}
1252
1253// Copy of first FATAL log message so that we can print it out again
1254// after all the stack traces. To preserve legacy behavior, we don't
1255// use fatal_msg_data_exclusive.
1256static time_t fatal_time;
1257static char fatal_message[256];
1258
1260 if (fatal_message[0]) {
1261 const int n = strlen(fatal_message);
1262 if (!absl::GetFlag(FLAGS_logtostderr)) {
1263 // Also write to stderr (don't color to avoid terminal checks)
1265 }
1266 LogDestination::LogToAllLogfiles(GLOG_ERROR, fatal_time, fatal_message, n);
1267 }
1268}
1269
1270// L >= log_mutex (callers must hold the log_mutex).
1271void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
1272 static bool already_warned_before_initgoogle = false;
1273
1274 log_mutex.AssertHeld();
1275
1276 RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
1277 data_->message_text_[data_->num_chars_to_log_ - 1] == '\n',
1278 "");
1279
1280 // Messages of a given severity get logged to lower severity logs, too
1281
1282 if (!already_warned_before_initgoogle &&
1284 const char w[] =
1285 "WARNING: Logging before InitGoogleLogging() is "
1286 "written to STDERR\n";
1287 WriteToStderr(w, strlen(w));
1288 already_warned_before_initgoogle = true;
1289 }
1290
1291 // global flag: never log to file if set. Also -- don't log to a
1292 // file if we haven't parsed the command line flags to get the
1293 // program name.
1294 if (absl::GetFlag(FLAGS_logtostderr) ||
1297 data_->num_chars_to_log_);
1298
1299 // this could be protected by a flag if necessary.
1300 LogDestination::LogToSinks(
1301 data_->severity_, data_->fullname_, data_->basename_, data_->line_,
1302 &data_->tm_time_, data_->message_text_ + data_->num_prefix_chars_,
1303 (data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1));
1304 } else {
1305 // log this message to all log files of severity <= severity_
1306 LogDestination::LogToAllLogfiles(data_->severity_, data_->timestamp_,
1307 data_->message_text_,
1308 data_->num_chars_to_log_);
1309
1310 LogDestination::MaybeLogToStderr(data_->severity_, data_->message_text_,
1311 data_->num_chars_to_log_);
1312 LogDestination::LogToSinks(
1313 data_->severity_, data_->fullname_, data_->basename_, data_->line_,
1314 &data_->tm_time_, data_->message_text_ + data_->num_prefix_chars_,
1315 (data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1));
1316 // NOTE: -1 removes trailing \n
1317 }
1318
1319 // If we log a FATAL message, flush all the log destinations, then toss
1320 // a signal for others to catch. We leave the logs in a state that
1321 // someone else can use them (as long as they flush afterwards)
1322 if (data_->severity_ == GLOG_FATAL && exit_on_dfatal) {
1323 if (data_->first_fatal_) {
1324 // Store crash information so that it is accessible from within signal
1325 // handlers that may be invoked later.
1326 RecordCrashReason(&crash_reason);
1328
1329 // Store shortened fatal message for other logs and GWQ status
1330 const int copy =
1331 min<int>(data_->num_chars_to_log_, sizeof(fatal_message) - 1);
1332 memcpy(fatal_message, data_->message_text_, copy);
1333 fatal_message[copy] = '\0';
1334 fatal_time = data_->timestamp_;
1335 }
1336
1337 if (!absl::GetFlag(FLAGS_logtostderr)) {
1338 for (int i = 0; i < NUM_SEVERITIES; ++i) {
1339 if (LogDestination::log_destinations_[i])
1340 LogDestination::log_destinations_[i]->logger_->Write(true, 0, "", 0);
1341 }
1342 }
1343
1344 // release the lock that our caller (directly or indirectly)
1345 // LogMessage::~LogMessage() grabbed so that signal handlers
1346 // can use the logging facility. Alternately, we could add
1347 // an entire unsafe logging interface to bypass locking
1348 // for signal handlers but this seems simpler.
1349 log_mutex.Unlock();
1350 LogDestination::WaitForSinks(data_);
1351
1352 const char* message = "*** Check failure stack trace: ***\n";
1353 if (write(STDERR_FILENO, message, strlen(message)) < 0) {
1354 // Ignore errors.
1355 }
1356 Fail();
1357 }
1358}
1359
1360void LogMessage::RecordCrashReason(logging_internal::CrashReason* reason) {
1365 // Retrieve the stack trace, omitting the logging frames that got us here.
1366 reason->depth =
1367 absl::GetStackTrace(reason->stack, ABSL_ARRAYSIZE(reason->stack), 4);
1368}
1369
1370#if !defined(_MSC_VER)
1371#define ATTRIBUTE_NORETURN __attribute__((noreturn))
1372#else
1373#define ATTRIBUTE_NORETURN
1374#endif
1375
1376#if defined(_MSC_VER)
1377__declspec(noreturn)
1378#endif
1379 static void logging_fail() ATTRIBUTE_NORETURN;
1380
1381static void logging_fail() { abort(); }
1382
1384
1387
1388void InstallFailureFunction(void (*fail_func)()) {
1390}
1391
1393
1394// L >= log_mutex (callers must hold the log_mutex).
1395void LogMessage::SendToSink() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
1396 if (data_->sink_ != NULL) {
1397 RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
1398 data_->message_text_[data_->num_chars_to_log_ - 1] == '\n',
1399 "");
1400 data_->sink_->send(
1401 data_->severity_, data_->fullname_, data_->basename_, data_->line_,
1402 &data_->tm_time_, data_->message_text_ + data_->num_prefix_chars_,
1403 (data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1));
1404 }
1405}
1406
1407// L >= log_mutex (callers must hold the log_mutex).
1408void LogMessage::SendToSinkAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
1409 SendToSink();
1410 SendToLog();
1411}
1412
1413// L >= log_mutex (callers must hold the log_mutex).
1414void LogMessage::SaveOrSendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
1415 if (data_->outvec_ != NULL) {
1416 RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
1417 data_->message_text_[data_->num_chars_to_log_ - 1] == '\n',
1418 "");
1419 // Omit prefix of message and trailing newline when recording in outvec_.
1420 const char* start = data_->message_text_ + data_->num_prefix_chars_;
1421 int len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;
1422 data_->outvec_->push_back(string(start, len));
1423 } else {
1424 SendToLog();
1425 }
1426}
1427
1428void LogMessage::WriteToStringAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
1429 if (data_->message_ != NULL) {
1430 RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
1431 data_->message_text_[data_->num_chars_to_log_ - 1] == '\n',
1432 "");
1433 // Omit prefix of message and trailing newline when writing to message_.
1434 const char* start = data_->message_text_ + data_->num_prefix_chars_;
1435 int len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;
1436 data_->message_->assign(start, len);
1437 }
1438 SendToLog();
1439}
1440
1441// L >= log_mutex (callers must hold the log_mutex).
1443#if !defined(_MSC_VER)
1444 // Before any calls to syslog(), make a single call to openlog()
1445 static bool openlog_already_called = false;
1446 if (!openlog_already_called) {
1448 LOG_CONS | LOG_NDELAY | LOG_PID, LOG_USER);
1449 openlog_already_called = true;
1450 }
1451
1452 // This array maps Google severity levels to syslog levels
1453 const int SEVERITY_TO_LEVEL[] = {LOG_INFO, LOG_WARNING, LOG_ERR, LOG_EMERG};
1454 syslog(LOG_USER | SEVERITY_TO_LEVEL[static_cast<int>(data_->severity_)],
1455 "%.*s", static_cast<int>(data_->num_chars_to_syslog_),
1456 data_->message_text_ + data_->num_prefix_chars_);
1457 SendToLog();
1458#else
1459 LOG(ERROR) << "No syslog support: message=" << data_->message_text_;
1460#endif
1461}
1462
1464 absl::MutexLock l(&log_mutex);
1465 return LogDestination::log_destination(severity)->logger_;
1466}
1467
1469 absl::MutexLock l(&log_mutex);
1470 LogDestination::log_destination(severity)->logger_ = logger;
1471}
1472
1473// L < log_mutex. Acquires and releases absl::Mutex_.
1475 absl::MutexLock l(&log_mutex);
1476 return num_messages_[severity];
1477}
1478
1479// Output the COUNTER value. This is only valid if ostream is a
1480// LogStream.
1481ostream& operator<<(ostream& os, const PRIVATE_Counter&) {
1482#ifdef DISABLE_RTTI
1483 LogMessage::LogStream* log = static_cast<LogMessage::LogStream*>(&os);
1484#else
1485 LogMessage::LogStream* log = dynamic_cast<LogMessage::LogStream*>(&os);
1486#endif
1487 CHECK(log && log == log->self())
1488 << "You must not use COUNTER with non-glog ostream";
1489 os << log->ctr();
1490 return os;
1491}
1492
1494 LogSeverity severity, int ctr,
1495 void (LogMessage::*send_method)())
1496 : LogMessage(file, line, severity, ctr, send_method) {}
1497
1499 // Don't access errno directly because it may have been altered
1500 // while streaming the message.
1501 stream() << ": " << StrError(preserved_errno()) << " [" << preserved_errno()
1502 << "]";
1503}
1504
1505void FlushLogFiles(LogSeverity min_severity) {
1506 LogDestination::FlushLogFiles(min_severity);
1507}
1508
1511}
1512
1513void SetLogDestination(LogSeverity severity, const char* base_filename) {
1514 LogDestination::SetLogDestination(severity, base_filename);
1515}
1516
1517void SetLogSymlink(LogSeverity severity, const char* symlink_basename) {
1518 LogDestination::SetLogSymlink(severity, symlink_basename);
1519}
1520
1522
1524 // noop default
1525}
1526
1527string LogSink::ToString(LogSeverity severity, const char* file, int line,
1528 const struct ::tm* tm_time, const char* message,
1529 size_t message_len) {
1530 ostringstream stream(string(message, message_len));
1531 stream.fill('0');
1532
1533 // FIXME(jrvb): Updating this to use the correct value for usecs
1534 // requires changing the signature for both this method and
1535 // LogSink::send(). This change needs to be done in a separate CL
1536 // so subclasses of LogSink can be updated at the same time.
1537 int usecs = 0;
1538
1539 stream << LogSeverityNames[severity][0] << setw(2) << 1 + tm_time->tm_mon
1540 << setw(2) << tm_time->tm_mday << ' ' << setw(2) << tm_time->tm_hour
1541 << ':' << setw(2) << tm_time->tm_min << ':' << setw(2)
1542 << tm_time->tm_sec << '.' << setw(6) << usecs << ' ' << setfill(' ')
1543 << setw(5) << logging_internal::GetTID() << setfill('0') << ' ' << file
1544 << ':' << line << "] ";
1545
1546 stream << string(message, message_len);
1547 return stream.str();
1548}
1549
1550void AddLogSink(LogSink* destination) {
1551 LogDestination::AddLogSink(destination);
1552}
1553
1554void RemoveLogSink(LogSink* destination) {
1555 LogDestination::RemoveLogSink(destination);
1556}
1557
1558void SetLogFilenameExtension(const char* ext) {
1560}
1561
1562void SetStderrLogging(LogSeverity min_severity) {
1564}
1565
1567
1568namespace base {
1569namespace internal {
1570
1571bool GetExitOnDFatal();
1573 absl::MutexLock l(&log_mutex);
1574 return exit_on_dfatal;
1575}
1576
1577// Determines whether we exit the program for a LOG(DFATAL) message in
1578// debug mode. It does this by skipping the call to Fail/FailQuietly.
1579// This is intended for testing only.
1580//
1581// This can have some effects on LOG(FATAL) as well. Failure messages
1582// are always allocated (rather than sharing a buffer), the crash
1583// reason is not recorded, the "gwq" status message is not updated,
1584// and the stack trace is not recorded. The LOG(FATAL) *will* still
1585// exit the program. Since this function is used only in testing,
1586// these differences are acceptable.
1587void SetExitOnDFatal(bool value);
1589 absl::MutexLock l(&log_mutex);
1591}
1592
1593} // namespace internal
1594} // namespace base
1595
1596// Shell-escaping as we need to shell out ot /bin/mail.
1597static const char kDontNeedShellEscapeChars[] =
1598 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1599 "abcdefghijklmnopqrstuvwxyz"
1600 "0123456789+-_.=/:,@";
1601
1602static string ShellEscape(const string& src) {
1603 string result;
1604 if (!src.empty() && // empty string needs quotes
1605 src.find_first_not_of(kDontNeedShellEscapeChars) == string::npos) {
1606 // only contains chars that don't need quotes; it's fine
1607 result.assign(src);
1608 } else if (src.find_first_of('\'') == string::npos) {
1609 // no single quotes; just wrap it in single quotes
1610 result.assign("'");
1611 result.append(src);
1612 result.append("'");
1613 } else {
1614 // needs double quote escaping
1615 result.assign("\"");
1616 for (size_t i = 0; i < src.size(); ++i) {
1617 switch (src[i]) {
1618 case '\\':
1619 case '$':
1620 case '"':
1621 case '`':
1622 result.append("\\");
1623 }
1624 result.append(src, i, 1);
1625 }
1626 result.append("\"");
1627 }
1628 return result;
1629}
1630
1631static void GetTempDirectories(vector<string>* list) {
1632 list->clear();
1633#ifdef _MSC_VER
1634 // On windows we'll try to find a directory in this order:
1635 // C:/Documents & Settings/whomever/TEMP (or whatever GetTempPath() is)
1636 // C:/TMP/
1637 // C:/TEMP/
1638 // C:/WINDOWS/ or C:/WINNT/
1639 // .
1640 char tmp[MAX_PATH];
1641 if (GetTempPathA(MAX_PATH, tmp)) list->push_back(tmp);
1642 list->push_back("C:\\tmp\\");
1643 list->push_back("C:\\temp\\");
1644#else
1645 // Directories, in order of preference. If we find a dir that
1646 // exists, we stop adding other less-preferred dirs
1647 const char* candidates[] = {
1648 // Non-null only during unittest/regtest
1649 getenv("TEST_TMPDIR"),
1650
1651 // Explicitly-supplied temp dirs
1652 getenv("TMPDIR"),
1653 getenv("TMP"),
1654
1655 // If all else fails
1656 "/tmp",
1657 };
1658
1659 for (size_t i = 0; i < ABSL_ARRAYSIZE(candidates); i++) {
1660 const char* d = candidates[i];
1661 if (!d) continue; // Empty env var
1662
1663 // Make sure we don't surprise anyone who's expecting a '/'
1664 string dstr = d;
1665 if (dstr[dstr.size() - 1] != '/') {
1666 dstr += "/";
1667 }
1668 list->push_back(dstr);
1669
1670 struct stat statbuf;
1671 if (!stat(d, &statbuf) && S_ISDIR(statbuf.st_mode)) {
1672 // We found a dir that exists - we're done.
1673 return;
1674 }
1675 }
1676
1677#endif
1678}
1679
1680static vector<string>* logging_directories_list;
1681
1682const vector<string>& GetLoggingDirectories() {
1683 // Not strictly thread-safe but we're called early in InitGoogle().
1684 if (logging_directories_list == NULL) {
1685 logging_directories_list = new vector<string>;
1686
1687 if (!absl::GetFlag(FLAGS_log_dir).empty()) {
1688 // A dir was specified, we should use it
1689 logging_directories_list->push_back(absl::GetFlag(FLAGS_log_dir).c_str());
1690 } else {
1692#ifdef _MSC_VER
1693 char tmp[MAX_PATH];
1694 if (GetWindowsDirectoryA(tmp, MAX_PATH))
1695 logging_directories_list->push_back(tmp);
1696 logging_directories_list->push_back(".\\");
1697#else
1698 logging_directories_list->push_back("./");
1699#endif
1700 }
1701 }
1703}
1704
1706 fprintf(stderr,
1707 "TestOnly_ClearLoggingDirectoriesList should only be "
1708 "called from test code.\n");
1711}
1712
1713void GetExistingTempDirectories(vector<string>* list) {
1714 GetTempDirectories(list);
1715 vector<string>::iterator i_dir = list->begin();
1716 while (i_dir != list->end()) {
1717 // zero arg to access means test for existence; no constant
1718 // defined on windows
1719 if (access(i_dir->c_str(), 0)) {
1720 i_dir = list->erase(i_dir);
1721 } else {
1722 ++i_dir;
1723 }
1724 }
1725}
1726
1727// Helper functions for string comparisons.
1728#define DEFINE_CHECK_STROP_IMPL(name, func, expected) \
1729 string* Check##func##expected##Impl(const char* s1, const char* s2, \
1730 const char* names) { \
1731 bool equal = s1 == s2 || (s1 && s2 && !func(s1, s2)); \
1732 if (equal == expected) { \
1733 return NULL; \
1734 } else { \
1735 ostringstream ss; \
1736 if (!s1) s1 = ""; \
1737 if (!s2) s2 = ""; \
1738 ss << #name " failed: " << names << " (" << s1 << " vs. " << s2 << ")"; \
1739 return new string(ss.str()); \
1740 } \
1741 }
1745DEFINE_CHECK_STROP_IMPL(CHECK_STRCASENE, strcasecmp, false)
1746#undef DEFINE_CHECK_STROP_IMPL
1747
1748int posix_strerror_r(int err, char* buf, size_t len) {
1749 // Sanity check input parameters
1750 if (buf == NULL || len <= 0) {
1751 errno = EINVAL;
1752 return -1;
1753 }
1754
1755 // Reset buf and errno, and try calling whatever version of strerror_r()
1756 // is implemented by glibc
1757 buf[0] = '\000';
1758 int old_errno = errno;
1759 errno = 0;
1760 char* rc = reinterpret_cast<char*>(strerror_r(err, buf, len));
1761
1762 // Both versions set errno on failure
1763 if (errno) {
1764 // Should already be there, but better safe than sorry
1765 buf[0] = '\000';
1766 return -1;
1767 }
1768 errno = old_errno;
1769
1770 // POSIX is vague about whether the string will be terminated, although
1771 // is indirectly implies that typically ERANGE will be returned, instead
1772 // of truncating the string. This is different from the GNU implementation.
1773 // We play it safe by always terminating the string explicitly.
1774 buf[len - 1] = '\000';
1775
1776 // If the function succeeded, we can use its exit code to determine the
1777 // semantics implemented by glibc
1778 if (!rc) {
1779 return 0;
1780 } else {
1781 // GNU semantics detected
1782 if (rc == buf) {
1783 return 0;
1784 } else {
1785 buf[0] = '\000';
1786#if defined(OS_MACOSX) || defined(OS_FREEBSD) || defined(OS_OPENBSD)
1787 if (reinterpret_cast<intptr_t>(rc) < sys_nerr) {
1788 // This means an error on MacOSX or FreeBSD.
1789 return -1;
1790 }
1791#endif
1792 strncat(buf, rc, len - 1);
1793 return 0;
1794 }
1795 }
1796}
1797
1798string StrError(int err) {
1799 char buf[100];
1800 int rc = posix_strerror_r(err, buf, sizeof(buf));
1801 if ((rc < 0) || (buf[0] == '\000')) {
1802 snprintf(buf, sizeof(buf), "Error number %d", err);
1803 }
1804 return buf;
1805}
1806
1808 : LogMessage(file, line, GLOG_FATAL) {}
1809
1811 const CheckOpString& result)
1812 : LogMessage(file, line, result) {}
1813
1815 Flush();
1817}
1818
1819namespace base {
1820
1822 : stream_(new ostringstream) {
1823 *stream_ << exprtext << " (";
1824}
1825
1827
1829 *stream_ << " vs. ";
1830 return stream_;
1831}
1832
1834 *stream_ << ")";
1835 return new string(stream_->str());
1836}
1837
1838} // namespace base
1839
1840template <>
1841void MakeCheckOpValueString(std::ostream* os, const char& v) {
1842 if (v >= 32 && v <= 126) {
1843 (*os) << "'" << v << "'";
1844 } else {
1845 (*os) << "char value " << (int16)v;
1846 }
1847}
1848
1849template <>
1850void MakeCheckOpValueString(std::ostream* os, const signed char& v) {
1851 if (v >= 32 && v <= 126) {
1852 (*os) << "'" << v << "'";
1853 } else {
1854 (*os) << "signed char value " << (int16)v;
1855 }
1856}
1857
1858template <>
1859void MakeCheckOpValueString(std::ostream* os, const unsigned char& v) {
1860 if (v >= 32 && v <= 126) {
1861 (*os) << "'" << v << "'";
1862 } else {
1863 (*os) << "unsigned char value " << (uint16)v;
1864 }
1865}
1866
1867void InitGoogleLogging(const char* argv0) {
1869}
1870
1876}
1877
1878} // namespace google
int64 min
Definition: alldiff_cst.cc:138
#define PATH_SEPARATOR
ABSL_DECLARE_FLAG(bool, log_prefix)
ABSL_FLAG(bool, logtostderr, false, "log messages go to stderr instead of logfiles")
static const char * DefaultLogDir()
static void GetHostName(string *hostname)
#define DEFINE_CHECK_STROP_IMPL(name, func, expected)
static bool TerminalSupportsColor()
void FixFlagsAndEnvironmentForSwig()
Definition: base/logging.cc:61
#define ATTRIBUTE_NORETURN
#define CHECK(condition)
Definition: base/logging.h:495
#define CHECK_STRNE(s1, s2)
Definition: base/logging.h:736
#define CHECK_LT(val1, val2)
Definition: base/logging.h:700
#define CHECK_GE(val1, val2)
Definition: base/logging.h:701
#define CHECK_STRCASEEQ(s1, s2)
Definition: base/logging.h:737
#define CHECK_STRCASENE(s1, s2)
Definition: base/logging.h:738
#define LOG(severity)
Definition: base/logging.h:420
#define CHECK_STREQ(s1, s2)
Definition: base/logging.h:735
ErrnoLogMessage(const char *file, int line, LogSeverity severity, int ctr, void(LogMessage::*send_method)())
static void AddLogSink(LogSink *destination)
static void RemoveLogSink(LogSink *destination)
static void SetStderrLogging(LogSeverity min_severity)
static void FlushLogFilesUnsafe(int min_severity)
static void SetLogSymlink(LogSeverity severity, const char *symlink_basename)
static void SetLogFilenameExtension(const char *filename_extension)
static void LogToStderr()
static void SetLogDestination(LogSeverity severity, const char *base_filename)
static void DeleteLogDestinations()
static const bool & terminal_supports_color()
static const string & hostname()
static void FlushLogFiles(int min_severity)
LogStream * self() const
LogMessageFatal(const char *file, int line)
ATTRIBUTE_NORETURN ~LogMessageFatal()
int preserved_errno() const
static int64 num_messages(int severity)
LogMessage(const char *file, int line, LogSeverity severity, int ctr, SendMethod send_method)
std::ostream & stream()
static const size_t kMaxLogMessageLen
static void ATTRIBUTE_NORETURN Fail()
virtual void send(LogSeverity severity, const char *full_filename, const char *base_filename, int line, const struct ::tm *tm_time, const char *message, size_t message_len)=0
virtual ~LogSink()
static std::string ToString(LogSeverity severity, const char *file, int line, const struct ::tm *tm_time, const char *message, size_t message_len)
virtual void WaitTillSent()
CheckOpMessageBuilder(const char *exprtext)
virtual void Flush()=0
Block * next
int64 value
unsigned short uint16
unsigned int uint32
short int16
int int32
int64_t int64
int LogSeverity
Definition: log_severity.h:22
const int ERROR
Definition: log_severity.h:32
#define GOOGLE_GLOG_DLL_DECL
Definition: file.cc:141
void SetExitOnDFatal(bool value)
GOOGLE_GLOG_DLL_DECL Logger * GetLogger(LogSeverity level)
GOOGLE_GLOG_DLL_DECL void SetLogger(LogSeverity level, Logger *logger)
void DumpStackTraceToString(std::string *stacktrace)
void InitGoogleLoggingUtilities(const char *argv0)
const char * ProgramInvocationShortName()
const std::string & MyUserName()
void SetCrashReason(const CrashReason *r)
int64 UsecToCycles(int64 usec)
const char * const_basename(const char *filepath)
ostream & operator<<(ostream &os, const PRIVATE_Counter &)
static thread_local bool thread_data_available
static char fatal_message[256]
const int GLOG_WARNING
Definition: log_severity.h:25
static void ColoredWriteToStderr(LogSeverity severity, const char *message, size_t len)
void MakeCheckOpValueString(std::ostream *os, const char &v)
void InitGoogleLogging(const char *argv0)
static thread_local std::aligned_storage< sizeof(LogMessage::LogMessageData), alignof(LogMessage::LogMessageData)>::type thread_msg_data
static absl::Mutex log_mutex
GOOGLE_GLOG_DLL_DECL logging_fail_func_t g_logging_fail_func
void FlushLogFilesUnsafe(LogSeverity min_severity)
void(* logging_fail_func_t)() ATTRIBUTE_NORETURN
static absl::Mutex fatal_msg_lock
static vector< string > * logging_directories_list
void SetLogFilenameExtension(const char *ext)
static GLogColor SeverityToColor(LogSeverity severity)
static bool exit_on_dfatal
void SetLogDestination(LogSeverity severity, const char *base_filename)
void SetStderrLogging(LogSeverity min_severity)
const char * GetLogSeverityName(LogSeverity severity)
const int NUM_SEVERITIES
Definition: log_severity.h:26
void GetExistingTempDirectories(vector< string > *list)
void ShutdownGoogleLogging()
static bool fatal_msg_exclusive
void InstallFailureFunction(void(*fail_func)())
static LogMessage::LogMessageData fatal_msg_data_exclusive
GOOGLE_GLOG_DLL_DECL const char *const LogSeverityNames[NUM_SEVERITIES]
static LogMessage::LogMessageData fatal_msg_data_shared
string StrError(int err)
int posix_strerror_r(int err, char *buf, size_t len)
const vector< string > & GetLoggingDirectories()
void SetLogSymlink(LogSeverity severity, const char *symlink_basename)
@ COLOR_DEFAULT
@ COLOR_YELLOW
static const char kDontNeedShellEscapeChars[]
static const char * GetAnsiColorCode(GLogColor color)
static string ShellEscape(const string &src)
void AddLogSink(LogSink *destination)
static time_t fatal_time
void LogToStderr()
const int GLOG_FATAL
Definition: log_severity.h:25
static void WriteToStderr(const char *message, size_t len)
void FlushLogFiles(LogSeverity min_severity)
static void GetTempDirectories(vector< string > *list)
static logging_internal::CrashReason crash_reason
static bool stop_writing
void TestOnly_ClearLoggingDirectoriesList()
const int GLOG_ERROR
Definition: log_severity.h:25
static void logging_fail() ATTRIBUTE_NORETURN
static int32 MaxLogSize()
const int GLOG_INFO
Definition: log_severity.h:25
void RemoveLogSink(LogSink *destination)
void ReprintFatalMessage()
#define RAW_DCHECK(condition, message)
Definition: raw_logging.h:117
std::string * str_
Definition: base/logging.h:508
char message_text_[LogMessage::kMaxLogMessageLen+1]
void(LogMessage::* send_method_)()
std::vector< std::string > * outvec_
std::string message
Definition: trace.cc:395