blob: f7e3111592ae0592ce78fe0b78cd6f1833c342a4 [file] [log] [blame]
Austin Schuh906616c2019-01-21 20:25:11 -08001// Copyright (c) 1999, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#define _GNU_SOURCE 1 // needed for O_NOFOLLOW and pread()/pwrite()
31
32#include "utilities.h"
33
34#include <algorithm>
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070035#include <cassert>
Austin Schuh906616c2019-01-21 20:25:11 -080036#include <iomanip>
37#include <string>
38#ifdef HAVE_UNISTD_H
39# include <unistd.h> // For _exit.
40#endif
41#include <climits>
42#include <sys/types.h>
43#include <sys/stat.h>
44#ifdef HAVE_SYS_UTSNAME_H
45# include <sys/utsname.h> // For uname.
46#endif
Ravago Jones37f3fbd2020-10-03 17:45:26 -070047#include <dirent.h>
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070048#include <ctime>
Austin Schuh906616c2019-01-21 20:25:11 -080049#include <fcntl.h>
50#include <cstdio>
51#include <iostream>
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070052#include <cstdarg>
53#include <cstdlib>
Austin Schuh906616c2019-01-21 20:25:11 -080054#ifdef HAVE_PWD_H
55# include <pwd.h>
56#endif
57#ifdef HAVE_SYSLOG_H
58# include <syslog.h>
59#endif
60#include <vector>
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070061#include <cerrno> // for errno
Austin Schuh906616c2019-01-21 20:25:11 -080062#include <sstream>
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070063#ifdef GLOG_OS_WINDOWS
64#include "windows/dirent.h"
65#else
66#include <dirent.h> // for automatic removal of old logs
67#endif
Austin Schuh906616c2019-01-21 20:25:11 -080068#include "base/commandlineflags.h" // to get the program name
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070069#include <glog/logging.h>
70#include <glog/raw_logging.h>
Austin Schuh906616c2019-01-21 20:25:11 -080071#include "base/googleinit.h"
72
73#ifdef HAVE_STACKTRACE
74# include "stacktrace.h"
75#endif
76
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070077#ifdef __ANDROID__
78#include <android/log.h>
79#endif
80
Austin Schuh906616c2019-01-21 20:25:11 -080081using std::string;
82using std::vector;
83using std::setw;
84using std::setfill;
85using std::hex;
86using std::dec;
87using std::min;
88using std::ostream;
89using std::ostringstream;
90
91using std::FILE;
92using std::fwrite;
93using std::fclose;
94using std::fflush;
95using std::fprintf;
96using std::perror;
97
98#ifdef __QNX__
99using std::fdopen;
100#endif
101
102#ifdef _WIN32
103#define fdopen _fdopen
104#endif
105
106// There is no thread annotation support.
107#define EXCLUSIVE_LOCKS_REQUIRED(mu)
108
109static bool BoolFromEnv(const char *varname, bool defval) {
110 const char* const valstr = getenv(varname);
111 if (!valstr) {
112 return defval;
113 }
114 return memchr("tTyY1\0", valstr[0], 6) != NULL;
115}
116
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700117GLOG_DEFINE_bool(timestamp_in_logfile_name,
118 BoolFromEnv("GOOGLE_TIMESTAMP_IN_LOGFILE_NAME", true),
119 "put a timestamp at the end of the log file name");
Austin Schuh906616c2019-01-21 20:25:11 -0800120GLOG_DEFINE_bool(logtostderr, BoolFromEnv("GOOGLE_LOGTOSTDERR", false),
121 "log messages go to stderr instead of logfiles");
122GLOG_DEFINE_bool(alsologtostderr, BoolFromEnv("GOOGLE_ALSOLOGTOSTDERR", false),
123 "log messages go to stderr in addition to logfiles");
124GLOG_DEFINE_bool(colorlogtostderr, false,
125 "color messages logged to stderr (if supported by terminal)");
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700126GLOG_DEFINE_bool(colorlogtostdout, false,
127 "color messages logged to stdout (if supported by terminal)");
128GLOG_DEFINE_bool(logtostdout, BoolFromEnv("GOOGLE_LOGTOSTDOUT", false),
129 "log messages go to stdout instead of logfiles");
130#ifdef GLOG_OS_LINUX
Austin Schuh906616c2019-01-21 20:25:11 -0800131GLOG_DEFINE_bool(drop_log_memory, true, "Drop in-memory buffers of log contents. "
132 "Logs can grow very quickly and they are rarely read before they "
133 "need to be evicted from memory. Instead, drop them from memory "
134 "as soon as they are flushed to disk.");
135#endif
136
137// By default, errors (including fatal errors) get logged to stderr as
138// well as the file.
139//
140// The default is ERROR instead of FATAL so that users can see problems
141// when they run a program without having to look in another file.
142DEFINE_int32(stderrthreshold,
143 GOOGLE_NAMESPACE::GLOG_ERROR,
144 "log messages at or above this level are copied to stderr in "
145 "addition to logfiles. This flag obsoletes --alsologtostderr.");
146
147GLOG_DEFINE_string(alsologtoemail, "",
148 "log messages go to these email addresses "
149 "in addition to logfiles");
150GLOG_DEFINE_bool(log_prefix, true,
151 "Prepend the log prefix to the start of each log line");
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700152GLOG_DEFINE_bool(log_year_in_prefix, true,
153 "Include the year in the log prefix");
Austin Schuh906616c2019-01-21 20:25:11 -0800154GLOG_DEFINE_int32(minloglevel, 0, "Messages logged at a lower level than this don't "
155 "actually get logged anywhere");
156GLOG_DEFINE_int32(logbuflevel, 0,
157 "Buffer log messages logged at this level or lower"
158 " (-1 means don't buffer; 0 means buffer INFO only;"
159 " ...)");
160GLOG_DEFINE_int32(logbufsecs, 30,
161 "Buffer log messages for at most this many seconds");
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700162
163GLOG_DEFINE_int32(logcleansecs, 60 * 5, // every 5 minutes
164 "Clean overdue logs every this many seconds");
165
Austin Schuh906616c2019-01-21 20:25:11 -0800166GLOG_DEFINE_int32(logemaillevel, 999,
167 "Email log messages logged at this level or higher"
168 " (0 means email all; 3 means email FATAL only;"
169 " ...)");
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700170GLOG_DEFINE_string(logmailer, "",
Austin Schuh906616c2019-01-21 20:25:11 -0800171 "Mailer used to send logging email");
172
173// Compute the default value for --log_dir
174static const char* DefaultLogDir() {
175 const char* env;
176 env = getenv("GOOGLE_LOG_DIR");
177 if (env != NULL && env[0] != '\0') {
178 return env;
179 }
180 env = getenv("TEST_TMPDIR");
181 if (env != NULL && env[0] != '\0') {
182 return env;
183 }
184 return "";
185}
186
Austin Schuh77f3f222022-06-10 16:49:21 -0700187namespace aos {
188void FatalUnsetRealtimePriority() __attribute__((weak));
189}
190
191static void MaybeUnsetRealtime() {
192 if (&aos::FatalUnsetRealtimePriority != nullptr) {
193 aos::FatalUnsetRealtimePriority();
194 }
195}
196
Austin Schuh906616c2019-01-21 20:25:11 -0800197GLOG_DEFINE_int32(logfile_mode, 0664, "Log file mode/permissions.");
198
199GLOG_DEFINE_string(log_dir, DefaultLogDir(),
200 "If specified, logfiles are written into this directory instead "
201 "of the default logging directory.");
202GLOG_DEFINE_string(log_link, "", "Put additional links to the log "
203 "files in this directory");
204
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700205GLOG_DEFINE_uint32(max_log_size, 1800,
206 "approx. maximum log file size (in MB). A value of 0 will "
207 "be silently overridden to 1.");
Austin Schuh906616c2019-01-21 20:25:11 -0800208
209GLOG_DEFINE_bool(stop_logging_if_full_disk, false,
210 "Stop attempting to log to disk if the disk is full.");
211
212GLOG_DEFINE_string(log_backtrace_at, "",
213 "Emit a backtrace when logging at file:linenum.");
214
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700215GLOG_DEFINE_bool(log_utc_time, false,
216 "Use UTC time for logging.");
217
Austin Schuh906616c2019-01-21 20:25:11 -0800218// TODO(hamaji): consider windows
219#define PATH_SEPARATOR '/'
220
221#ifndef HAVE_PREAD
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700222#if defined(GLOG_OS_WINDOWS)
Austin Schuh906616c2019-01-21 20:25:11 -0800223#include <basetsd.h>
224#define ssize_t SSIZE_T
225#endif
226static ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
227 off_t orig_offset = lseek(fd, 0, SEEK_CUR);
228 if (orig_offset == (off_t)-1)
229 return -1;
230 if (lseek(fd, offset, SEEK_CUR) == (off_t)-1)
231 return -1;
232 ssize_t len = read(fd, buf, count);
233 if (len < 0)
234 return len;
235 if (lseek(fd, orig_offset, SEEK_SET) == (off_t)-1)
236 return -1;
237 return len;
238}
239#endif // !HAVE_PREAD
240
241#ifndef HAVE_PWRITE
242static ssize_t pwrite(int fd, void* buf, size_t count, off_t offset) {
243 off_t orig_offset = lseek(fd, 0, SEEK_CUR);
244 if (orig_offset == (off_t)-1)
245 return -1;
246 if (lseek(fd, offset, SEEK_CUR) == (off_t)-1)
247 return -1;
248 ssize_t len = write(fd, buf, count);
249 if (len < 0)
250 return len;
251 if (lseek(fd, orig_offset, SEEK_SET) == (off_t)-1)
252 return -1;
253 return len;
254}
255#endif // !HAVE_PWRITE
256
257static void GetHostName(string* hostname) {
258#if defined(HAVE_SYS_UTSNAME_H)
259 struct utsname buf;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700260 if (uname(&buf) < 0) {
Austin Schuh906616c2019-01-21 20:25:11 -0800261 // ensure null termination on failure
262 *buf.nodename = '\0';
263 }
264 *hostname = buf.nodename;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700265#elif defined(GLOG_OS_WINDOWS)
Austin Schuh906616c2019-01-21 20:25:11 -0800266 char buf[MAX_COMPUTERNAME_LENGTH + 1];
267 DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
268 if (GetComputerNameA(buf, &len)) {
269 *hostname = buf;
270 } else {
271 hostname->clear();
272 }
273#else
274# warning There is no way to retrieve the host name.
275 *hostname = "(unknown)";
276#endif
277}
278
279// Returns true iff terminal supports using colors in output.
280static bool TerminalSupportsColor() {
281 bool term_supports_color = false;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700282#ifdef GLOG_OS_WINDOWS
Austin Schuh906616c2019-01-21 20:25:11 -0800283 // on Windows TERM variable is usually not set, but the console does
284 // support colors.
285 term_supports_color = true;
286#else
287 // On non-Windows platforms, we rely on the TERM variable.
288 const char* const term = getenv("TERM");
289 if (term != NULL && term[0] != '\0') {
290 term_supports_color =
291 !strcmp(term, "xterm") ||
292 !strcmp(term, "xterm-color") ||
293 !strcmp(term, "xterm-256color") ||
294 !strcmp(term, "screen-256color") ||
295 !strcmp(term, "konsole") ||
296 !strcmp(term, "konsole-16color") ||
297 !strcmp(term, "konsole-256color") ||
298 !strcmp(term, "screen") ||
299 !strcmp(term, "linux") ||
300 !strcmp(term, "cygwin");
301 }
302#endif
303 return term_supports_color;
304}
305
306_START_GOOGLE_NAMESPACE_
307
308enum GLogColor {
309 COLOR_DEFAULT,
310 COLOR_RED,
311 COLOR_GREEN,
312 COLOR_YELLOW
313};
314
315static GLogColor SeverityToColor(LogSeverity severity) {
316 assert(severity >= 0 && severity < NUM_SEVERITIES);
317 GLogColor color = COLOR_DEFAULT;
318 switch (severity) {
319 case GLOG_INFO:
320 color = COLOR_DEFAULT;
321 break;
322 case GLOG_WARNING:
323 color = COLOR_YELLOW;
324 break;
325 case GLOG_ERROR:
326 case GLOG_FATAL:
327 color = COLOR_RED;
328 break;
329 default:
330 // should never get here.
331 assert(false);
332 }
333 return color;
334}
335
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700336#ifdef GLOG_OS_WINDOWS
Austin Schuh906616c2019-01-21 20:25:11 -0800337
338// Returns the character attribute for the given color.
339static WORD GetColorAttribute(GLogColor color) {
340 switch (color) {
341 case COLOR_RED: return FOREGROUND_RED;
342 case COLOR_GREEN: return FOREGROUND_GREEN;
343 case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
344 default: return 0;
345 }
346}
347
348#else
349
350// Returns the ANSI color code for the given color.
351static const char* GetAnsiColorCode(GLogColor color) {
352 switch (color) {
353 case COLOR_RED: return "1";
354 case COLOR_GREEN: return "2";
355 case COLOR_YELLOW: return "3";
356 case COLOR_DEFAULT: return "";
357 };
358 return NULL; // stop warning about return type.
359}
360
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700361#endif // GLOG_OS_WINDOWS
Austin Schuh906616c2019-01-21 20:25:11 -0800362
363// Safely get max_log_size, overriding to 1 if it somehow gets defined as 0
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700364static uint32 MaxLogSize() {
365 return (FLAGS_max_log_size > 0 && FLAGS_max_log_size < 4096
366 ? FLAGS_max_log_size
367 : 1);
Austin Schuh906616c2019-01-21 20:25:11 -0800368}
369
370// An arbitrary limit on the length of a single log message. This
371// is so that streaming can be done more efficiently.
372const size_t LogMessage::kMaxLogMessageLen = 30000;
373
374struct LogMessage::LogMessageData {
375 LogMessageData();
376
377 int preserved_errno_; // preserved errno
378 // Buffer space; contains complete message text.
379 char message_text_[LogMessage::kMaxLogMessageLen+1];
380 LogStream stream_;
381 char severity_; // What level is this LogMessage logged at?
382 int line_; // line number where logging call is.
383 void (LogMessage::*send_method_)(); // Call this in destructor to send
384 union { // At most one of these is used: union to keep the size low.
385 LogSink* sink_; // NULL or sink to send message to
386 std::vector<std::string>* outvec_; // NULL or vector to push message onto
387 std::string* message_; // NULL or string to write message into
388 };
Austin Schuh906616c2019-01-21 20:25:11 -0800389 size_t num_prefix_chars_; // # of chars of prefix in this message
390 size_t num_chars_to_log_; // # of chars of msg to send to log
391 size_t num_chars_to_syslog_; // # of chars of msg to send to syslog
392 const char* basename_; // basename of file that called LOG
393 const char* fullname_; // fullname of file that called LOG
394 bool has_been_flushed_; // false => data has not been flushed
395 bool first_fatal_; // true => this was first fatal msg
396
397 private:
398 LogMessageData(const LogMessageData&);
399 void operator=(const LogMessageData&);
400};
401
402// A mutex that allows only one thread to log at a time, to keep things from
403// getting jumbled. Some other very uncommon logging operations (like
404// changing the destination file for log messages of a given severity) also
405// lock this mutex. Please be sure that anybody who might possibly need to
406// lock it does so.
407static Mutex log_mutex;
408
409// Number of messages sent at each severity. Under log_mutex.
410int64 LogMessage::num_messages_[NUM_SEVERITIES] = {0, 0, 0, 0};
411
412// Globally disable log writing (if disk is full)
413static bool stop_writing = false;
414
415const char*const LogSeverityNames[NUM_SEVERITIES] = {
416 "INFO", "WARNING", "ERROR", "FATAL"
417};
418
419// Has the user called SetExitOnDFatal(true)?
420static bool exit_on_dfatal = true;
421
422const char* GetLogSeverityName(LogSeverity severity) {
423 return LogSeverityNames[severity];
424}
425
426static bool SendEmailInternal(const char*dest, const char *subject,
427 const char*body, bool use_logging);
428
429base::Logger::~Logger() {
430}
431
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700432#ifdef GLOG_CUSTOM_PREFIX_SUPPORT
433namespace {
434 // Optional user-configured callback to print custom prefixes.
435 CustomPrefixCallback custom_prefix_callback = NULL;
436 // User-provided data to pass to the callback:
437 void* custom_prefix_callback_data = NULL;
438}
439#endif
440
Austin Schuh906616c2019-01-21 20:25:11 -0800441namespace {
442
443// Encapsulates all file-system related state
444class LogFileObject : public base::Logger {
445 public:
446 LogFileObject(LogSeverity severity, const char* base_filename);
447 ~LogFileObject();
448
449 virtual void Write(bool force_flush, // Should we force a flush here?
450 time_t timestamp, // Timestamp for this entry
451 const char* message,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700452 size_t message_len);
Austin Schuh906616c2019-01-21 20:25:11 -0800453
454 // Configuration options
455 void SetBasename(const char* basename);
456 void SetExtension(const char* ext);
457 void SetSymlinkBasename(const char* symlink_basename);
458
459 // Normal flushing routine
460 virtual void Flush();
461
462 // It is the actual file length for the system loggers,
463 // i.e., INFO, ERROR, etc.
464 virtual uint32 LogSize() {
465 MutexLock l(&lock_);
466 return file_length_;
467 }
468
469 // Internal flush routine. Exposed so that FlushLogFilesUnsafe()
470 // can avoid grabbing a lock. Usually Flush() calls it after
471 // acquiring lock_.
472 void FlushUnlocked();
473
474 private:
475 static const uint32 kRolloverAttemptFrequency = 0x20;
476
477 Mutex lock_;
478 bool base_filename_selected_;
479 string base_filename_;
480 string symlink_basename_;
481 string filename_extension_; // option users can specify (eg to add port#)
482 FILE* file_;
483 LogSeverity severity_;
484 uint32 bytes_since_flush_;
485 uint32 dropped_mem_length_;
486 uint32 file_length_;
487 unsigned int rollover_attempt_;
488 int64 next_flush_time_; // cycle count at which to flush log
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700489 WallTime start_time_;
Austin Schuh906616c2019-01-21 20:25:11 -0800490
491 // Actually create a logfile using the value of base_filename_ and the
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700492 // optional argument time_pid_string
Austin Schuh906616c2019-01-21 20:25:11 -0800493 // REQUIRES: lock_ is held
494 bool CreateLogfile(const string& time_pid_string);
495};
496
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700497// Encapsulate all log cleaner related states
498class LogCleaner {
499 public:
500 LogCleaner();
501
502 // Setting overdue_days to 0 days will delete all logs.
503 void Enable(unsigned int overdue_days);
504 void Disable();
505
506 // update next_cleanup_time_
507 void UpdateCleanUpTime();
508
509 void Run(bool base_filename_selected,
510 const string& base_filename,
511 const string& filename_extension);
512
513 bool enabled() const { return enabled_; }
514
515 private:
516 vector<string> GetOverdueLogNames(string log_directory, unsigned int days,
517 const string& base_filename,
518 const string& filename_extension) const;
519
520 bool IsLogFromCurrentProject(const string& filepath,
521 const string& base_filename,
522 const string& filename_extension) const;
523
524 bool IsLogLastModifiedOver(const string& filepath, unsigned int days) const;
525
526 bool enabled_;
527 unsigned int overdue_days_;
528 int64 next_cleanup_time_; // cycle count at which to clean overdue log
529};
530
531LogCleaner log_cleaner;
532
Austin Schuh906616c2019-01-21 20:25:11 -0800533} // namespace
534
535class LogDestination {
536 public:
537 friend class LogMessage;
538 friend void ReprintFatalMessage();
539 friend base::Logger* base::GetLogger(LogSeverity);
540 friend void base::SetLogger(LogSeverity, base::Logger*);
541
542 // These methods are just forwarded to by their global versions.
543 static void SetLogDestination(LogSeverity severity,
544 const char* base_filename);
545 static void SetLogSymlink(LogSeverity severity,
546 const char* symlink_basename);
547 static void AddLogSink(LogSink *destination);
548 static void RemoveLogSink(LogSink *destination);
549 static void SetLogFilenameExtension(const char* filename_extension);
550 static void SetStderrLogging(LogSeverity min_severity);
551 static void SetEmailLogging(LogSeverity min_severity, const char* addresses);
552 static void LogToStderr();
553 // Flush all log files that are at least at the given severity level
554 static void FlushLogFiles(int min_severity);
555 static void FlushLogFilesUnsafe(int min_severity);
556
557 // we set the maximum size of our packet to be 1400, the logic being
558 // to prevent fragmentation.
559 // Really this number is arbitrary.
560 static const int kNetworkBytes = 1400;
561
562 static const string& hostname();
563 static const bool& terminal_supports_color() {
564 return terminal_supports_color_;
565 }
566
567 static void DeleteLogDestinations();
568
569 private:
570 LogDestination(LogSeverity severity, const char* base_filename);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700571 ~LogDestination();
Austin Schuh906616c2019-01-21 20:25:11 -0800572
573 // Take a log message of a particular severity and log it to stderr
574 // iff it's of a high enough severity to deserve it.
575 static void MaybeLogToStderr(LogSeverity severity, const char* message,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700576 size_t message_len, size_t prefix_len);
Austin Schuh906616c2019-01-21 20:25:11 -0800577
578 // Take a log message of a particular severity and log it to email
579 // iff it's of a high enough severity to deserve it.
580 static void MaybeLogToEmail(LogSeverity severity, const char* message,
581 size_t len);
582 // Take a log message of a particular severity and log it to a file
583 // iff the base filename is not "" (which means "don't log to me")
584 static void MaybeLogToLogfile(LogSeverity severity,
585 time_t timestamp,
586 const char* message, size_t len);
587 // Take a log message of a particular severity and log it to the file
588 // for that severity and also for all files with severity less than
589 // this severity.
590 static void LogToAllLogfiles(LogSeverity severity,
591 time_t timestamp,
592 const char* message, size_t len);
593
594 // Send logging info to all registered sinks.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700595 static void LogToSinks(LogSeverity severity, const char* full_filename,
596 const char* base_filename, int line,
597 const LogMessageTime& logmsgtime, const char* message,
Austin Schuh906616c2019-01-21 20:25:11 -0800598 size_t message_len);
599
600 // Wait for all registered sinks via WaitTillSent
601 // including the optional one in "data".
602 static void WaitForSinks(LogMessage::LogMessageData* data);
603
604 static LogDestination* log_destination(LogSeverity severity);
605
606 LogFileObject fileobject_;
607 base::Logger* logger_; // Either &fileobject_, or wrapper around it
608
609 static LogDestination* log_destinations_[NUM_SEVERITIES];
610 static LogSeverity email_logging_severity_;
611 static string addresses_;
612 static string hostname_;
613 static bool terminal_supports_color_;
614
615 // arbitrary global logging destinations.
616 static vector<LogSink*>* sinks_;
617
618 // Protects the vector sinks_,
619 // but not the LogSink objects its elements reference.
620 static Mutex sink_mutex_;
621
622 // Disallow
623 LogDestination(const LogDestination&);
624 LogDestination& operator=(const LogDestination&);
625};
626
627// Errors do not get logged to email by default.
628LogSeverity LogDestination::email_logging_severity_ = 99999;
629
630string LogDestination::addresses_;
631string LogDestination::hostname_;
632
633vector<LogSink*>* LogDestination::sinks_ = NULL;
634Mutex LogDestination::sink_mutex_;
635bool LogDestination::terminal_supports_color_ = TerminalSupportsColor();
636
637/* static */
638const string& LogDestination::hostname() {
639 if (hostname_.empty()) {
640 GetHostName(&hostname_);
641 if (hostname_.empty()) {
642 hostname_ = "(unknown)";
643 }
644 }
645 return hostname_;
646}
647
648LogDestination::LogDestination(LogSeverity severity,
649 const char* base_filename)
650 : fileobject_(severity, base_filename),
651 logger_(&fileobject_) {
652}
653
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700654LogDestination::~LogDestination() {
655 if (logger_ && logger_ != &fileobject_) {
656 // Delete user-specified logger set via SetLogger().
657 delete logger_;
658 }
659}
660
Austin Schuh906616c2019-01-21 20:25:11 -0800661inline void LogDestination::FlushLogFilesUnsafe(int min_severity) {
662 // assume we have the log_mutex or we simply don't care
663 // about it
664 for (int i = min_severity; i < NUM_SEVERITIES; i++) {
665 LogDestination* log = log_destinations_[i];
666 if (log != NULL) {
667 // Flush the base fileobject_ logger directly instead of going
668 // through any wrappers to reduce chance of deadlock.
669 log->fileobject_.FlushUnlocked();
670 }
671 }
672}
673
674inline void LogDestination::FlushLogFiles(int min_severity) {
675 // Prevent any subtle race conditions by wrapping a mutex lock around
676 // all this stuff.
677 MutexLock l(&log_mutex);
678 for (int i = min_severity; i < NUM_SEVERITIES; i++) {
679 LogDestination* log = log_destination(i);
680 if (log != NULL) {
681 log->logger_->Flush();
682 }
683 }
684}
685
686inline void LogDestination::SetLogDestination(LogSeverity severity,
687 const char* base_filename) {
688 assert(severity >= 0 && severity < NUM_SEVERITIES);
689 // Prevent any subtle race conditions by wrapping a mutex lock around
690 // all this stuff.
691 MutexLock l(&log_mutex);
692 log_destination(severity)->fileobject_.SetBasename(base_filename);
693}
694
695inline void LogDestination::SetLogSymlink(LogSeverity severity,
696 const char* symlink_basename) {
697 CHECK_GE(severity, 0);
698 CHECK_LT(severity, NUM_SEVERITIES);
699 MutexLock l(&log_mutex);
700 log_destination(severity)->fileobject_.SetSymlinkBasename(symlink_basename);
701}
702
703inline void LogDestination::AddLogSink(LogSink *destination) {
704 // Prevent any subtle race conditions by wrapping a mutex lock around
705 // all this stuff.
706 MutexLock l(&sink_mutex_);
707 if (!sinks_) sinks_ = new vector<LogSink*>;
708 sinks_->push_back(destination);
709}
710
711inline void LogDestination::RemoveLogSink(LogSink *destination) {
712 // Prevent any subtle race conditions by wrapping a mutex lock around
713 // all this stuff.
714 MutexLock l(&sink_mutex_);
715 // This doesn't keep the sinks in order, but who cares?
716 if (sinks_) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700717 sinks_->erase(std::remove(sinks_->begin(), sinks_->end(), destination), sinks_->end());
Austin Schuh906616c2019-01-21 20:25:11 -0800718 }
719}
720
721inline void LogDestination::SetLogFilenameExtension(const char* ext) {
722 // Prevent any subtle race conditions by wrapping a mutex lock around
723 // all this stuff.
724 MutexLock l(&log_mutex);
725 for ( int severity = 0; severity < NUM_SEVERITIES; ++severity ) {
726 log_destination(severity)->fileobject_.SetExtension(ext);
727 }
728}
729
730inline void LogDestination::SetStderrLogging(LogSeverity min_severity) {
731 assert(min_severity >= 0 && min_severity < NUM_SEVERITIES);
732 // Prevent any subtle race conditions by wrapping a mutex lock around
733 // all this stuff.
734 MutexLock l(&log_mutex);
735 FLAGS_stderrthreshold = min_severity;
736}
737
738inline void LogDestination::LogToStderr() {
739 // *Don't* put this stuff in a mutex lock, since SetStderrLogging &
740 // SetLogDestination already do the locking!
741 SetStderrLogging(0); // thus everything is "also" logged to stderr
742 for ( int i = 0; i < NUM_SEVERITIES; ++i ) {
743 SetLogDestination(i, ""); // "" turns off logging to a logfile
744 }
745}
746
747inline void LogDestination::SetEmailLogging(LogSeverity min_severity,
748 const char* addresses) {
749 assert(min_severity >= 0 && min_severity < NUM_SEVERITIES);
750 // Prevent any subtle race conditions by wrapping a mutex lock around
751 // all this stuff.
752 MutexLock l(&log_mutex);
753 LogDestination::email_logging_severity_ = min_severity;
754 LogDestination::addresses_ = addresses;
755}
756
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700757static void ColoredWriteToStderrOrStdout(FILE* output, LogSeverity severity,
758 const char* message, size_t len) {
759 bool is_stdout = (output == stdout);
760 const GLogColor color = (LogDestination::terminal_supports_color() &&
761 ((!is_stdout && FLAGS_colorlogtostderr) ||
762 (is_stdout && FLAGS_colorlogtostdout)))
763 ? SeverityToColor(severity)
764 : COLOR_DEFAULT;
Austin Schuh906616c2019-01-21 20:25:11 -0800765
766 // Avoid using cerr from this module since we may get called during
767 // exit code, and cerr may be partially or fully destroyed by then.
768 if (COLOR_DEFAULT == color) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700769 fwrite(message, len, 1, output);
Austin Schuh906616c2019-01-21 20:25:11 -0800770 return;
771 }
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700772#ifdef GLOG_OS_WINDOWS
773 const HANDLE output_handle =
774 GetStdHandle(is_stdout ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
Austin Schuh906616c2019-01-21 20:25:11 -0800775
776 // Gets the current text color.
777 CONSOLE_SCREEN_BUFFER_INFO buffer_info;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700778 GetConsoleScreenBufferInfo(output_handle, &buffer_info);
Austin Schuh906616c2019-01-21 20:25:11 -0800779 const WORD old_color_attrs = buffer_info.wAttributes;
780
781 // We need to flush the stream buffers into the console before each
782 // SetConsoleTextAttribute call lest it affect the text that is already
783 // printed but has not yet reached the console.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700784 fflush(output);
785 SetConsoleTextAttribute(output_handle,
Austin Schuh906616c2019-01-21 20:25:11 -0800786 GetColorAttribute(color) | FOREGROUND_INTENSITY);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700787 fwrite(message, len, 1, output);
788 fflush(output);
Austin Schuh906616c2019-01-21 20:25:11 -0800789 // Restores the text color.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700790 SetConsoleTextAttribute(output_handle, old_color_attrs);
Austin Schuh906616c2019-01-21 20:25:11 -0800791#else
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700792 fprintf(output, "\033[0;3%sm", GetAnsiColorCode(color));
793 fwrite(message, len, 1, output);
794 fprintf(output, "\033[m"); // Resets the terminal to default.
795#endif // GLOG_OS_WINDOWS
796}
797
798static void ColoredWriteToStdout(LogSeverity severity, const char* message,
799 size_t len) {
800 FILE* output = stdout;
801 // We also need to send logs to the stderr when the severity is
802 // higher or equal to the stderr threshold.
803 if (severity >= FLAGS_stderrthreshold) {
804 output = stderr;
805 }
806 ColoredWriteToStderrOrStdout(output, severity, message, len);
807}
808
809static void ColoredWriteToStderr(LogSeverity severity, const char* message,
810 size_t len) {
811 ColoredWriteToStderrOrStdout(stderr, severity, message, len);
Austin Schuh906616c2019-01-21 20:25:11 -0800812}
813
814static void WriteToStderr(const char* message, size_t len) {
815 // Avoid using cerr from this module since we may get called during
816 // exit code, and cerr may be partially or fully destroyed by then.
817 fwrite(message, len, 1, stderr);
818}
819
820inline void LogDestination::MaybeLogToStderr(LogSeverity severity,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700821 const char* message, size_t message_len, size_t prefix_len) {
Austin Schuh906616c2019-01-21 20:25:11 -0800822 if ((severity >= FLAGS_stderrthreshold) || FLAGS_alsologtostderr) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700823 ColoredWriteToStderr(severity, message, message_len);
824#ifdef GLOG_OS_WINDOWS
825 (void) prefix_len;
Austin Schuh906616c2019-01-21 20:25:11 -0800826 // On Windows, also output to the debugger
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700827 ::OutputDebugStringA(message);
828#elif defined(__ANDROID__)
829 // On Android, also output to logcat
830 const int android_log_levels[NUM_SEVERITIES] = {
831 ANDROID_LOG_INFO,
832 ANDROID_LOG_WARN,
833 ANDROID_LOG_ERROR,
834 ANDROID_LOG_FATAL,
835 };
836 __android_log_write(android_log_levels[severity],
837 glog_internal_namespace_::ProgramInvocationShortName(),
838 message + prefix_len);
839#else
840 (void) prefix_len;
Austin Schuh906616c2019-01-21 20:25:11 -0800841#endif
842 }
843}
844
845
846inline void LogDestination::MaybeLogToEmail(LogSeverity severity,
847 const char* message, size_t len) {
848 if (severity >= email_logging_severity_ ||
849 severity >= FLAGS_logemaillevel) {
850 string to(FLAGS_alsologtoemail);
851 if (!addresses_.empty()) {
852 if (!to.empty()) {
853 to += ",";
854 }
855 to += addresses_;
856 }
857 const string subject(string("[LOG] ") + LogSeverityNames[severity] + ": " +
858 glog_internal_namespace_::ProgramInvocationShortName());
859 string body(hostname());
860 body += "\n\n";
861 body.append(message, len);
862
863 // should NOT use SendEmail(). The caller of this function holds the
864 // log_mutex and SendEmail() calls LOG/VLOG which will block trying to
865 // acquire the log_mutex object. Use SendEmailInternal() and set
866 // use_logging to false.
867 SendEmailInternal(to.c_str(), subject.c_str(), body.c_str(), false);
868 }
869}
870
871
872inline void LogDestination::MaybeLogToLogfile(LogSeverity severity,
873 time_t timestamp,
874 const char* message,
875 size_t len) {
876 const bool should_flush = severity > FLAGS_logbuflevel;
877 LogDestination* destination = log_destination(severity);
878 destination->logger_->Write(should_flush, timestamp, message, len);
879}
880
881inline void LogDestination::LogToAllLogfiles(LogSeverity severity,
882 time_t timestamp,
883 const char* message,
884 size_t len) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700885 if (FLAGS_logtostdout) { // global flag: never log to file
886 ColoredWriteToStdout(severity, message, len);
887 } else if (FLAGS_logtostderr) { // global flag: never log to file
Austin Schuh906616c2019-01-21 20:25:11 -0800888 ColoredWriteToStderr(severity, message, len);
889 } else {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700890 for (int i = severity; i >= 0; --i) {
Austin Schuh906616c2019-01-21 20:25:11 -0800891 LogDestination::MaybeLogToLogfile(i, timestamp, message, len);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700892 }
Austin Schuh906616c2019-01-21 20:25:11 -0800893 }
894}
895
896inline void LogDestination::LogToSinks(LogSeverity severity,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700897 const char* full_filename,
898 const char* base_filename, int line,
899 const LogMessageTime& logmsgtime,
Austin Schuh906616c2019-01-21 20:25:11 -0800900 const char* message,
901 size_t message_len) {
902 ReaderMutexLock l(&sink_mutex_);
903 if (sinks_) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700904 for (size_t i = sinks_->size(); i-- > 0; ) {
Austin Schuh906616c2019-01-21 20:25:11 -0800905 (*sinks_)[i]->send(severity, full_filename, base_filename,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700906 line, logmsgtime, message, message_len);
Austin Schuh906616c2019-01-21 20:25:11 -0800907 }
908 }
909}
910
911inline void LogDestination::WaitForSinks(LogMessage::LogMessageData* data) {
912 ReaderMutexLock l(&sink_mutex_);
913 if (sinks_) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700914 for (size_t i = sinks_->size(); i-- > 0; ) {
Austin Schuh906616c2019-01-21 20:25:11 -0800915 (*sinks_)[i]->WaitTillSent();
916 }
917 }
918 const bool send_to_sink =
919 (data->send_method_ == &LogMessage::SendToSink) ||
920 (data->send_method_ == &LogMessage::SendToSinkAndLog);
921 if (send_to_sink && data->sink_ != NULL) {
922 data->sink_->WaitTillSent();
923 }
924}
925
926LogDestination* LogDestination::log_destinations_[NUM_SEVERITIES];
927
928inline LogDestination* LogDestination::log_destination(LogSeverity severity) {
929 assert(severity >=0 && severity < NUM_SEVERITIES);
930 if (!log_destinations_[severity]) {
931 log_destinations_[severity] = new LogDestination(severity, NULL);
932 }
933 return log_destinations_[severity];
934}
935
936void LogDestination::DeleteLogDestinations() {
937 for (int severity = 0; severity < NUM_SEVERITIES; ++severity) {
938 delete log_destinations_[severity];
939 log_destinations_[severity] = NULL;
940 }
941 MutexLock l(&sink_mutex_);
942 delete sinks_;
943 sinks_ = NULL;
944}
945
946namespace {
947
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700948std::string g_application_fingerprint;
949
950} // namespace
951
952void SetApplicationFingerprint(const std::string& fingerprint) {
953 g_application_fingerprint = fingerprint;
954}
955
956namespace {
957
958// Directory delimiter; Windows supports both forward slashes and backslashes
959#ifdef GLOG_OS_WINDOWS
960const char possible_dir_delim[] = {'\\', '/'};
961#else
962const char possible_dir_delim[] = {'/'};
963#endif
964
965string PrettyDuration(int secs) {
966 std::stringstream result;
967 int mins = secs / 60;
968 int hours = mins / 60;
969 mins = mins % 60;
970 secs = secs % 60;
971 result.fill('0');
972 result << hours << ':' << setw(2) << mins << ':' << setw(2) << secs;
973 return result.str();
974}
975
976
Austin Schuh906616c2019-01-21 20:25:11 -0800977LogFileObject::LogFileObject(LogSeverity severity,
978 const char* base_filename)
979 : base_filename_selected_(base_filename != NULL),
980 base_filename_((base_filename != NULL) ? base_filename : ""),
981 symlink_basename_(glog_internal_namespace_::ProgramInvocationShortName()),
982 filename_extension_(),
983 file_(NULL),
984 severity_(severity),
985 bytes_since_flush_(0),
986 dropped_mem_length_(0),
987 file_length_(0),
988 rollover_attempt_(kRolloverAttemptFrequency-1),
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700989 next_flush_time_(0),
990 start_time_(WallTime_Now()) {
Austin Schuh906616c2019-01-21 20:25:11 -0800991 assert(severity >= 0);
992 assert(severity < NUM_SEVERITIES);
993}
994
995LogFileObject::~LogFileObject() {
996 MutexLock l(&lock_);
997 if (file_ != NULL) {
998 fclose(file_);
999 file_ = NULL;
1000 }
1001}
1002
1003void LogFileObject::SetBasename(const char* basename) {
1004 MutexLock l(&lock_);
1005 base_filename_selected_ = true;
1006 if (base_filename_ != basename) {
1007 // Get rid of old log file since we are changing names
1008 if (file_ != NULL) {
1009 fclose(file_);
1010 file_ = NULL;
1011 rollover_attempt_ = kRolloverAttemptFrequency-1;
1012 }
1013 base_filename_ = basename;
1014 }
1015}
1016
1017void LogFileObject::SetExtension(const char* ext) {
1018 MutexLock l(&lock_);
1019 if (filename_extension_ != ext) {
1020 // Get rid of old log file since we are changing names
1021 if (file_ != NULL) {
1022 fclose(file_);
1023 file_ = NULL;
1024 rollover_attempt_ = kRolloverAttemptFrequency-1;
1025 }
1026 filename_extension_ = ext;
1027 }
1028}
1029
1030void LogFileObject::SetSymlinkBasename(const char* symlink_basename) {
1031 MutexLock l(&lock_);
1032 symlink_basename_ = symlink_basename;
1033}
1034
1035void LogFileObject::Flush() {
1036 MutexLock l(&lock_);
1037 FlushUnlocked();
1038}
1039
1040void LogFileObject::FlushUnlocked(){
1041 if (file_ != NULL) {
1042 fflush(file_);
1043 bytes_since_flush_ = 0;
1044 }
1045 // Figure out when we are due for another flush.
1046 const int64 next = (FLAGS_logbufsecs
1047 * static_cast<int64>(1000000)); // in usec
1048 next_flush_time_ = CycleClock_Now() + UsecToCycles(next);
1049}
1050
1051bool LogFileObject::CreateLogfile(const string& time_pid_string) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001052 string string_filename = base_filename_;
1053 if (FLAGS_timestamp_in_logfile_name) {
1054 string_filename += time_pid_string;
1055 }
1056 string_filename += filename_extension_;
Austin Schuh906616c2019-01-21 20:25:11 -08001057 const char* filename = string_filename.c_str();
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001058 //only write to files, create if non-existant.
1059 int flags = O_WRONLY | O_CREAT;
1060 if (FLAGS_timestamp_in_logfile_name) {
1061 //demand that the file is unique for our timestamp (fail if it exists).
1062 flags = flags | O_EXCL;
1063 }
1064 int fd = open(filename, flags, static_cast<mode_t>(FLAGS_logfile_mode));
Austin Schuh906616c2019-01-21 20:25:11 -08001065 if (fd == -1) return false;
1066#ifdef HAVE_FCNTL
1067 // Mark the file close-on-exec. We don't really care if this fails
1068 fcntl(fd, F_SETFD, FD_CLOEXEC);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001069
1070 // Mark the file as exclusive write access to avoid two clients logging to the
1071 // same file. This applies particularly when !FLAGS_timestamp_in_logfile_name
1072 // (otherwise open would fail because the O_EXCL flag on similar filename).
1073 // locks are released on unlock or close() automatically, only after log is
1074 // released.
1075 // This will work after a fork as it is not inherited (not stored in the fd).
1076 // Lock will not be lost because the file is opened with exclusive lock (write)
1077 // and we will never read from it inside the process.
1078 // TODO windows implementation of this (as flock is not available on mingw).
1079 static struct flock w_lock;
1080
1081 w_lock.l_type = F_WRLCK;
1082 w_lock.l_start = 0;
1083 w_lock.l_whence = SEEK_SET;
1084 w_lock.l_len = 0;
1085
1086 int wlock_ret = fcntl(fd, F_SETLK, &w_lock);
1087 if (wlock_ret == -1) {
1088 close(fd); //as we are failing already, do not check errors here
1089 return false;
1090 }
Austin Schuh906616c2019-01-21 20:25:11 -08001091#endif
1092
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001093 //fdopen in append mode so if the file exists it will fseek to the end
Austin Schuh906616c2019-01-21 20:25:11 -08001094 file_ = fdopen(fd, "a"); // Make a FILE*.
1095 if (file_ == NULL) { // Man, we're screwed!
1096 close(fd);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001097 if (FLAGS_timestamp_in_logfile_name) {
1098 unlink(filename); // Erase the half-baked evidence: an unusable log file, only if we just created it.
1099 }
Austin Schuh906616c2019-01-21 20:25:11 -08001100 return false;
1101 }
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001102#ifdef GLOG_OS_WINDOWS
1103 // https://github.com/golang/go/issues/27638 - make sure we seek to the end to append
1104 // empirically replicated with wine over mingw build
1105 if (!FLAGS_timestamp_in_logfile_name) {
1106 if (fseek(file_, 0, SEEK_END) != 0) {
1107 return false;
1108 }
1109 }
1110#endif
Austin Schuh906616c2019-01-21 20:25:11 -08001111 // We try to create a symlink called <program_name>.<severity>,
1112 // which is easier to use. (Every time we create a new logfile,
1113 // we destroy the old symlink and create a new one, so it always
1114 // points to the latest logfile.) If it fails, we're sad but it's
1115 // no error.
1116 if (!symlink_basename_.empty()) {
1117 // take directory from filename
1118 const char* slash = strrchr(filename, PATH_SEPARATOR);
1119 const string linkname =
1120 symlink_basename_ + '.' + LogSeverityNames[severity_];
1121 string linkpath;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001122 if ( slash ) linkpath = string(filename, static_cast<size_t>(slash-filename+1)); // get dirname
Austin Schuh906616c2019-01-21 20:25:11 -08001123 linkpath += linkname;
1124 unlink(linkpath.c_str()); // delete old one if it exists
1125
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001126#if defined(GLOG_OS_WINDOWS)
Austin Schuh906616c2019-01-21 20:25:11 -08001127 // TODO(hamaji): Create lnk file on Windows?
1128#elif defined(HAVE_UNISTD_H)
1129 // We must have unistd.h.
1130 // Make the symlink be relative (in the same dir) so that if the
1131 // entire log directory gets relocated the link is still valid.
1132 const char *linkdest = slash ? (slash + 1) : filename;
1133 if (symlink(linkdest, linkpath.c_str()) != 0) {
1134 // silently ignore failures
1135 }
1136
1137 // Make an additional link to the log file in a place specified by
1138 // FLAGS_log_link, if indicated
1139 if (!FLAGS_log_link.empty()) {
1140 linkpath = FLAGS_log_link + "/" + linkname;
1141 unlink(linkpath.c_str()); // delete old one if it exists
1142 if (symlink(filename, linkpath.c_str()) != 0) {
1143 // silently ignore failures
1144 }
1145 }
1146#endif
1147 }
1148
1149 return true; // Everything worked
1150}
1151
1152void LogFileObject::Write(bool force_flush,
1153 time_t timestamp,
1154 const char* message,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001155 size_t message_len) {
Austin Schuh906616c2019-01-21 20:25:11 -08001156 MutexLock l(&lock_);
1157
1158 // We don't log if the base_name_ is "" (which means "don't write")
1159 if (base_filename_selected_ && base_filename_.empty()) {
1160 return;
1161 }
1162
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001163 if (file_length_ >> 20U >= MaxLogSize() || PidHasChanged()) {
Austin Schuh906616c2019-01-21 20:25:11 -08001164 if (file_ != NULL) fclose(file_);
1165 file_ = NULL;
1166 file_length_ = bytes_since_flush_ = dropped_mem_length_ = 0;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001167 rollover_attempt_ = kRolloverAttemptFrequency - 1;
Austin Schuh906616c2019-01-21 20:25:11 -08001168 }
1169
1170 // If there's no destination file, make one before outputting
1171 if (file_ == NULL) {
1172 // Try to rollover the log file every 32 log messages. The only time
1173 // this could matter would be when we have trouble creating the log
1174 // file. If that happens, we'll lose lots of log messages, of course!
1175 if (++rollover_attempt_ != kRolloverAttemptFrequency) return;
1176 rollover_attempt_ = 0;
1177
1178 struct ::tm tm_time;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001179 if (FLAGS_log_utc_time) {
1180 gmtime_r(&timestamp, &tm_time);
1181 } else {
1182 localtime_r(&timestamp, &tm_time);
1183 }
Austin Schuh906616c2019-01-21 20:25:11 -08001184
1185 // The logfile's filename will have the date/time & pid in it
1186 ostringstream time_pid_stream;
1187 time_pid_stream.fill('0');
1188 time_pid_stream << 1900+tm_time.tm_year
1189 << setw(2) << 1+tm_time.tm_mon
1190 << setw(2) << tm_time.tm_mday
1191 << '-'
1192 << setw(2) << tm_time.tm_hour
1193 << setw(2) << tm_time.tm_min
1194 << setw(2) << tm_time.tm_sec
1195 << '.'
1196 << GetMainThreadPid();
1197 const string& time_pid_string = time_pid_stream.str();
1198
1199 if (base_filename_selected_) {
1200 if (!CreateLogfile(time_pid_string)) {
1201 perror("Could not create log file");
1202 fprintf(stderr, "COULD NOT CREATE LOGFILE '%s'!\n",
1203 time_pid_string.c_str());
1204 return;
1205 }
1206 } else {
1207 // If no base filename for logs of this severity has been set, use a
1208 // default base filename of
1209 // "<program name>.<hostname>.<user name>.log.<severity level>.". So
1210 // logfiles will have names like
1211 // webserver.examplehost.root.log.INFO.19990817-150000.4354, where
1212 // 19990817 is a date (1999 August 17), 150000 is a time (15:00:00),
1213 // and 4354 is the pid of the logging process. The date & time reflect
1214 // when the file was created for output.
1215 //
1216 // Where does the file get put? Successively try the directories
1217 // "/tmp", and "."
1218 string stripped_filename(
1219 glog_internal_namespace_::ProgramInvocationShortName());
1220 string hostname;
1221 GetHostName(&hostname);
1222
1223 string uidname = MyUserName();
1224 // We should not call CHECK() here because this function can be
1225 // called after holding on to log_mutex. We don't want to
1226 // attempt to hold on to the same mutex, and get into a
1227 // deadlock. Simply use a name like invalid-user.
1228 if (uidname.empty()) uidname = "invalid-user";
1229
1230 stripped_filename = stripped_filename+'.'+hostname+'.'
1231 +uidname+".log."
1232 +LogSeverityNames[severity_]+'.';
1233 // We're going to (potentially) try to put logs in several different dirs
1234 const vector<string> & log_dirs = GetLoggingDirectories();
1235
1236 // Go through the list of dirs, and try to create the log file in each
1237 // until we succeed or run out of options
1238 bool success = false;
1239 for (vector<string>::const_iterator dir = log_dirs.begin();
1240 dir != log_dirs.end();
1241 ++dir) {
1242 base_filename_ = *dir + "/" + stripped_filename;
1243 if ( CreateLogfile(time_pid_string) ) {
1244 success = true;
1245 break;
1246 }
1247 }
1248 // If we never succeeded, we have to give up
1249 if ( success == false ) {
1250 perror("Could not create logging file");
1251 fprintf(stderr, "COULD NOT CREATE A LOGGINGFILE %s!",
1252 time_pid_string.c_str());
1253 return;
1254 }
1255 }
1256
1257 // Write a header message into the log file
1258 ostringstream file_header_stream;
1259 file_header_stream.fill('0');
1260 file_header_stream << "Log file created at: "
1261 << 1900+tm_time.tm_year << '/'
1262 << setw(2) << 1+tm_time.tm_mon << '/'
1263 << setw(2) << tm_time.tm_mday
1264 << ' '
1265 << setw(2) << tm_time.tm_hour << ':'
1266 << setw(2) << tm_time.tm_min << ':'
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001267 << setw(2) << tm_time.tm_sec << (FLAGS_log_utc_time ? " UTC\n" : "\n")
Austin Schuh906616c2019-01-21 20:25:11 -08001268 << "Running on machine: "
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001269 << LogDestination::hostname() << '\n';
1270
1271 if(!g_application_fingerprint.empty()) {
1272 file_header_stream << "Application fingerprint: " << g_application_fingerprint << '\n';
1273 }
1274 const char* const date_time_format = FLAGS_log_year_in_prefix
1275 ? "yyyymmdd hh:mm:ss.uuuuuu"
1276 : "mmdd hh:mm:ss.uuuuuu";
1277 file_header_stream << "Running duration (h:mm:ss): "
1278 << PrettyDuration(static_cast<int>(WallTime_Now() - start_time_)) << '\n'
1279 << "Log line format: [IWEF]" << date_time_format << " "
Austin Schuh906616c2019-01-21 20:25:11 -08001280 << "threadid file:line] msg" << '\n';
1281 const string& file_header_string = file_header_stream.str();
1282
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001283 const size_t header_len = file_header_string.size();
Austin Schuh906616c2019-01-21 20:25:11 -08001284 fwrite(file_header_string.data(), 1, header_len, file_);
1285 file_length_ += header_len;
1286 bytes_since_flush_ += header_len;
1287 }
1288
1289 // Write to LOG file
1290 if ( !stop_writing ) {
1291 // fwrite() doesn't return an error when the disk is full, for
1292 // messages that are less than 4096 bytes. When the disk is full,
1293 // it returns the message length for messages that are less than
1294 // 4096 bytes. fwrite() returns 4096 for message lengths that are
1295 // greater than 4096, thereby indicating an error.
1296 errno = 0;
1297 fwrite(message, 1, message_len, file_);
1298 if ( FLAGS_stop_logging_if_full_disk &&
1299 errno == ENOSPC ) { // disk full, stop writing to disk
1300 stop_writing = true; // until the disk is
1301 return;
1302 } else {
1303 file_length_ += message_len;
1304 bytes_since_flush_ += message_len;
1305 }
1306 } else {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001307 if (CycleClock_Now() >= next_flush_time_) {
Austin Schuh906616c2019-01-21 20:25:11 -08001308 stop_writing = false; // check to see if disk has free space.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001309 }
Austin Schuh906616c2019-01-21 20:25:11 -08001310 return; // no need to flush
1311 }
1312
1313 // See important msgs *now*. Also, flush logs at least every 10^6 chars,
1314 // or every "FLAGS_logbufsecs" seconds.
1315 if ( force_flush ||
1316 (bytes_since_flush_ >= 1000000) ||
1317 (CycleClock_Now() >= next_flush_time_) ) {
1318 FlushUnlocked();
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001319#ifdef GLOG_OS_LINUX
Austin Schuh906616c2019-01-21 20:25:11 -08001320 // Only consider files >= 3MiB
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001321 if (FLAGS_drop_log_memory && file_length_ >= (3U << 20U)) {
Austin Schuh906616c2019-01-21 20:25:11 -08001322 // Don't evict the most recent 1-2MiB so as not to impact a tailer
1323 // of the log file and to avoid page rounding issue on linux < 4.7
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001324 uint32 total_drop_length =
1325 (file_length_ & ~((1U << 20U) - 1U)) - (1U << 20U);
Austin Schuh906616c2019-01-21 20:25:11 -08001326 uint32 this_drop_length = total_drop_length - dropped_mem_length_;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001327 if (this_drop_length >= (2U << 20U)) {
Austin Schuh906616c2019-01-21 20:25:11 -08001328 // Only advise when >= 2MiB to drop
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001329# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
1330 // 'posix_fadvise' introduced in API 21:
1331 // * https://android.googlesource.com/platform/bionic/+/6880f936173081297be0dc12f687d341b86a4cfa/libc/libc.map.txt#732
1332# else
1333 posix_fadvise(fileno(file_), static_cast<off_t>(dropped_mem_length_),
1334 static_cast<off_t>(this_drop_length),
Austin Schuh906616c2019-01-21 20:25:11 -08001335 POSIX_FADV_DONTNEED);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001336# endif
Austin Schuh906616c2019-01-21 20:25:11 -08001337 dropped_mem_length_ = total_drop_length;
1338 }
1339 }
1340#endif
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001341
1342 // Remove old logs
1343 if (log_cleaner.enabled()) {
1344 log_cleaner.Run(base_filename_selected_,
1345 base_filename_,
1346 filename_extension_);
1347 }
Austin Schuh906616c2019-01-21 20:25:11 -08001348 }
1349}
1350
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001351LogCleaner::LogCleaner() : enabled_(false), overdue_days_(7), next_cleanup_time_(0) {}
Austin Schuh906616c2019-01-21 20:25:11 -08001352
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001353void LogCleaner::Enable(unsigned int overdue_days) {
1354 enabled_ = true;
1355 overdue_days_ = overdue_days;
1356}
1357
1358void LogCleaner::Disable() {
1359 enabled_ = false;
1360}
1361
1362void LogCleaner::UpdateCleanUpTime() {
1363 const int64 next = (FLAGS_logcleansecs
1364 * 1000000); // in usec
1365 next_cleanup_time_ = CycleClock_Now() + UsecToCycles(next);
1366}
1367
1368void LogCleaner::Run(bool base_filename_selected,
1369 const string& base_filename,
1370 const string& filename_extension) {
1371 assert(enabled_);
1372 assert(!base_filename_selected || !base_filename.empty());
1373
1374 // avoid scanning logs too frequently
1375 if (CycleClock_Now() < next_cleanup_time_) {
1376 return;
1377 }
1378 UpdateCleanUpTime();
1379
1380 vector<string> dirs;
1381
1382 if (!base_filename_selected) {
1383 dirs = GetLoggingDirectories();
1384 } else {
1385 size_t pos = base_filename.find_last_of(possible_dir_delim, string::npos,
1386 sizeof(possible_dir_delim));
1387 if (pos != string::npos) {
1388 string dir = base_filename.substr(0, pos + 1);
1389 dirs.push_back(dir);
1390 } else {
1391 dirs.push_back(".");
1392 }
1393 }
1394
1395 for (size_t i = 0; i < dirs.size(); i++) {
1396 vector<string> logs = GetOverdueLogNames(dirs[i],
1397 overdue_days_,
1398 base_filename,
1399 filename_extension);
1400 for (size_t j = 0; j < logs.size(); j++) {
1401 static_cast<void>(unlink(logs[j].c_str()));
1402 }
1403 }
1404}
1405
1406vector<string> LogCleaner::GetOverdueLogNames(
1407 string log_directory, unsigned int days, const string& base_filename,
1408 const string& filename_extension) const {
1409 // The names of overdue logs.
1410 vector<string> overdue_log_names;
1411
1412 // Try to get all files within log_directory.
1413 DIR *dir;
1414 struct dirent *ent;
1415
1416 if ((dir = opendir(log_directory.c_str()))) {
1417 while ((ent = readdir(dir))) {
1418 if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
1419 continue;
1420 }
1421
1422 string filepath = ent->d_name;
1423 const char* const dir_delim_end =
1424 possible_dir_delim + sizeof(possible_dir_delim);
1425
1426 if (!log_directory.empty() &&
1427 std::find(possible_dir_delim, dir_delim_end,
1428 log_directory[log_directory.size() - 1]) != dir_delim_end) {
1429 filepath = log_directory + filepath;
1430 }
1431
1432 if (IsLogFromCurrentProject(filepath, base_filename, filename_extension) &&
1433 IsLogLastModifiedOver(filepath, days)) {
1434 overdue_log_names.push_back(filepath);
1435 }
1436 }
1437 closedir(dir);
1438 }
1439
1440 return overdue_log_names;
1441}
1442
1443bool LogCleaner::IsLogFromCurrentProject(const string& filepath,
1444 const string& base_filename,
1445 const string& filename_extension) const {
1446 // We should remove duplicated delimiters from `base_filename`, e.g.,
1447 // before: "/tmp//<base_filename>.<create_time>.<pid>"
1448 // after: "/tmp/<base_filename>.<create_time>.<pid>"
1449 string cleaned_base_filename;
1450
1451 const char* const dir_delim_end =
1452 possible_dir_delim + sizeof(possible_dir_delim);
1453
1454 size_t real_filepath_size = filepath.size();
1455 for (size_t i = 0; i < base_filename.size(); ++i) {
1456 const char& c = base_filename[i];
1457
1458 if (cleaned_base_filename.empty()) {
1459 cleaned_base_filename += c;
1460 } else if (std::find(possible_dir_delim, dir_delim_end, c) ==
1461 dir_delim_end ||
1462 (!cleaned_base_filename.empty() &&
1463 c != cleaned_base_filename[cleaned_base_filename.size() - 1])) {
1464 cleaned_base_filename += c;
1465 }
1466 }
1467
1468 // Return early if the filename doesn't start with `cleaned_base_filename`.
1469 if (filepath.find(cleaned_base_filename) != 0) {
1470 return false;
1471 }
1472
1473 // Check if in the string `filename_extension` is right next to
1474 // `cleaned_base_filename` in `filepath` if the user
1475 // has set a custom filename extension.
1476 if (!filename_extension.empty()) {
1477 if (cleaned_base_filename.size() >= real_filepath_size) {
1478 return false;
1479 }
1480 // for origin version, `filename_extension` is middle of the `filepath`.
1481 string ext = filepath.substr(cleaned_base_filename.size(), filename_extension.size());
1482 if (ext == filename_extension) {
1483 cleaned_base_filename += filename_extension;
1484 }
1485 else {
1486 // for new version, `filename_extension` is right of the `filepath`.
1487 if (filename_extension.size() >= real_filepath_size) {
1488 return false;
1489 }
1490 real_filepath_size = filepath.size() - filename_extension.size();
1491 if (filepath.substr(real_filepath_size) != filename_extension) {
1492 return false;
1493 }
1494 }
1495 }
1496
1497 // The characters after `cleaned_base_filename` should match the format:
1498 // YYYYMMDD-HHMMSS.pid
1499 for (size_t i = cleaned_base_filename.size(); i < real_filepath_size; i++) {
1500 const char& c = filepath[i];
1501
1502 if (i <= cleaned_base_filename.size() + 7) { // 0 ~ 7 : YYYYMMDD
1503 if (c < '0' || c > '9') { return false; }
1504
1505 } else if (i == cleaned_base_filename.size() + 8) { // 8: -
1506 if (c != '-') { return false; }
1507
1508 } else if (i <= cleaned_base_filename.size() + 14) { // 9 ~ 14: HHMMSS
1509 if (c < '0' || c > '9') { return false; }
1510
1511 } else if (i == cleaned_base_filename.size() + 15) { // 15: .
1512 if (c != '.') { return false; }
1513
1514 } else if (i >= cleaned_base_filename.size() + 16) { // 16+: pid
1515 if (c < '0' || c > '9') { return false; }
1516 }
1517 }
1518
1519 return true;
1520}
1521
1522bool LogCleaner::IsLogLastModifiedOver(const string& filepath,
1523 unsigned int days) const {
1524 // Try to get the last modified time of this file.
1525 struct stat file_stat;
1526
1527 if (stat(filepath.c_str(), &file_stat) == 0) {
1528 const time_t seconds_in_a_day = 60 * 60 * 24;
1529 time_t last_modified_time = file_stat.st_mtime;
1530 time_t current_time = time(NULL);
1531 return difftime(current_time, last_modified_time) > days * seconds_in_a_day;
1532 }
1533
1534 // If failed to get file stat, don't return true!
1535 return false;
1536}
1537
1538} // namespace
Austin Schuh906616c2019-01-21 20:25:11 -08001539
1540// Static log data space to avoid alloc failures in a LOG(FATAL)
1541//
1542// Since multiple threads may call LOG(FATAL), and we want to preserve
1543// the data from the first call, we allocate two sets of space. One
1544// for exclusive use by the first thread, and one for shared use by
1545// all other threads.
1546static Mutex fatal_msg_lock;
1547static CrashReason crash_reason;
1548static bool fatal_msg_exclusive = true;
1549static LogMessage::LogMessageData fatal_msg_data_exclusive;
1550static LogMessage::LogMessageData fatal_msg_data_shared;
1551
1552#ifdef GLOG_THREAD_LOCAL_STORAGE
1553// Static thread-local log data space to use, because typically at most one
1554// LogMessageData object exists (in this case glog makes zero heap memory
1555// allocations).
1556static GLOG_THREAD_LOCAL_STORAGE bool thread_data_available = true;
1557
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001558#if defined(HAVE_ALIGNED_STORAGE) && __cplusplus >= 201103L
Austin Schuh906616c2019-01-21 20:25:11 -08001559static GLOG_THREAD_LOCAL_STORAGE
1560 std::aligned_storage<sizeof(LogMessage::LogMessageData),
1561 alignof(LogMessage::LogMessageData)>::type thread_msg_data;
1562#else
1563static GLOG_THREAD_LOCAL_STORAGE
1564 char thread_msg_data[sizeof(void*) + sizeof(LogMessage::LogMessageData)];
1565#endif // HAVE_ALIGNED_STORAGE
1566#endif // defined(GLOG_THREAD_LOCAL_STORAGE)
1567
1568LogMessage::LogMessageData::LogMessageData()
1569 : stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {
1570}
1571
1572LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001573 int64 ctr, void (LogMessage::*send_method)())
Austin Schuh906616c2019-01-21 20:25:11 -08001574 : allocated_(NULL) {
1575 Init(file, line, severity, send_method);
1576 data_->stream_.set_ctr(ctr);
1577}
1578
1579LogMessage::LogMessage(const char* file, int line,
1580 const CheckOpString& result)
1581 : allocated_(NULL) {
1582 Init(file, line, GLOG_FATAL, &LogMessage::SendToLog);
1583 stream() << "Check failed: " << (*result.str_) << " ";
1584}
1585
1586LogMessage::LogMessage(const char* file, int line)
1587 : allocated_(NULL) {
1588 Init(file, line, GLOG_INFO, &LogMessage::SendToLog);
1589}
1590
1591LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
1592 : allocated_(NULL) {
1593 Init(file, line, severity, &LogMessage::SendToLog);
1594}
1595
1596LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
1597 LogSink* sink, bool also_send_to_log)
1598 : allocated_(NULL) {
1599 Init(file, line, severity, also_send_to_log ? &LogMessage::SendToSinkAndLog :
1600 &LogMessage::SendToSink);
1601 data_->sink_ = sink; // override Init()'s setting to NULL
1602}
1603
1604LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
1605 vector<string> *outvec)
1606 : allocated_(NULL) {
1607 Init(file, line, severity, &LogMessage::SaveOrSendToLog);
1608 data_->outvec_ = outvec; // override Init()'s setting to NULL
1609}
1610
1611LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
1612 string *message)
1613 : allocated_(NULL) {
1614 Init(file, line, severity, &LogMessage::WriteToStringAndLog);
1615 data_->message_ = message; // override Init()'s setting to NULL
1616}
1617
1618void LogMessage::Init(const char* file,
1619 int line,
1620 LogSeverity severity,
1621 void (LogMessage::*send_method)()) {
1622 allocated_ = NULL;
1623 if (severity != GLOG_FATAL || !exit_on_dfatal) {
1624#ifdef GLOG_THREAD_LOCAL_STORAGE
1625 // No need for locking, because this is thread local.
1626 if (thread_data_available) {
1627 thread_data_available = false;
1628#ifdef HAVE_ALIGNED_STORAGE
1629 data_ = new (&thread_msg_data) LogMessageData;
1630#else
1631 const uintptr_t kAlign = sizeof(void*) - 1;
1632
1633 char* align_ptr =
1634 reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(thread_msg_data + kAlign) & ~kAlign);
1635 data_ = new (align_ptr) LogMessageData;
1636 assert(reinterpret_cast<uintptr_t>(align_ptr) % sizeof(void*) == 0);
1637#endif
1638 } else {
1639 allocated_ = new LogMessageData();
1640 data_ = allocated_;
1641 }
1642#else // !defined(GLOG_THREAD_LOCAL_STORAGE)
1643 allocated_ = new LogMessageData();
1644 data_ = allocated_;
1645#endif // defined(GLOG_THREAD_LOCAL_STORAGE)
1646 data_->first_fatal_ = false;
1647 } else {
1648 MutexLock l(&fatal_msg_lock);
1649 if (fatal_msg_exclusive) {
1650 fatal_msg_exclusive = false;
1651 data_ = &fatal_msg_data_exclusive;
1652 data_->first_fatal_ = true;
1653 } else {
1654 data_ = &fatal_msg_data_shared;
1655 data_->first_fatal_ = false;
1656 }
Austin Schuh77f3f222022-06-10 16:49:21 -07001657 MaybeUnsetRealtime();
Austin Schuh906616c2019-01-21 20:25:11 -08001658 }
1659
Austin Schuh906616c2019-01-21 20:25:11 -08001660 data_->preserved_errno_ = errno;
1661 data_->severity_ = severity;
1662 data_->line_ = line;
1663 data_->send_method_ = send_method;
1664 data_->sink_ = NULL;
1665 data_->outvec_ = NULL;
1666 WallTime now = WallTime_Now();
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001667 time_t timestamp_now = static_cast<time_t>(now);
1668 logmsgtime_ = LogMessageTime(timestamp_now, now);
Austin Schuh906616c2019-01-21 20:25:11 -08001669
1670 data_->num_chars_to_log_ = 0;
1671 data_->num_chars_to_syslog_ = 0;
1672 data_->basename_ = const_basename(file);
1673 data_->fullname_ = file;
1674 data_->has_been_flushed_ = false;
1675
1676 // If specified, prepend a prefix to each line. For example:
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001677 // I20201018 160715 f5d4fbb0 logging.cc:1153]
1678 // (log level, GMT year, month, date, time, thread_id, file basename, line)
Austin Schuh906616c2019-01-21 20:25:11 -08001679 // We exclude the thread_id for the default thread.
1680 if (FLAGS_log_prefix && (line != kNoLogPrefix)) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001681 std::ios saved_fmt(NULL);
1682 saved_fmt.copyfmt(stream());
1683 stream().fill('0');
1684 #ifdef GLOG_CUSTOM_PREFIX_SUPPORT
1685 if (custom_prefix_callback == NULL) {
1686 #endif
1687 stream() << LogSeverityNames[severity][0];
1688 if (FLAGS_log_year_in_prefix) {
1689 stream() << setw(4) << 1900 + logmsgtime_.year();
1690 }
1691 stream() << setw(2) << 1 + logmsgtime_.month()
1692 << setw(2) << logmsgtime_.day()
1693 << ' '
1694 << setw(2) << logmsgtime_.hour() << ':'
1695 << setw(2) << logmsgtime_.min() << ':'
1696 << setw(2) << logmsgtime_.sec() << "."
1697 << setw(6) << logmsgtime_.usec()
1698 << ' '
1699 << setfill(' ') << setw(5)
1700 << static_cast<unsigned int>(GetTID()) << setfill('0')
1701 << ' '
1702 << data_->basename_ << ':' << data_->line_ << "] ";
1703 #ifdef GLOG_CUSTOM_PREFIX_SUPPORT
1704 } else {
1705 custom_prefix_callback(
1706 stream(),
1707 LogMessageInfo(LogSeverityNames[severity],
1708 data_->basename_, data_->line_, GetTID(),
1709 logmsgtime_),
1710 custom_prefix_callback_data
1711 );
1712 stream() << " ";
1713 }
1714 #endif
1715 stream().copyfmt(saved_fmt);
Austin Schuh906616c2019-01-21 20:25:11 -08001716 }
1717 data_->num_prefix_chars_ = data_->stream_.pcount();
1718
1719 if (!FLAGS_log_backtrace_at.empty()) {
1720 char fileline[128];
1721 snprintf(fileline, sizeof(fileline), "%s:%d", data_->basename_, line);
1722#ifdef HAVE_STACKTRACE
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001723 if (FLAGS_log_backtrace_at == fileline) {
Austin Schuh906616c2019-01-21 20:25:11 -08001724 string stacktrace;
1725 DumpStackTraceToString(&stacktrace);
1726 stream() << " (stacktrace:\n" << stacktrace << ") ";
1727 }
1728#endif
1729 }
1730}
1731
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001732const LogMessageTime& LogMessage::getLogMessageTime() const {
1733 return logmsgtime_;
1734}
1735
Austin Schuh906616c2019-01-21 20:25:11 -08001736LogMessage::~LogMessage() {
1737 Flush();
1738#ifdef GLOG_THREAD_LOCAL_STORAGE
1739 if (data_ == static_cast<void*>(&thread_msg_data)) {
1740 data_->~LogMessageData();
1741 thread_data_available = true;
1742 }
1743 else {
1744 delete allocated_;
1745 }
1746#else // !defined(GLOG_THREAD_LOCAL_STORAGE)
1747 delete allocated_;
1748#endif // defined(GLOG_THREAD_LOCAL_STORAGE)
1749}
1750
1751int LogMessage::preserved_errno() const {
1752 return data_->preserved_errno_;
1753}
1754
1755ostream& LogMessage::stream() {
1756 return data_->stream_;
1757}
1758
1759// Flush buffered message, called by the destructor, or any other function
1760// that needs to synchronize the log.
1761void LogMessage::Flush() {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001762 if (data_->has_been_flushed_ || data_->severity_ < FLAGS_minloglevel) {
Austin Schuh906616c2019-01-21 20:25:11 -08001763 return;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001764 }
Austin Schuh906616c2019-01-21 20:25:11 -08001765
1766 data_->num_chars_to_log_ = data_->stream_.pcount();
1767 data_->num_chars_to_syslog_ =
1768 data_->num_chars_to_log_ - data_->num_prefix_chars_;
1769
1770 // Do we need to add a \n to the end of this message?
1771 bool append_newline =
1772 (data_->message_text_[data_->num_chars_to_log_-1] != '\n');
1773 char original_final_char = '\0';
1774
1775 // If we do need to add a \n, we'll do it by violating the memory of the
1776 // ostrstream buffer. This is quick, and we'll make sure to undo our
1777 // modification before anything else is done with the ostrstream. It
1778 // would be preferable not to do things this way, but it seems to be
1779 // the best way to deal with this.
1780 if (append_newline) {
1781 original_final_char = data_->message_text_[data_->num_chars_to_log_];
1782 data_->message_text_[data_->num_chars_to_log_++] = '\n';
1783 }
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001784 data_->message_text_[data_->num_chars_to_log_] = '\0';
Austin Schuh906616c2019-01-21 20:25:11 -08001785
1786 // Prevent any subtle race conditions by wrapping a mutex lock around
1787 // the actual logging action per se.
1788 {
1789 MutexLock l(&log_mutex);
1790 (this->*(data_->send_method_))();
1791 ++num_messages_[static_cast<int>(data_->severity_)];
1792 }
1793 LogDestination::WaitForSinks(data_);
1794
1795 if (append_newline) {
1796 // Fix the ostrstream back how it was before we screwed with it.
1797 // It's 99.44% certain that we don't need to worry about doing this.
1798 data_->message_text_[data_->num_chars_to_log_-1] = original_final_char;
1799 }
1800
1801 // If errno was already set before we enter the logging call, we'll
1802 // set it back to that value when we return from the logging call.
1803 // It happens often that we log an error message after a syscall
1804 // failure, which can potentially set the errno to some other
1805 // values. We would like to preserve the original errno.
1806 if (data_->preserved_errno_ != 0) {
1807 errno = data_->preserved_errno_;
1808 }
1809
1810 // Note that this message is now safely logged. If we're asked to flush
1811 // again, as a result of destruction, say, we'll do nothing on future calls.
1812 data_->has_been_flushed_ = true;
1813}
1814
1815// Copy of first FATAL log message so that we can print it out again
1816// after all the stack traces. To preserve legacy behavior, we don't
1817// use fatal_msg_data_exclusive.
1818static time_t fatal_time;
1819static char fatal_message[256];
1820
1821void ReprintFatalMessage() {
1822 if (fatal_message[0]) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001823 const size_t n = strlen(fatal_message);
Austin Schuh906616c2019-01-21 20:25:11 -08001824 if (!FLAGS_logtostderr) {
1825 // Also write to stderr (don't color to avoid terminal checks)
1826 WriteToStderr(fatal_message, n);
1827 }
1828 LogDestination::LogToAllLogfiles(GLOG_ERROR, fatal_time, fatal_message, n);
1829 }
1830}
1831
1832// L >= log_mutex (callers must hold the log_mutex).
1833void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
1834 static bool already_warned_before_initgoogle = false;
1835
1836 log_mutex.AssertHeld();
Austin Schuh77f3f222022-06-10 16:49:21 -07001837 if (data_->severity_ == GLOG_FATAL && exit_on_dfatal) {
1838 if (data_->first_fatal_) {
1839 MaybeUnsetRealtime();
1840 }
1841 }
Austin Schuh906616c2019-01-21 20:25:11 -08001842
1843 RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
1844 data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
1845
1846 // Messages of a given severity get logged to lower severity logs, too
1847
1848 if (!already_warned_before_initgoogle && !IsGoogleLoggingInitialized()) {
1849 const char w[] = "WARNING: Logging before InitGoogleLogging() is "
1850 "written to STDERR\n";
1851 WriteToStderr(w, strlen(w));
1852 already_warned_before_initgoogle = true;
1853 }
1854
1855 // global flag: never log to file if set. Also -- don't log to a
1856 // file if we haven't parsed the command line flags to get the
1857 // program name.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001858 if (FLAGS_logtostderr || FLAGS_logtostdout || !IsGoogleLoggingInitialized()) {
1859 if (FLAGS_logtostdout) {
1860 ColoredWriteToStdout(data_->severity_, data_->message_text_,
1861 data_->num_chars_to_log_);
1862 } else {
1863 ColoredWriteToStderr(data_->severity_, data_->message_text_,
1864 data_->num_chars_to_log_);
1865 }
Austin Schuh906616c2019-01-21 20:25:11 -08001866
1867 // this could be protected by a flag if necessary.
1868 LogDestination::LogToSinks(data_->severity_,
1869 data_->fullname_, data_->basename_,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001870 data_->line_, logmsgtime_,
Austin Schuh906616c2019-01-21 20:25:11 -08001871 data_->message_text_ + data_->num_prefix_chars_,
1872 (data_->num_chars_to_log_ -
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001873 data_->num_prefix_chars_ - 1) );
Austin Schuh906616c2019-01-21 20:25:11 -08001874 } else {
Austin Schuh906616c2019-01-21 20:25:11 -08001875 // log this message to all log files of severity <= severity_
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001876 LogDestination::LogToAllLogfiles(data_->severity_, logmsgtime_.timestamp(),
Austin Schuh906616c2019-01-21 20:25:11 -08001877 data_->message_text_,
1878 data_->num_chars_to_log_);
1879
1880 LogDestination::MaybeLogToStderr(data_->severity_, data_->message_text_,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001881 data_->num_chars_to_log_,
1882 data_->num_prefix_chars_);
Austin Schuh906616c2019-01-21 20:25:11 -08001883 LogDestination::MaybeLogToEmail(data_->severity_, data_->message_text_,
1884 data_->num_chars_to_log_);
1885 LogDestination::LogToSinks(data_->severity_,
1886 data_->fullname_, data_->basename_,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001887 data_->line_, logmsgtime_,
Austin Schuh906616c2019-01-21 20:25:11 -08001888 data_->message_text_ + data_->num_prefix_chars_,
1889 (data_->num_chars_to_log_
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001890 - data_->num_prefix_chars_ - 1) );
Austin Schuh906616c2019-01-21 20:25:11 -08001891 // NOTE: -1 removes trailing \n
1892 }
1893
1894 // If we log a FATAL message, flush all the log destinations, then toss
1895 // a signal for others to catch. We leave the logs in a state that
1896 // someone else can use them (as long as they flush afterwards)
1897 if (data_->severity_ == GLOG_FATAL && exit_on_dfatal) {
1898 if (data_->first_fatal_) {
1899 // Store crash information so that it is accessible from within signal
1900 // handlers that may be invoked later.
1901 RecordCrashReason(&crash_reason);
1902 SetCrashReason(&crash_reason);
1903
1904 // Store shortened fatal message for other logs and GWQ status
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001905 const size_t copy = min(data_->num_chars_to_log_,
Austin Schuh906616c2019-01-21 20:25:11 -08001906 sizeof(fatal_message)-1);
1907 memcpy(fatal_message, data_->message_text_, copy);
1908 fatal_message[copy] = '\0';
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001909 fatal_time = logmsgtime_.timestamp();
Austin Schuh906616c2019-01-21 20:25:11 -08001910 }
1911
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001912 if (!FLAGS_logtostderr && !FLAGS_logtostdout) {
Austin Schuh906616c2019-01-21 20:25:11 -08001913 for (int i = 0; i < NUM_SEVERITIES; ++i) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001914 if (LogDestination::log_destinations_[i]) {
Austin Schuh906616c2019-01-21 20:25:11 -08001915 LogDestination::log_destinations_[i]->logger_->Write(true, 0, "", 0);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001916 }
Austin Schuh906616c2019-01-21 20:25:11 -08001917 }
1918 }
1919
1920 // release the lock that our caller (directly or indirectly)
1921 // LogMessage::~LogMessage() grabbed so that signal handlers
1922 // can use the logging facility. Alternately, we could add
1923 // an entire unsafe logging interface to bypass locking
1924 // for signal handlers but this seems simpler.
1925 log_mutex.Unlock();
1926 LogDestination::WaitForSinks(data_);
1927
1928 const char* message = "*** Check failure stack trace: ***\n";
1929 if (write(STDERR_FILENO, message, strlen(message)) < 0) {
1930 // Ignore errors.
1931 }
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001932#if defined(__ANDROID__)
1933 // ANDROID_LOG_FATAL as this message is of FATAL severity.
1934 __android_log_write(ANDROID_LOG_FATAL,
1935 glog_internal_namespace_::ProgramInvocationShortName(),
1936 message);
1937#endif
Austin Schuh906616c2019-01-21 20:25:11 -08001938 Fail();
1939 }
1940}
1941
1942void LogMessage::RecordCrashReason(
1943 glog_internal_namespace_::CrashReason* reason) {
1944 reason->filename = fatal_msg_data_exclusive.fullname_;
1945 reason->line_number = fatal_msg_data_exclusive.line_;
1946 reason->message = fatal_msg_data_exclusive.message_text_ +
1947 fatal_msg_data_exclusive.num_prefix_chars_;
1948#ifdef HAVE_STACKTRACE
1949 // Retrieve the stack trace, omitting the logging frames that got us here.
1950 reason->depth = GetStackTrace(reason->stack, ARRAYSIZE(reason->stack), 4);
1951#else
1952 reason->depth = 0;
1953#endif
1954}
1955
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001956GLOG_EXPORT logging_fail_func_t g_logging_fail_func =
1957 reinterpret_cast<logging_fail_func_t>(&abort);
Austin Schuh906616c2019-01-21 20:25:11 -08001958
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001959void InstallFailureFunction(logging_fail_func_t fail_func) {
1960 g_logging_fail_func = fail_func;
Austin Schuh906616c2019-01-21 20:25:11 -08001961}
1962
1963void LogMessage::Fail() {
1964 g_logging_fail_func();
1965}
1966
1967// L >= log_mutex (callers must hold the log_mutex).
1968void LogMessage::SendToSink() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
1969 if (data_->sink_ != NULL) {
1970 RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
1971 data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
1972 data_->sink_->send(data_->severity_, data_->fullname_, data_->basename_,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001973 data_->line_, logmsgtime_,
Austin Schuh906616c2019-01-21 20:25:11 -08001974 data_->message_text_ + data_->num_prefix_chars_,
1975 (data_->num_chars_to_log_ -
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001976 data_->num_prefix_chars_ - 1) );
Austin Schuh906616c2019-01-21 20:25:11 -08001977 }
1978}
1979
1980// L >= log_mutex (callers must hold the log_mutex).
1981void LogMessage::SendToSinkAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
1982 SendToSink();
1983 SendToLog();
1984}
1985
1986// L >= log_mutex (callers must hold the log_mutex).
1987void LogMessage::SaveOrSendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
1988 if (data_->outvec_ != NULL) {
1989 RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
1990 data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
1991 // Omit prefix of message and trailing newline when recording in outvec_.
1992 const char *start = data_->message_text_ + data_->num_prefix_chars_;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07001993 size_t len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;
Austin Schuh906616c2019-01-21 20:25:11 -08001994 data_->outvec_->push_back(string(start, len));
1995 } else {
1996 SendToLog();
1997 }
1998}
1999
2000void LogMessage::WriteToStringAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
2001 if (data_->message_ != NULL) {
2002 RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
2003 data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
2004 // Omit prefix of message and trailing newline when writing to message_.
2005 const char *start = data_->message_text_ + data_->num_prefix_chars_;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002006 size_t len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;
Austin Schuh906616c2019-01-21 20:25:11 -08002007 data_->message_->assign(start, len);
2008 }
2009 SendToLog();
2010}
2011
2012// L >= log_mutex (callers must hold the log_mutex).
2013void LogMessage::SendToSyslogAndLog() {
2014#ifdef HAVE_SYSLOG_H
2015 // Before any calls to syslog(), make a single call to openlog()
2016 static bool openlog_already_called = false;
2017 if (!openlog_already_called) {
2018 openlog(glog_internal_namespace_::ProgramInvocationShortName(),
2019 LOG_CONS | LOG_NDELAY | LOG_PID,
2020 LOG_USER);
2021 openlog_already_called = true;
2022 }
2023
2024 // This array maps Google severity levels to syslog levels
2025 const int SEVERITY_TO_LEVEL[] = { LOG_INFO, LOG_WARNING, LOG_ERR, LOG_EMERG };
2026 syslog(LOG_USER | SEVERITY_TO_LEVEL[static_cast<int>(data_->severity_)], "%.*s",
2027 int(data_->num_chars_to_syslog_),
2028 data_->message_text_ + data_->num_prefix_chars_);
2029 SendToLog();
2030#else
2031 LOG(ERROR) << "No syslog support: message=" << data_->message_text_;
2032#endif
2033}
2034
2035base::Logger* base::GetLogger(LogSeverity severity) {
2036 MutexLock l(&log_mutex);
2037 return LogDestination::log_destination(severity)->logger_;
2038}
2039
2040void base::SetLogger(LogSeverity severity, base::Logger* logger) {
2041 MutexLock l(&log_mutex);
2042 LogDestination::log_destination(severity)->logger_ = logger;
2043}
2044
2045// L < log_mutex. Acquires and releases mutex_.
2046int64 LogMessage::num_messages(int severity) {
2047 MutexLock l(&log_mutex);
2048 return num_messages_[severity];
2049}
2050
2051// Output the COUNTER value. This is only valid if ostream is a
2052// LogStream.
2053ostream& operator<<(ostream &os, const PRIVATE_Counter&) {
2054#ifdef DISABLE_RTTI
2055 LogMessage::LogStream *log = static_cast<LogMessage::LogStream*>(&os);
2056#else
2057 LogMessage::LogStream *log = dynamic_cast<LogMessage::LogStream*>(&os);
2058#endif
2059 CHECK(log && log == log->self())
2060 << "You must not use COUNTER with non-glog ostream";
2061 os << log->ctr();
2062 return os;
2063}
2064
2065ErrnoLogMessage::ErrnoLogMessage(const char* file, int line,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002066 LogSeverity severity, int64 ctr,
Austin Schuh906616c2019-01-21 20:25:11 -08002067 void (LogMessage::*send_method)())
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002068 : LogMessage(file, line, severity, ctr, send_method) {}
Austin Schuh906616c2019-01-21 20:25:11 -08002069
2070ErrnoLogMessage::~ErrnoLogMessage() {
2071 // Don't access errno directly because it may have been altered
2072 // while streaming the message.
2073 stream() << ": " << StrError(preserved_errno()) << " ["
2074 << preserved_errno() << "]";
2075}
2076
2077void FlushLogFiles(LogSeverity min_severity) {
2078 LogDestination::FlushLogFiles(min_severity);
2079}
2080
2081void FlushLogFilesUnsafe(LogSeverity min_severity) {
2082 LogDestination::FlushLogFilesUnsafe(min_severity);
2083}
2084
2085void SetLogDestination(LogSeverity severity, const char* base_filename) {
2086 LogDestination::SetLogDestination(severity, base_filename);
2087}
2088
2089void SetLogSymlink(LogSeverity severity, const char* symlink_basename) {
2090 LogDestination::SetLogSymlink(severity, symlink_basename);
2091}
2092
2093LogSink::~LogSink() {
2094}
2095
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002096void LogSink::send(LogSeverity severity, const char* full_filename,
2097 const char* base_filename, int line,
2098 const LogMessageTime& time, const char* message,
2099 size_t message_len) {
2100#if defined(__GNUC__)
2101#pragma GCC diagnostic push
2102#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
2103#elif defined(_MSC_VER)
2104#pragma warning(push)
2105#pragma warning(disable : 4996)
2106#endif // __GNUC__
2107 send(severity, full_filename, base_filename, line, &time.tm(), message,
2108 message_len);
2109#if defined(__GNUC__)
2110#pragma GCC diagnostic pop
2111#elif defined(_MSC_VER)
2112#pragma warning(pop)
2113#endif // __GNUC__
2114}
2115
2116void LogSink::send(LogSeverity severity, const char* full_filename,
2117 const char* base_filename, int line, const std::tm* t,
2118 const char* message, size_t message_len) {
2119 (void)severity;
2120 (void)full_filename;
2121 (void)base_filename;
2122 (void)line;
2123 (void)t;
2124 (void)message;
2125 (void)message_len;
2126}
2127
Austin Schuh906616c2019-01-21 20:25:11 -08002128void LogSink::WaitTillSent() {
2129 // noop default
2130}
2131
2132string LogSink::ToString(LogSeverity severity, const char* file, int line,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002133 const LogMessageTime& logmsgtime, const char* message,
2134 size_t message_len) {
Austin Schuh906616c2019-01-21 20:25:11 -08002135 ostringstream stream(string(message, message_len));
2136 stream.fill('0');
2137
Austin Schuh906616c2019-01-21 20:25:11 -08002138 stream << LogSeverityNames[severity][0]
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002139 << setw(4) << 1900 + logmsgtime.year()
2140 << setw(2) << 1 + logmsgtime.month()
2141 << setw(2) << logmsgtime.day()
Austin Schuh906616c2019-01-21 20:25:11 -08002142 << ' '
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002143 << setw(2) << logmsgtime.hour() << ':'
2144 << setw(2) << logmsgtime.min() << ':'
2145 << setw(2) << logmsgtime.sec() << '.'
2146 << setw(6) << logmsgtime.usec()
Austin Schuh906616c2019-01-21 20:25:11 -08002147 << ' '
2148 << setfill(' ') << setw(5) << GetTID() << setfill('0')
2149 << ' '
2150 << file << ':' << line << "] ";
2151
2152 stream << string(message, message_len);
2153 return stream.str();
2154}
2155
2156void AddLogSink(LogSink *destination) {
2157 LogDestination::AddLogSink(destination);
2158}
2159
2160void RemoveLogSink(LogSink *destination) {
2161 LogDestination::RemoveLogSink(destination);
2162}
2163
2164void SetLogFilenameExtension(const char* ext) {
2165 LogDestination::SetLogFilenameExtension(ext);
2166}
2167
2168void SetStderrLogging(LogSeverity min_severity) {
2169 LogDestination::SetStderrLogging(min_severity);
2170}
2171
2172void SetEmailLogging(LogSeverity min_severity, const char* addresses) {
2173 LogDestination::SetEmailLogging(min_severity, addresses);
2174}
2175
2176void LogToStderr() {
2177 LogDestination::LogToStderr();
2178}
2179
2180namespace base {
2181namespace internal {
2182
2183bool GetExitOnDFatal();
2184bool GetExitOnDFatal() {
2185 MutexLock l(&log_mutex);
2186 return exit_on_dfatal;
2187}
2188
2189// Determines whether we exit the program for a LOG(DFATAL) message in
2190// debug mode. It does this by skipping the call to Fail/FailQuietly.
2191// This is intended for testing only.
2192//
2193// This can have some effects on LOG(FATAL) as well. Failure messages
2194// are always allocated (rather than sharing a buffer), the crash
2195// reason is not recorded, the "gwq" status message is not updated,
2196// and the stack trace is not recorded. The LOG(FATAL) *will* still
2197// exit the program. Since this function is used only in testing,
2198// these differences are acceptable.
2199void SetExitOnDFatal(bool value);
2200void SetExitOnDFatal(bool value) {
2201 MutexLock l(&log_mutex);
2202 exit_on_dfatal = value;
2203}
2204
2205} // namespace internal
2206} // namespace base
2207
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002208#ifndef GLOG_OS_EMSCRIPTEN
Austin Schuh906616c2019-01-21 20:25:11 -08002209// Shell-escaping as we need to shell out ot /bin/mail.
2210static const char kDontNeedShellEscapeChars[] =
2211 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2212 "abcdefghijklmnopqrstuvwxyz"
2213 "0123456789+-_.=/:,@";
2214
2215static string ShellEscape(const string& src) {
2216 string result;
2217 if (!src.empty() && // empty string needs quotes
2218 src.find_first_not_of(kDontNeedShellEscapeChars) == string::npos) {
2219 // only contains chars that don't need quotes; it's fine
2220 result.assign(src);
2221 } else if (src.find_first_of('\'') == string::npos) {
2222 // no single quotes; just wrap it in single quotes
2223 result.assign("'");
2224 result.append(src);
2225 result.append("'");
2226 } else {
2227 // needs double quote escaping
2228 result.assign("\"");
2229 for (size_t i = 0; i < src.size(); ++i) {
2230 switch (src[i]) {
2231 case '\\':
2232 case '$':
2233 case '"':
2234 case '`':
2235 result.append("\\");
2236 }
2237 result.append(src, i, 1);
2238 }
2239 result.append("\"");
2240 }
2241 return result;
2242}
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002243#endif
Austin Schuh906616c2019-01-21 20:25:11 -08002244
2245// use_logging controls whether the logging functions LOG/VLOG are used
2246// to log errors. It should be set to false when the caller holds the
2247// log_mutex.
2248static bool SendEmailInternal(const char*dest, const char *subject,
2249 const char*body, bool use_logging) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002250#ifndef GLOG_OS_EMSCRIPTEN
Austin Schuh906616c2019-01-21 20:25:11 -08002251 if (dest && *dest) {
2252 if ( use_logging ) {
2253 VLOG(1) << "Trying to send TITLE:" << subject
2254 << " BODY:" << body << " to " << dest;
2255 } else {
2256 fprintf(stderr, "Trying to send TITLE: %s BODY: %s to %s\n",
2257 subject, body, dest);
2258 }
2259
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002260 string logmailer = FLAGS_logmailer;
2261 if (logmailer.empty()) {
2262 logmailer = "/bin/mail";
2263 }
Austin Schuh906616c2019-01-21 20:25:11 -08002264 string cmd =
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002265 logmailer + " -s" +
Austin Schuh906616c2019-01-21 20:25:11 -08002266 ShellEscape(subject) + " " + ShellEscape(dest);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002267 if (use_logging) {
2268 VLOG(4) << "Mailing command: " << cmd;
2269 }
Austin Schuh906616c2019-01-21 20:25:11 -08002270
2271 FILE* pipe = popen(cmd.c_str(), "w");
2272 if (pipe != NULL) {
2273 // Add the body if we have one
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002274 if (body) {
Austin Schuh906616c2019-01-21 20:25:11 -08002275 fwrite(body, sizeof(char), strlen(body), pipe);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002276 }
Austin Schuh906616c2019-01-21 20:25:11 -08002277 bool ok = pclose(pipe) != -1;
2278 if ( !ok ) {
2279 if ( use_logging ) {
2280 LOG(ERROR) << "Problems sending mail to " << dest << ": "
2281 << StrError(errno);
2282 } else {
2283 fprintf(stderr, "Problems sending mail to %s: %s\n",
2284 dest, StrError(errno).c_str());
2285 }
2286 }
2287 return ok;
2288 } else {
2289 if ( use_logging ) {
2290 LOG(ERROR) << "Unable to send mail to " << dest;
2291 } else {
2292 fprintf(stderr, "Unable to send mail to %s\n", dest);
2293 }
2294 }
2295 }
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002296#else
2297 (void)dest;
2298 (void)subject;
2299 (void)body;
2300 (void)use_logging;
2301 LOG(WARNING) << "Email support not available; not sending message";
2302#endif
Austin Schuh906616c2019-01-21 20:25:11 -08002303 return false;
2304}
2305
2306bool SendEmail(const char*dest, const char *subject, const char*body){
2307 return SendEmailInternal(dest, subject, body, true);
2308}
2309
2310static void GetTempDirectories(vector<string>* list) {
2311 list->clear();
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002312#ifdef GLOG_OS_WINDOWS
Austin Schuh906616c2019-01-21 20:25:11 -08002313 // On windows we'll try to find a directory in this order:
2314 // C:/Documents & Settings/whomever/TEMP (or whatever GetTempPath() is)
2315 // C:/TMP/
2316 // C:/TEMP/
2317 // C:/WINDOWS/ or C:/WINNT/
2318 // .
2319 char tmp[MAX_PATH];
2320 if (GetTempPathA(MAX_PATH, tmp))
2321 list->push_back(tmp);
2322 list->push_back("C:\\tmp\\");
2323 list->push_back("C:\\temp\\");
2324#else
2325 // Directories, in order of preference. If we find a dir that
2326 // exists, we stop adding other less-preferred dirs
2327 const char * candidates[] = {
2328 // Non-null only during unittest/regtest
2329 getenv("TEST_TMPDIR"),
2330
2331 // Explicitly-supplied temp dirs
2332 getenv("TMPDIR"), getenv("TMP"),
2333
2334 // If all else fails
2335 "/tmp",
2336 };
2337
2338 for (size_t i = 0; i < ARRAYSIZE(candidates); i++) {
2339 const char *d = candidates[i];
2340 if (!d) continue; // Empty env var
2341
2342 // Make sure we don't surprise anyone who's expecting a '/'
2343 string dstr = d;
2344 if (dstr[dstr.size() - 1] != '/') {
2345 dstr += "/";
2346 }
2347 list->push_back(dstr);
2348
2349 struct stat statbuf;
2350 if (!stat(d, &statbuf) && S_ISDIR(statbuf.st_mode)) {
2351 // We found a dir that exists - we're done.
2352 return;
2353 }
2354 }
2355
2356#endif
2357}
2358
2359static vector<string>* logging_directories_list;
2360
2361const vector<string>& GetLoggingDirectories() {
2362 // Not strictly thread-safe but we're called early in InitGoogle().
2363 if (logging_directories_list == NULL) {
2364 logging_directories_list = new vector<string>;
2365
2366 if ( !FLAGS_log_dir.empty() ) {
2367 // A dir was specified, we should use it
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002368 logging_directories_list->push_back(FLAGS_log_dir);
Austin Schuh906616c2019-01-21 20:25:11 -08002369 } else {
2370 GetTempDirectories(logging_directories_list);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002371#ifdef GLOG_OS_WINDOWS
Austin Schuh906616c2019-01-21 20:25:11 -08002372 char tmp[MAX_PATH];
2373 if (GetWindowsDirectoryA(tmp, MAX_PATH))
2374 logging_directories_list->push_back(tmp);
2375 logging_directories_list->push_back(".\\");
2376#else
2377 logging_directories_list->push_back("./");
2378#endif
2379 }
2380 }
2381 return *logging_directories_list;
2382}
2383
2384void TestOnly_ClearLoggingDirectoriesList() {
2385 fprintf(stderr, "TestOnly_ClearLoggingDirectoriesList should only be "
2386 "called from test code.\n");
2387 delete logging_directories_list;
2388 logging_directories_list = NULL;
2389}
2390
2391void GetExistingTempDirectories(vector<string>* list) {
2392 GetTempDirectories(list);
2393 vector<string>::iterator i_dir = list->begin();
2394 while( i_dir != list->end() ) {
2395 // zero arg to access means test for existence; no constant
2396 // defined on windows
2397 if ( access(i_dir->c_str(), 0) ) {
2398 i_dir = list->erase(i_dir);
2399 } else {
2400 ++i_dir;
2401 }
2402 }
2403}
2404
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002405void TruncateLogFile(const char *path, uint64 limit, uint64 keep) {
Austin Schuh906616c2019-01-21 20:25:11 -08002406#ifdef HAVE_UNISTD_H
2407 struct stat statbuf;
2408 const int kCopyBlockSize = 8 << 10;
2409 char copybuf[kCopyBlockSize];
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002410 off_t read_offset, write_offset;
Austin Schuh906616c2019-01-21 20:25:11 -08002411 // Don't follow symlinks unless they're our own fd symlinks in /proc
2412 int flags = O_RDWR;
2413 // TODO(hamaji): Support other environments.
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002414#ifdef GLOG_OS_LINUX
Austin Schuh906616c2019-01-21 20:25:11 -08002415 const char *procfd_prefix = "/proc/self/fd/";
2416 if (strncmp(procfd_prefix, path, strlen(procfd_prefix))) flags |= O_NOFOLLOW;
2417#endif
2418
2419 int fd = open(path, flags);
2420 if (fd == -1) {
2421 if (errno == EFBIG) {
2422 // The log file in question has got too big for us to open. The
2423 // real fix for this would be to compile logging.cc (or probably
2424 // all of base/...) with -D_FILE_OFFSET_BITS=64 but that's
2425 // rather scary.
2426 // Instead just truncate the file to something we can manage
2427 if (truncate(path, 0) == -1) {
2428 PLOG(ERROR) << "Unable to truncate " << path;
2429 } else {
2430 LOG(ERROR) << "Truncated " << path << " due to EFBIG error";
2431 }
2432 } else {
2433 PLOG(ERROR) << "Unable to open " << path;
2434 }
2435 return;
2436 }
2437
2438 if (fstat(fd, &statbuf) == -1) {
2439 PLOG(ERROR) << "Unable to fstat()";
2440 goto out_close_fd;
2441 }
2442
2443 // See if the path refers to a regular file bigger than the
2444 // specified limit
2445 if (!S_ISREG(statbuf.st_mode)) goto out_close_fd;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002446 if (statbuf.st_size <= static_cast<off_t>(limit)) goto out_close_fd;
2447 if (statbuf.st_size <= static_cast<off_t>(keep)) goto out_close_fd;
Austin Schuh906616c2019-01-21 20:25:11 -08002448
2449 // This log file is too large - we need to truncate it
2450 LOG(INFO) << "Truncating " << path << " to " << keep << " bytes";
2451
2452 // Copy the last "keep" bytes of the file to the beginning of the file
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002453 read_offset = statbuf.st_size - static_cast<off_t>(keep);
Austin Schuh906616c2019-01-21 20:25:11 -08002454 write_offset = 0;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002455 ssize_t bytesin, bytesout;
Austin Schuh906616c2019-01-21 20:25:11 -08002456 while ((bytesin = pread(fd, copybuf, sizeof(copybuf), read_offset)) > 0) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002457 bytesout = pwrite(fd, copybuf, static_cast<size_t>(bytesin), write_offset);
Austin Schuh906616c2019-01-21 20:25:11 -08002458 if (bytesout == -1) {
2459 PLOG(ERROR) << "Unable to write to " << path;
2460 break;
2461 } else if (bytesout != bytesin) {
2462 LOG(ERROR) << "Expected to write " << bytesin << ", wrote " << bytesout;
2463 }
2464 read_offset += bytesin;
2465 write_offset += bytesout;
2466 }
2467 if (bytesin == -1) PLOG(ERROR) << "Unable to read from " << path;
2468
2469 // Truncate the remainder of the file. If someone else writes to the
2470 // end of the file after our last read() above, we lose their latest
2471 // data. Too bad ...
2472 if (ftruncate(fd, write_offset) == -1) {
2473 PLOG(ERROR) << "Unable to truncate " << path;
2474 }
2475
2476 out_close_fd:
2477 close(fd);
2478#else
2479 LOG(ERROR) << "No log truncation support.";
Austin Schuh10358f22019-01-21 20:25:11 -08002480 (void)path;
2481 (void)limit;
2482 (void)keep;
Austin Schuh906616c2019-01-21 20:25:11 -08002483#endif
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002484 }
Austin Schuh906616c2019-01-21 20:25:11 -08002485
2486void TruncateStdoutStderr() {
2487#ifdef HAVE_UNISTD_H
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002488 uint64 limit = MaxLogSize() << 20U;
2489 uint64 keep = 1U << 20U;
Austin Schuh906616c2019-01-21 20:25:11 -08002490 TruncateLogFile("/proc/self/fd/1", limit, keep);
2491 TruncateLogFile("/proc/self/fd/2", limit, keep);
2492#else
2493 LOG(ERROR) << "No log truncation support.";
2494#endif
2495}
2496
2497
2498// Helper functions for string comparisons.
2499#define DEFINE_CHECK_STROP_IMPL(name, func, expected) \
2500 string* Check##func##expected##Impl(const char* s1, const char* s2, \
2501 const char* names) { \
2502 bool equal = s1 == s2 || (s1 && s2 && !func(s1, s2)); \
2503 if (equal == expected) return NULL; \
2504 else { \
2505 ostringstream ss; \
2506 if (!s1) s1 = ""; \
2507 if (!s2) s2 = ""; \
2508 ss << #name " failed: " << names << " (" << s1 << " vs. " << s2 << ")"; \
2509 return new string(ss.str()); \
2510 } \
2511 }
2512DEFINE_CHECK_STROP_IMPL(CHECK_STREQ, strcmp, true)
2513DEFINE_CHECK_STROP_IMPL(CHECK_STRNE, strcmp, false)
2514DEFINE_CHECK_STROP_IMPL(CHECK_STRCASEEQ, strcasecmp, true)
2515DEFINE_CHECK_STROP_IMPL(CHECK_STRCASENE, strcasecmp, false)
2516#undef DEFINE_CHECK_STROP_IMPL
2517
2518int posix_strerror_r(int err, char *buf, size_t len) {
2519 // Sanity check input parameters
2520 if (buf == NULL || len <= 0) {
2521 errno = EINVAL;
2522 return -1;
2523 }
2524
2525 // Reset buf and errno, and try calling whatever version of strerror_r()
2526 // is implemented by glibc
2527 buf[0] = '\000';
2528 int old_errno = errno;
2529 errno = 0;
2530 char *rc = reinterpret_cast<char *>(strerror_r(err, buf, len));
2531
2532 // Both versions set errno on failure
2533 if (errno) {
2534 // Should already be there, but better safe than sorry
2535 buf[0] = '\000';
2536 return -1;
2537 }
2538 errno = old_errno;
2539
2540 // POSIX is vague about whether the string will be terminated, although
2541 // is indirectly implies that typically ERANGE will be returned, instead
2542 // of truncating the string. This is different from the GNU implementation.
2543 // We play it safe by always terminating the string explicitly.
2544 buf[len-1] = '\000';
2545
2546 // If the function succeeded, we can use its exit code to determine the
2547 // semantics implemented by glibc
2548 if (!rc) {
2549 return 0;
2550 } else {
2551 // GNU semantics detected
2552 if (rc == buf) {
2553 return 0;
2554 } else {
2555 buf[0] = '\000';
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002556#if defined(GLOG_OS_MACOSX) || defined(GLOG_OS_FREEBSD) || defined(GLOG_OS_OPENBSD)
Austin Schuh906616c2019-01-21 20:25:11 -08002557 if (reinterpret_cast<intptr_t>(rc) < sys_nerr) {
2558 // This means an error on MacOSX or FreeBSD.
2559 return -1;
2560 }
2561#endif
2562 strncat(buf, rc, len-1);
2563 return 0;
2564 }
2565 }
2566}
2567
2568string StrError(int err) {
2569 char buf[100];
2570 int rc = posix_strerror_r(err, buf, sizeof(buf));
2571 if ((rc < 0) || (buf[0] == '\000')) {
2572 snprintf(buf, sizeof(buf), "Error number %d", err);
2573 }
2574 return buf;
2575}
2576
Austin Schuh77f3f222022-06-10 16:49:21 -07002577LogMessageFatal::LogMessageFatal(const char *file, int line)
2578 : LogMessage(file, line, GLOG_FATAL) {
2579 MaybeUnsetRealtime();
2580}
Austin Schuh906616c2019-01-21 20:25:11 -08002581
2582LogMessageFatal::LogMessageFatal(const char* file, int line,
2583 const CheckOpString& result) :
2584 LogMessage(file, line, result) {}
2585
2586LogMessageFatal::~LogMessageFatal() {
2587 Flush();
2588 LogMessage::Fail();
2589}
2590
2591namespace base {
2592
Austin Schuh77f3f222022-06-10 16:49:21 -07002593static ostringstream* MakeSafeOstream() {
2594 MaybeUnsetRealtime();
2595 return new ostringstream;
2596}
2597
Austin Schuh906616c2019-01-21 20:25:11 -08002598CheckOpMessageBuilder::CheckOpMessageBuilder(const char *exprtext)
Austin Schuh77f3f222022-06-10 16:49:21 -07002599 : stream_(MakeSafeOstream()) {
Austin Schuh906616c2019-01-21 20:25:11 -08002600 *stream_ << exprtext << " (";
2601}
2602
2603CheckOpMessageBuilder::~CheckOpMessageBuilder() {
2604 delete stream_;
2605}
2606
2607ostream* CheckOpMessageBuilder::ForVar2() {
2608 *stream_ << " vs. ";
2609 return stream_;
2610}
2611
2612string* CheckOpMessageBuilder::NewString() {
2613 *stream_ << ")";
2614 return new string(stream_->str());
2615}
2616
2617} // namespace base
2618
2619template <>
2620void MakeCheckOpValueString(std::ostream* os, const char& v) {
2621 if (v >= 32 && v <= 126) {
2622 (*os) << "'" << v << "'";
2623 } else {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002624 (*os) << "char value " << static_cast<short>(v);
Austin Schuh906616c2019-01-21 20:25:11 -08002625 }
2626}
2627
2628template <>
2629void MakeCheckOpValueString(std::ostream* os, const signed char& v) {
2630 if (v >= 32 && v <= 126) {
2631 (*os) << "'" << v << "'";
2632 } else {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002633 (*os) << "signed char value " << static_cast<short>(v);
Austin Schuh906616c2019-01-21 20:25:11 -08002634 }
2635}
2636
2637template <>
2638void MakeCheckOpValueString(std::ostream* os, const unsigned char& v) {
2639 if (v >= 32 && v <= 126) {
2640 (*os) << "'" << v << "'";
2641 } else {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002642 (*os) << "unsigned char value " << static_cast<unsigned short>(v);
Austin Schuh906616c2019-01-21 20:25:11 -08002643 }
2644}
2645
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002646#if defined(HAVE_CXX11_NULLPTR_T) && __cplusplus >= 201103L
2647template <>
2648void MakeCheckOpValueString(std::ostream* os, const std::nullptr_t& /*v*/) {
2649 (*os) << "nullptr";
2650}
2651#endif // defined(HAVE_CXX11_NULLPTR_T)
2652
Austin Schuh906616c2019-01-21 20:25:11 -08002653void InitGoogleLogging(const char* argv0) {
2654 glog_internal_namespace_::InitGoogleLoggingUtilities(argv0);
2655}
2656
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002657#ifdef GLOG_CUSTOM_PREFIX_SUPPORT
2658void InitGoogleLogging(const char* argv0,
2659 CustomPrefixCallback prefix_callback,
2660 void* prefix_callback_data) {
2661 custom_prefix_callback = prefix_callback;
2662 custom_prefix_callback_data = prefix_callback_data;
2663 InitGoogleLogging(argv0);
2664}
2665#endif
2666
Austin Schuh906616c2019-01-21 20:25:11 -08002667void ShutdownGoogleLogging() {
2668 glog_internal_namespace_::ShutdownGoogleLoggingUtilities();
2669 LogDestination::DeleteLogDestinations();
2670 delete logging_directories_list;
2671 logging_directories_list = NULL;
2672}
2673
James Kuszmaulba0ac1a2022-08-12 16:29:30 -07002674void EnableLogCleaner(unsigned int overdue_days) {
2675 log_cleaner.Enable(overdue_days);
2676}
2677
2678void DisableLogCleaner() {
2679 log_cleaner.Disable();
2680}
2681
2682LogMessageTime::LogMessageTime()
2683 : time_struct_(), timestamp_(0), usecs_(0), gmtoffset_(0) {}
2684
2685LogMessageTime::LogMessageTime(std::tm t) {
2686 std::time_t timestamp = std::mktime(&t);
2687 init(t, timestamp, 0);
2688}
2689
2690LogMessageTime::LogMessageTime(std::time_t timestamp, WallTime now) {
2691 std::tm t;
2692 if (FLAGS_log_utc_time)
2693 gmtime_r(&timestamp, &t);
2694 else
2695 localtime_r(&timestamp, &t);
2696 init(t, timestamp, now);
2697}
2698
2699void LogMessageTime::init(const std::tm& t, std::time_t timestamp,
2700 WallTime now) {
2701 time_struct_ = t;
2702 timestamp_ = timestamp;
2703 usecs_ = static_cast<int32>((now - timestamp) * 1000000);
2704
2705 CalcGmtOffset();
2706}
2707
2708void LogMessageTime::CalcGmtOffset() {
2709 std::tm gmt_struct;
2710 int isDst = 0;
2711 if ( FLAGS_log_utc_time ) {
2712 localtime_r(&timestamp_, &gmt_struct);
2713 isDst = gmt_struct.tm_isdst;
2714 gmt_struct = time_struct_;
2715 } else {
2716 isDst = time_struct_.tm_isdst;
2717 gmtime_r(&timestamp_, &gmt_struct);
2718 }
2719
2720 time_t gmt_sec = mktime(&gmt_struct);
2721 const long hour_secs = 3600;
2722 // If the Daylight Saving Time(isDst) is active subtract an hour from the current timestamp.
2723 gmtoffset_ = static_cast<long int>(timestamp_ - gmt_sec + (isDst ? hour_secs : 0) ) ;
2724}
2725
Austin Schuh906616c2019-01-21 20:25:11 -08002726_END_GOOGLE_NAMESPACE_