source: trunk/synergy/lib/base/CLog.cpp@ 3232

Last change on this file since 3232 was 2760, checked in by bird, 19 years ago

skip the part of the file path which isn't interesting.

File size: 7.2 KB
Line 
1/*
2 * synergy -- mouse and keyboard sharing utility
3 * Copyright (C) 2002 Chris Schoeneman
4 *
5 * This package is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * found in the file COPYING that should have accompanied this file.
8 *
9 * This package is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include "CLog.h"
16#include "CString.h"
17#include "CStringUtil.h"
18#include "LogOutputters.h"
19#include "CArch.h"
20#include "Version.h"
21#include <cstdio>
22#include <cstring>
23#ifdef __OS2__
24# include <InnoTekLIBC/FastInfoBlocks.h>
25#endif
26
27// names of priorities
28static const char* g_priority[] = {
29 "FATAL",
30 "ERROR",
31 "WARNING",
32 "NOTE",
33 "INFO",
34 "DEBUG",
35 "DEBUG1",
36 "DEBUG2"
37 };
38
39// number of priorities
40static const int g_numPriority = (int)(sizeof(g_priority) /
41 sizeof(g_priority[0]));
42
43// the default priority
44#if defined(NDEBUG)
45static const int g_defaultMaxPriority = 4;
46#else
47static const int g_defaultMaxPriority = 5;
48#endif
49
50// length of longest string in g_priority
51#ifdef __OS2__
52static const int g_maxPriorityLength = 7 + 30;
53#else
54static const int g_maxPriorityLength = 7;
55#endif
56
57// length of suffix string (": ")
58static const int g_prioritySuffixLength = 2;
59
60// amount of padded required to fill in the priority prefix
61static const int g_priorityPad = g_maxPriorityLength +
62 g_prioritySuffixLength;
63
64
65//
66// CLog
67//
68
69CLog* CLog::s_log = NULL;
70
71CLog::CLog()
72{
73 assert(s_log == NULL);
74
75 // create mutex for multithread safe operation
76 m_mutex = ARCH->newMutex();
77
78 // other initalization
79 m_maxPriority = g_defaultMaxPriority;
80 m_maxNewlineLength = 0;
81 insert(new CConsoleLogOutputter);
82}
83
84CLog::~CLog()
85{
86 // clean up
87 for (COutputterList::iterator index = m_outputters.begin();
88 index != m_outputters.end(); ++index) {
89 delete *index;
90 }
91 for (COutputterList::iterator index = m_alwaysOutputters.begin();
92 index != m_alwaysOutputters.end(); ++index) {
93 delete *index;
94 }
95 ARCH->closeMutex(m_mutex);
96 s_log = NULL;
97}
98
99CLog*
100CLog::getInstance()
101{
102 // note -- not thread safe; client must initialize log safely
103 if (s_log == NULL) {
104 s_log = new CLog;
105 }
106 return s_log;
107}
108
109void
110CLog::print(const char* file, int line, const char* fmt, ...) const
111{
112 // check if fmt begins with a priority argument
113 int priority = 4;
114 if (fmt[0] == '%' && fmt[1] == 'z') {
115 priority = fmt[2] - '\060';
116 fmt += 3;
117 }
118
119 // done if below priority threshold
120 if (priority > getFilter()) {
121 return;
122 }
123
124 // compute prefix padding length
125 char stack[1024];
126 int pPad = g_priorityPad;
127 if (file != NULL) {
128#ifdef __OS2__ /* only last two levels (very annoying otherwise). */
129 const size_t cchPrefix = sizeof(__FILE__) - sizeof("lib/base/CLog.cpp");
130 if (!strncmp(file, __FILE__, cchPrefix)) {
131 file += cchPrefix;
132 }
133#endif
134 sprintf(stack, "%d", line);
135 pPad += strlen(file) + 1 /* comma */ +
136 strlen(stack) + 1 /* colon */ + 1 /* space */;
137 }
138
139 // compute suffix padding length
140 int sPad = m_maxNewlineLength;
141
142 // print to buffer, leaving space for a newline at the end and prefix
143 // at the beginning.
144 char* buffer = stack;
145 int len = (int)(sizeof(stack) / sizeof(stack[0]));
146 while (true) {
147 // try printing into the buffer
148 va_list args;
149 va_start(args, fmt);
150 int n = ARCH->vsnprintf(buffer + pPad, len - pPad - sPad, fmt, args);
151 va_end(args);
152
153 // if the buffer wasn't big enough then make it bigger and try again
154 if (n < 0 || n > (int)len) {
155 if (buffer != stack) {
156 delete[] buffer;
157 }
158 len *= 2;
159 buffer = new char[len];
160 }
161
162 // if the buffer was big enough then continue
163 else {
164 break;
165 }
166 }
167
168 // print the prefix to the buffer. leave space for priority label.
169 char* message = buffer;
170 if (file != NULL) {
171 sprintf(buffer + g_priorityPad, "%s,%d:", file, line);
172 buffer[pPad - 1] = ' ';
173
174 // discard file and line if priority < 0
175 if (priority < 0) {
176 message += pPad - g_priorityPad;
177 }
178 }
179
180 // output buffer
181 output(priority, message);
182
183 // clean up
184 if (buffer != stack) {
185 delete[] buffer;
186 }
187}
188
189void
190CLog::insert(ILogOutputter* outputter, bool alwaysAtHead)
191{
192 assert(outputter != NULL);
193 assert(outputter->getNewline() != NULL);
194
195 CArchMutexLock lock(m_mutex);
196 if (alwaysAtHead) {
197 m_alwaysOutputters.push_front(outputter);
198 }
199 else {
200 m_outputters.push_front(outputter);
201 }
202 int newlineLength = strlen(outputter->getNewline());
203 if (newlineLength > m_maxNewlineLength) {
204 m_maxNewlineLength = newlineLength;
205 }
206 outputter->open(kAppVersion);
207 outputter->show(false);
208}
209
210void
211CLog::remove(ILogOutputter* outputter)
212{
213 CArchMutexLock lock(m_mutex);
214 m_outputters.remove(outputter);
215 m_alwaysOutputters.remove(outputter);
216}
217
218void
219CLog::pop_front(bool alwaysAtHead)
220{
221 CArchMutexLock lock(m_mutex);
222 COutputterList* list = alwaysAtHead ? &m_alwaysOutputters : &m_outputters;
223 if (!list->empty()) {
224 delete list->front();
225 list->pop_front();
226 }
227}
228
229bool
230CLog::setFilter(const char* maxPriority)
231{
232 if (maxPriority != NULL) {
233 for (int i = 0; i < g_numPriority; ++i) {
234 if (strcmp(maxPriority, g_priority[i]) == 0) {
235 setFilter(i);
236 return true;
237 }
238 }
239 return false;
240 }
241 return true;
242}
243
244void
245CLog::setFilter(int maxPriority)
246{
247 CArchMutexLock lock(m_mutex);
248 m_maxPriority = maxPriority;
249}
250
251int
252CLog::getFilter() const
253{
254 CArchMutexLock lock(m_mutex);
255 return m_maxPriority;
256}
257
258void
259CLog::output(int priority, char* msg) const
260{
261 assert(priority >= -1 && priority < g_numPriority);
262 assert(msg != NULL);
263
264 // insert priority label
265 int n = -g_prioritySuffixLength;
266 if (priority >= 0) {
267#ifdef __OS2__
268 char sz[80];
269 snprintf(sz, sizeof(sz), "%d %d %s", fibGetMsCount(), fibGetTid(), g_priority[priority]);
270 n = strlen(sz);
271 assert(n <= g_maxPriorityLength);
272 strcpy(msg + g_maxPriorityLength - n, sz);
273#else
274 n = strlen(g_priority[priority]);
275 strcpy(msg + g_maxPriorityLength - n, g_priority[priority]);
276#endif
277 msg[g_maxPriorityLength + 0] = ':';
278 msg[g_maxPriorityLength + 1] = ' ';
279 }
280
281 // find end of message
282 char* end = msg + g_priorityPad + strlen(msg + g_priorityPad);
283
284 // write to each outputter
285 CArchMutexLock lock(m_mutex);
286 for (COutputterList::const_iterator index = m_alwaysOutputters.begin();
287 index != m_alwaysOutputters.end();
288 ++index) {
289 // get outputter
290 ILogOutputter* outputter = *index;
291
292 // put an appropriate newline at the end
293 strcpy(end, outputter->getNewline());
294
295 // write message
296 outputter->write(static_cast<ILogOutputter::ELevel>(priority),
297 msg + g_maxPriorityLength - n);
298 }
299 for (COutputterList::const_iterator index = m_outputters.begin();
300 index != m_outputters.end(); ++index) {
301 // get outputter
302 ILogOutputter* outputter = *index;
303
304 // put an appropriate newline at the end
305 strcpy(end, outputter->getNewline());
306
307 // write message and break out of loop if it returns false
308 if (!outputter->write(static_cast<ILogOutputter::ELevel>(priority),
309 msg + g_maxPriorityLength - n)) {
310 break;
311 }
312 }
313}
Note: See TracBrowser for help on using the repository browser.