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

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

Prefix the log messages with tid+time so I can make some sense of all this.

File size: 6.9 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 sprintf(stack, "%d", line);
129 pPad += strlen(file) + 1 /* comma */ +
130 strlen(stack) + 1 /* colon */ + 1 /* space */;
131 }
132
133 // compute suffix padding length
134 int sPad = m_maxNewlineLength;
135
136 // print to buffer, leaving space for a newline at the end and prefix
137 // at the beginning.
138 char* buffer = stack;
139 int len = (int)(sizeof(stack) / sizeof(stack[0]));
140 while (true) {
141 // try printing into the buffer
142 va_list args;
143 va_start(args, fmt);
144 int n = ARCH->vsnprintf(buffer + pPad, len - pPad - sPad, fmt, args);
145 va_end(args);
146
147 // if the buffer wasn't big enough then make it bigger and try again
148 if (n < 0 || n > (int)len) {
149 if (buffer != stack) {
150 delete[] buffer;
151 }
152 len *= 2;
153 buffer = new char[len];
154 }
155
156 // if the buffer was big enough then continue
157 else {
158 break;
159 }
160 }
161
162 // print the prefix to the buffer. leave space for priority label.
163 char* message = buffer;
164 if (file != NULL) {
165 sprintf(buffer + g_priorityPad, "%s,%d:", file, line);
166 buffer[pPad - 1] = ' ';
167
168 // discard file and line if priority < 0
169 if (priority < 0) {
170 message += pPad - g_priorityPad;
171 }
172 }
173
174 // output buffer
175 output(priority, message);
176
177 // clean up
178 if (buffer != stack) {
179 delete[] buffer;
180 }
181}
182
183void
184CLog::insert(ILogOutputter* outputter, bool alwaysAtHead)
185{
186 assert(outputter != NULL);
187 assert(outputter->getNewline() != NULL);
188
189 CArchMutexLock lock(m_mutex);
190 if (alwaysAtHead) {
191 m_alwaysOutputters.push_front(outputter);
192 }
193 else {
194 m_outputters.push_front(outputter);
195 }
196 int newlineLength = strlen(outputter->getNewline());
197 if (newlineLength > m_maxNewlineLength) {
198 m_maxNewlineLength = newlineLength;
199 }
200 outputter->open(kAppVersion);
201 outputter->show(false);
202}
203
204void
205CLog::remove(ILogOutputter* outputter)
206{
207 CArchMutexLock lock(m_mutex);
208 m_outputters.remove(outputter);
209 m_alwaysOutputters.remove(outputter);
210}
211
212void
213CLog::pop_front(bool alwaysAtHead)
214{
215 CArchMutexLock lock(m_mutex);
216 COutputterList* list = alwaysAtHead ? &m_alwaysOutputters : &m_outputters;
217 if (!list->empty()) {
218 delete list->front();
219 list->pop_front();
220 }
221}
222
223bool
224CLog::setFilter(const char* maxPriority)
225{
226 if (maxPriority != NULL) {
227 for (int i = 0; i < g_numPriority; ++i) {
228 if (strcmp(maxPriority, g_priority[i]) == 0) {
229 setFilter(i);
230 return true;
231 }
232 }
233 return false;
234 }
235 return true;
236}
237
238void
239CLog::setFilter(int maxPriority)
240{
241 CArchMutexLock lock(m_mutex);
242 m_maxPriority = maxPriority;
243}
244
245int
246CLog::getFilter() const
247{
248 CArchMutexLock lock(m_mutex);
249 return m_maxPriority;
250}
251
252void
253CLog::output(int priority, char* msg) const
254{
255 assert(priority >= -1 && priority < g_numPriority);
256 assert(msg != NULL);
257
258 // insert priority label
259 int n = -g_prioritySuffixLength;
260 if (priority >= 0) {
261#ifdef __OS2__
262 char sz[80];
263 snprintf(sz, sizeof(sz), "%d %d %s", fibGetMsCount(), fibGetTid(), g_priority[priority]);
264 n = strlen(sz);
265 assert(n <= g_maxPriorityLength);
266 strcpy(msg + g_maxPriorityLength - n, sz);
267#else
268 n = strlen(g_priority[priority]);
269 strcpy(msg + g_maxPriorityLength - n, g_priority[priority]);
270#endif
271 msg[g_maxPriorityLength + 0] = ':';
272 msg[g_maxPriorityLength + 1] = ' ';
273 }
274
275 // find end of message
276 char* end = msg + g_priorityPad + strlen(msg + g_priorityPad);
277
278 // write to each outputter
279 CArchMutexLock lock(m_mutex);
280 for (COutputterList::const_iterator index = m_alwaysOutputters.begin();
281 index != m_alwaysOutputters.end();
282 ++index) {
283 // get outputter
284 ILogOutputter* outputter = *index;
285
286 // put an appropriate newline at the end
287 strcpy(end, outputter->getNewline());
288
289 // write message
290 outputter->write(static_cast<ILogOutputter::ELevel>(priority),
291 msg + g_maxPriorityLength - n);
292 }
293 for (COutputterList::const_iterator index = m_outputters.begin();
294 index != m_outputters.end(); ++index) {
295 // get outputter
296 ILogOutputter* outputter = *index;
297
298 // put an appropriate newline at the end
299 strcpy(end, outputter->getNewline());
300
301 // write message and break out of loop if it returns false
302 if (!outputter->write(static_cast<ILogOutputter::ELevel>(priority),
303 msg + g_maxPriorityLength - n)) {
304 break;
305 }
306 }
307}
Note: See TracBrowser for help on using the repository browser.