Remove unused header include
[xapian.git] / xapian-core / common / debuglog.cc
bloba215817f3a1aadaac31e16f94d754d8d6d27569d
1 /** @file debuglog.cc
2 * @brief Debug logging macros.
3 */
4 /* Copyright (C) 2008,2011,2012,2014,2015 Olly Betts
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <config.h>
23 #ifdef XAPIAN_DEBUG_LOG
25 #include "debuglog.h"
27 #include "errno_to_string.h"
28 #include "str.h"
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include "safeerrno.h"
33 #include "safefcntl.h"
34 #include "safeunistd.h"
36 #include <cstdlib> // For getenv().
37 #include <string>
39 using namespace std;
41 DebugLogger xapian_debuglogger_;
43 // We use O_SYNC to attempt to ensure that debug output is written to disk so
44 // that none is lost if we crash. Some platforms (e.g. mingw) don't support
45 // O_SYNC, so on these we just don't use it.
46 #ifndef O_SYNC
47 # define O_SYNC 0
48 #endif
50 DebugLogger::~DebugLogger()
52 LOGLINE(ALWAYS, PACKAGE_STRING": debug log ended");
55 void
56 DebugLogger::initialise_categories_mask()
58 fd = -2;
59 const char * f = getenv("XAPIAN_DEBUG_LOG");
60 if (f && *f) {
61 if (f[0] == '-' && f[1] == '\0') {
62 // Filename "-" means "log to stderr".
63 fd = 2;
64 } else {
65 string fnm, pid;
66 while (*f) {
67 if (*f == '%' && f[1] == 'p') {
68 // Replace %p in the filename with the process id.
69 if (pid.empty()) pid = str(getpid());
70 fnm += pid;
71 f += 2;
72 } else {
73 fnm += *f++;
77 fd = open(fnm.c_str(), O_CREAT|O_WRONLY|O_SYNC|O_APPEND|O_CLOEXEC, 0644);
78 if (fd == -1) {
79 // If we failed to open the log file, report to stderr, but
80 // don't spew all the log output to stderr too or else the
81 // user will probably miss the message about the debug log
82 // failing to open!
83 fd = 2;
84 string e;
85 errno_to_string(errno, e);
86 LOGLINE(ALWAYS, PACKAGE_STRING": Failed to open debug log '"
87 << fnm << "' (" << e << ')');
88 fd = -2;
92 if (fd >= 0) {
93 const char * v = getenv("XAPIAN_DEBUG_FLAGS");
94 if (v) {
95 bool toggle = (*v == '-');
96 if (toggle) ++v;
97 categories_mask = 0;
98 while (*v) {
99 int ch = *v++ - '@';
100 if (ch > 0 && ch <= 26) categories_mask |= 1ul << ch;
102 if (toggle) categories_mask ^= 0xffffffff;
106 LOGLINE(ALWAYS, PACKAGE_STRING": debug log started");
109 void
110 DebugLogger::log_line(debuglog_categories category, const string & msg)
112 if (fd < 0) return;
114 // Preserve errno over logging calls, so they can safely be added to code
115 // which expects errno not to change.
116 int saved_errno = errno;
118 string line;
119 line.reserve(9 + indent_level + msg.size());
120 line = char(category) + '@';
121 line += ' ';
122 line += str(getpid());
123 line.append(indent_level + 1, ' ');
124 line += msg;
125 line += '\n';
127 const char * p = line.data();
128 size_t to_do = line.size();
129 while (to_do) {
130 ssize_t n = write(fd, p, to_do);
131 if (n < 0) {
132 // Retry if interrupted by a signal.
133 if (errno == EINTR) continue;
135 // Upon other errors, close the log file, moan to stderr, and stop
136 // logging.
137 (void)close(fd);
138 fd = 2;
139 string e;
140 errno_to_string(errno, e);
141 LOGLINE(ALWAYS, PACKAGE_STRING": Failed to write log output ("
142 << e << ')');
143 fd = -2;
144 break;
146 p += n;
147 to_do -= n;
150 errno = saved_errno;
153 #endif // XAPIAN_DEBUG_LOG