barrier/lib/base/CLog.cpp
crs fee4095624 Reorganized source tree. Moved client.cpp into cmd/synergy as
synergy.cpp and server.cpp into cmd/synergyd as synergyd.cpp.
Moved and renamed related files.  Moved remaining source files
into lib/....  Modified and added makefiles as appropriate.
Result is that library files are under lib with each library
in its own directory and program files are under cmd with each
command in its own directory.
2002-07-30 16:52:46 +00:00

315 lines
6.5 KiB
C++

#include "CLog.h"
#include "CString.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#if WINDOWS_LIKE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define vsnprintf _vsnprintf
#endif
// names of priorities
static const char* g_priority[] = {
"FATAL",
"ERROR",
"WARNING",
"NOTE",
"INFO",
"DEBUG",
"DEBUG1",
"DEBUG2"
};
// number of priorities
static const int g_numPriority = (int)(sizeof(g_priority) /
sizeof(g_priority[0]));
// the default priority
#if defined(NDEBUG)
static const int g_defaultMaxPriority = 4;
#else
static const int g_defaultMaxPriority = 5;
#endif
// length of longest string in g_priority
static const int g_maxPriorityLength = 7;
// length of suffix string (": ")
static const int g_prioritySuffixLength = 2;
// amount of padded required to fill in the priority prefix
static const int g_priorityPad = g_maxPriorityLength +
g_prioritySuffixLength;
// platform newline sequence
#if WINDOWS_LIKE
static const char* g_newline = "\r\n";
#else
static const char* g_newline = "\n";
#endif
// minimum length of a newline sequence
static const int g_newlineLength = 2;
//
// CLog
//
CLog::Outputter CLog::s_outputter = NULL;
CLog::Lock CLog::s_lock = &CLog::dummyLock;
int CLog::s_maxPriority = -1;
void
CLog::print(const char* fmt, ...)
{
// check if fmt begins with a priority argument
int priority = 4;
if (fmt[0] == '%' && fmt[1] == 'z') {
priority = fmt[2] - '\060';
fmt += 3;
}
// done if below priority threshold
if (priority > getMaxPriority()) {
return;
}
// compute prefix padding length
int pad = g_priorityPad;
// print to buffer
char stack[1024];
va_list args;
va_start(args, fmt);
char* buffer = CStringUtil::vsprint(stack,
sizeof(stack) / sizeof(stack[0]),
pad, g_newlineLength, fmt, args);
va_end(args);
// output buffer
output(priority, buffer);
// clean up
if (buffer != stack)
delete[] buffer;
}
void
CLog::printt(const char* file, int line, const char* fmt, ...)
{
// check if fmt begins with a priority argument
int priority = 4;
if (fmt[0] == '%' && fmt[1] == 'z') {
priority = fmt[2] - '\060';
fmt += 3;
}
// done if below priority threshold
if (priority > getMaxPriority()) {
return;
}
// compute prefix padding length
char stack[1024];
sprintf(stack, "%d", line);
int pad = strlen(file) + 1 /* comma */ +
strlen(stack) + 1 /* colon */ + 1 /* space */ +
g_priorityPad;
// print to buffer, leaving space for a newline at the end
va_list args;
va_start(args, fmt);
char* buffer = CStringUtil::vsprint(stack,
sizeof(stack) / sizeof(stack[0]),
pad, g_newlineLength, fmt, args);
va_end(args);
// print the prefix to the buffer. leave space for priority label.
sprintf(buffer + g_priorityPad, "%s,%d:", file, line);
buffer[pad - 1] = ' ';
// discard file and line if priority < 0
char* message = buffer;
if (priority < 0) {
message += pad - g_priorityPad;
}
// output buffer
output(priority, message);
// clean up
if (buffer != stack)
delete[] buffer;
}
void
CLog::setOutputter(Outputter outputter)
{
CHoldLock lock(s_lock);
s_outputter = outputter;
}
CLog::Outputter
CLog::getOutputter()
{
CHoldLock lock(s_lock);
return s_outputter;
}
void
CLog::setLock(Lock newLock)
{
CHoldLock lock(s_lock);
s_lock = (newLock == NULL) ? dummyLock : newLock;
}
CLog::Lock
CLog::getLock()
{
CHoldLock lock(s_lock);
return (s_lock == dummyLock) ? NULL : s_lock;
}
bool
CLog::setFilter(const char* maxPriority)
{
if (maxPriority != NULL) {
for (int i = 0; i < g_numPriority; ++i) {
if (strcmp(maxPriority, g_priority[i]) == 0) {
setFilter(i);
return true;
}
}
return false;
}
return true;
}
void
CLog::setFilter(int maxPriority)
{
CHoldLock lock(s_lock);
s_maxPriority = maxPriority;
}
int
CLog::getFilter()
{
CHoldLock lock(s_lock);
return getMaxPriority();
}
void
CLog::dummyLock(bool)
{
// do nothing
}
int
CLog::getMaxPriority()
{
CHoldLock lock(s_lock);
if (s_maxPriority == -1) {
s_maxPriority = g_defaultMaxPriority;
setFilter(getenv("SYN_LOG_PRI"));
}
return s_maxPriority;
}
void
CLog::output(int priority, char* msg)
{
assert(priority >= -1 && priority < g_numPriority);
assert(msg != NULL);
// insert priority label
int n = -g_prioritySuffixLength;
if (priority >= 0) {
n = strlen(g_priority[priority]);
strcpy(msg + g_maxPriorityLength - n, g_priority[priority]);
msg[g_maxPriorityLength + 0] = ':';
msg[g_maxPriorityLength + 1] = ' ';
msg[g_maxPriorityLength + 1] = ' ';
}
// put a newline at the end
strcat(msg + g_priorityPad, g_newline);
// print it
CHoldLock lock(s_lock);
if (s_outputter == NULL ||
!s_outputter(priority, msg + g_maxPriorityLength - n)) {
#if WINDOWS_LIKE
openConsole();
#endif
fprintf(stderr, "%s", msg + g_maxPriorityLength - n);
}
}
#if WINDOWS_LIKE
static DWORD s_thread = 0;
static
BOOL WINAPI
CLogSignalHandler(DWORD)
{
// terminate cleanly and skip remaining handlers
PostThreadMessage(s_thread, WM_QUIT, 0, 0);
return TRUE;
}
void
CLog::openConsole()
{
static bool s_hasConsole = false;
// ignore if already created
if (s_hasConsole)
return;
// remember the current thread. when we get a ctrl+break or the
// console is closed we'll post WM_QUIT to this thread to shutdown
// cleanly.
// note -- win95/98/me are broken and will not receive a signal
// when the console is closed nor during logoff or shutdown,
// see microsoft articles Q130717 and Q134284. we could work
// around this in a painful way using hooks and hidden windows
// (as apache does) but it's not worth it. the app will still
// quit, just not cleanly. users in-the-know can use ctrl+c.
s_thread = GetCurrentThreadId();
// open a console
if (!AllocConsole())
return;
// get the handle for error output
HANDLE herr = GetStdHandle(STD_ERROR_HANDLE);
// prep console. windows 95 and its ilk have braindead
// consoles that can't even resize independently of the
// buffer size. use a 25 line buffer for those systems.
OSVERSIONINFO osInfo;
COORD size = { 80, 1000 };
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
if (GetVersionEx(&osInfo) &&
osInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
size.Y = 25;
SetConsoleScreenBufferSize(herr, size);
SetConsoleTextAttribute(herr,
FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE);
SetConsoleCtrlHandler(CLogSignalHandler, TRUE);
// reopen stderr to point at console
freopen("con", "w", stderr);
s_hasConsole = true;
}
#endif