f9e44df1cc7bb09a7b8491e2f299e78a11e586b0
[platform/upstream/glog.git] / src / raw_logging.cc
1 // Copyright 2006 Google Inc. All Rights Reserved.
2 // Author: Maxim Lifantsev
3 //
4 // logging_unittest.cc covers the functionality herein
5
6 #include "utilities.h"
7
8 #include <stdarg.h>
9 #include <stdio.h>
10 #include <time.h>
11 #include "config.h"
12 #include "glog/logging.h"          // To pick up flag settings etc.
13 #include "glog/raw_logging.h"
14
15 #if defined(HAVE_SYSCALL_H)
16 #include <syscall.h>                 // for syscall()
17 #elif defined(HAVE_SYS_SYSCALL_H)
18 #include <sys/syscall.h>                 // for syscall()
19 #endif
20 #include <unistd.h>
21
22 #if defined(OS_MACOSX)
23 #ifndef __DARWIN_UNIX03
24 #define __DARWIN_UNIX03  // tells libgen.h to define basename()
25 #endif
26 #endif  // OS_MACOSX
27
28 #include <libgen.h>                      // basename()
29
30 _START_GOOGLE_NAMESPACE_
31
32 // Data for RawLog__ below. We simply pick up the latest
33 // time data created by a normal log message to avoid calling
34 // localtime_r which can allocate memory.
35 static struct ::tm last_tm_time_for_raw_log;
36
37 void RawLog__SetLastTime(const struct ::tm& t) {
38   memcpy(&last_tm_time_for_raw_log, &t, sizeof(last_tm_time_for_raw_log));
39 }
40
41 // CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
42 // that invoke malloc() and getenv() that might acquire some locks.
43 // If this becomes a problem we should reimplement a subset of vsnprintf
44 // that does not need locks and malloc.
45
46 // Helper for RawLog__ below.
47 // *DoRawLog writes to *buf of *size and move them past the written portion.
48 // It returns true iff there was no overflow or error.
49 static bool DoRawLog(char** buf, int* size, const char* format, ...) {
50   va_list ap;
51   va_start(ap, format);
52   int n = vsnprintf(*buf, *size, format, ap);
53   va_end(ap);
54   if (n < 0 || n > *size) return false;
55   *size -= n;
56   *buf += n;
57   return true;
58 }
59
60 // Helper for RawLog__ below.
61 inline static bool VADoRawLog(char** buf, int* size,
62                               const char* format, va_list ap) {
63   int n = vsnprintf(*buf, *size, format, ap);
64   if (n < 0 || n > *size) return false;
65   *size -= n;
66   *buf += n;
67   return true;
68 }
69
70 void RawLog__(LogSeverity severity, const char* file, int line,
71               const char* format, ...) {
72   if (!(FLAGS_logtostderr || severity >= FLAGS_stderrthreshold ||
73         FLAGS_alsologtostderr || !IsGoogleLoggingInitialized())) {
74     return;  // this stderr log message is suppressed
75   }
76   // can't call localtime_r here: it can allocate
77   struct ::tm& t = last_tm_time_for_raw_log;
78   char buffer[3000];  // 3000 bytes should be enough for everyone... :-)
79   char* buf = buffer;
80   int size = sizeof(buffer);
81   if (is_default_thread()) {
82      DoRawLog(&buf, &size, "%c%02d%02d %02d%02d%02d %s:%d] RAW: ",
83               LogSeverityNames[severity][0],
84               1 + t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,
85               basename(const_cast<char *>(file)), line);
86   } else {
87     DoRawLog(&buf, &size, "%c%02d%02d %02d%02d%02d %08x %s:%d] RAW: ",
88              LogSeverityNames[severity][0],
89              1 + t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,
90              int(pthread_self()),
91              basename(const_cast<char *>(file)), line);
92   }
93   va_list ap;
94   va_start(ap, format);
95   bool no_chop = VADoRawLog(&buf, &size, format, ap);
96   va_end(ap);
97   if (no_chop) {
98     DoRawLog(&buf, &size, "\n");
99   } else {
100     DoRawLog(&buf, &size, "RAW_LOG ERROR: The Message was too long!\n");
101   }
102   // We make a raw syscall to write directly to the stderr file descriptor,
103   // avoiding FILE buffering (to avoid invoking malloc()), and bypassing
104   // libc (to side-step any libc interception).
105   // We write just once to avoid races with other invocations of RawLog__.
106 #if defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)
107   syscall(SYS_write, STDERR_FILENO, buffer, strlen(buffer));
108 #else
109   write(STDERR_FILENO, buffer, strlen(buffer));
110 #endif
111   if (severity == FATAL)  LogMessage::Fail();
112 }
113
114 _END_GOOGLE_NAMESPACE_