Windows logging changes

- can log to the debugger (MSVC output window) via OutputDebugStr
- logging to the console is optional, triggered by new
  requestConsole hook()
This commit is contained in:
James Turner
2013-10-26 21:04:16 +01:00
parent f26f3b606d
commit 94326fd964
3 changed files with 122 additions and 34 deletions

View File

@@ -34,18 +34,15 @@ class BufferedLogCallback::BufferedLogCallbackPrivate
{
public:
SGMutex m_mutex;
sgDebugClass m_class;
sgDebugPriority m_priority;
vector_cstring m_buffer;
unsigned int m_stamp;
unsigned int m_maxLength;
};
BufferedLogCallback::BufferedLogCallback(sgDebugClass c, sgDebugPriority p) :
simgear::LogCallback(c,p),
d(new BufferedLogCallbackPrivate)
{
d->m_class = c;
d->m_priority = p;
d->m_stamp = 0;
d->m_maxLength = 0xffff;
}
@@ -63,7 +60,7 @@ void BufferedLogCallback::operator()(sgDebugClass c, sgDebugPriority p,
SG_UNUSED(file);
SG_UNUSED(line);
if ((c & d->m_class) == 0 || p < d->m_priority) return;
if (!shouldLog(c, p)) return;
vector_cstring::value_type msg;
if (aMessage.size() >= d->m_maxLength) {

View File

@@ -20,10 +20,13 @@
//
// $Id$
#include <simgear_config.h>
#include "logstream.hxx"
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <boost/foreach.hpp>
@@ -35,8 +38,8 @@
#include <simgear/misc/sg_path.hxx>
#ifdef _WIN32
// for AllocConsole
#ifdef SG_WINDOWS
// for AllocConsole, OutputDebugString
#include "windows.h"
#endif
@@ -73,37 +76,57 @@ const char* debugClassToString(sgDebugClass c)
//////////////////////////////////////////////////////////////////////////////
namespace simgear
{
LogCallback::LogCallback(sgDebugClass c, sgDebugPriority p) :
m_class(c),
m_priority(p)
{
}
bool LogCallback::shouldLog(sgDebugClass c, sgDebugPriority p) const
{
return ((c & m_class) != 0 && p >= m_priority);
}
void LogCallback::setLogLevels( sgDebugClass c, sgDebugPriority p )
{
m_priority = p;
m_class = c;
}
} // of namespace simgear
//////////////////////////////////////////////////////////////////////////////
class FileLogCallback : public simgear::LogCallback
{
public:
FileLogCallback(const std::string& aPath, sgDebugClass c, sgDebugPriority p) :
m_file(aPath.c_str(), std::ios_base::out | std::ios_base::trunc),
m_class(c),
m_priority(p)
simgear::LogCallback(c, p),
m_file(aPath.c_str(), std::ios_base::out | std::ios_base::trunc)
{
}
virtual void operator()(sgDebugClass c, sgDebugPriority p,
const char* file, int line, const std::string& message)
{
if ((c & m_class) == 0 || p < m_priority) return;
if (!shouldLog(c, p)) return;
m_file << debugClassToString(c) << ":" << (int) p
<< ":" << file << ":" << line << ":" << message << std::endl;
}
private:
std::ofstream m_file;
sgDebugClass m_class;
sgDebugPriority m_priority;
};
class StderrLogCallback : public simgear::LogCallback
{
public:
StderrLogCallback(sgDebugClass c, sgDebugPriority p) :
m_class(c),
m_priority(p)
simgear::LogCallback(c, p)
{
#ifdef _WIN32
#ifdef SG_WINDOWS
AllocConsole(); // but only if we want a console
freopen("conin$", "r", stdin);
freopen("conout$", "w", stdout);
@@ -111,29 +134,42 @@ public:
#endif
}
void setLogLevels( sgDebugClass c, sgDebugPriority p )
{
m_priority = p;
m_class = c;
}
virtual void operator()(sgDebugClass c, sgDebugPriority p,
const char* file, int line, const std::string& aMessage)
{
if ((c & m_class) == 0 || p < m_priority) return;
// if running under MSVC, we could use OutputDebugString here
if (!shouldLog(c, p)) return;
fprintf(stderr, "%s\n", aMessage.c_str());
//fprintf(stderr, "%s:%d:%s:%d:%s\n", debugClassToString(c), p,
// file, line, aMessage.c_str());
fflush(stderr);
}
private:
sgDebugClass m_class;
sgDebugPriority m_priority;
};
#ifdef SG_WINDOWS
class WinDebugLogCallback : public simgear::LogCallback
{
public:
WinDebugLogCallback(sgDebugClass c, sgDebugPriority p) :
simgear::LogCallback(c, p)
{
}
virtual void operator()(sgDebugClass c, sgDebugPriority p,
const char* file, int line, const std::string& aMessage)
{
if (!shouldLog(c, p)) return;
std::ostringstream os;
os << debugClassToString(c) << ":" << aMessage << std::endl;
OutputDebugStringA(os.str().c_str());
}
};
#endif
class LogStreamPrivate : public SGThread
{
private:
@@ -181,10 +217,20 @@ public:
LogStreamPrivate() :
m_logClass(SG_ALL),
m_logPriority(SG_ALERT),
m_isRunning(false)
m_isRunning(false),
m_consoleRequested(false)
{
m_stderrCallback = new StderrLogCallback(m_logClass, m_logPriority);
addCallback(m_stderrCallback);
#if !defined(SG_WINDOWS)
m_callbacks.push_back(new StderrLogCallback(m_logClass, m_logPriority));
m_consoleCallbacks.push_back(m_callbacks.back());
m_consoleRequested = true;
#endif
#if defined (SG_WINDOWS) && !defined(NDEBUG)
m_callbacks.push_back(new WinDebugLogCallback(m_logClass, m_logPriority));
m_consoleCallbacks.push_back(m_callbacks.back());
#endif
}
SGMutex m_lock;
@@ -192,11 +238,14 @@ public:
typedef std::vector<simgear::LogCallback*> CallbackVec;
CallbackVec m_callbacks;
/// subset of callbacks which correspond to stdout / console,
/// and hence should dynamically reflect console logging settings
CallbackVec m_consoleCallbacks;
sgDebugClass m_logClass;
sgDebugPriority m_logPriority;
bool m_isRunning;
StderrLogCallback* m_stderrCallback;
bool m_consoleRequested;
void startLog()
{
@@ -260,7 +309,9 @@ public:
PauseThread pause(this);
m_logPriority = p;
m_logClass = c;
m_stderrCallback->setLogLevels(c, p);
BOOST_FOREACH(simgear::LogCallback* cb, m_consoleCallbacks) {
cb->setLogLevels(c, p);
}
}
bool would_log( sgDebugClass c, sgDebugPriority p ) const
@@ -275,6 +326,18 @@ public:
LogEntry entry(c, p, fileName, line, msg);
m_entries.push(entry);
}
void requestConsole()
{
PauseThread pause(this);
if (m_consoleRequested) {
return;
}
m_consoleRequested = true;
m_callbacks.push_back(new StderrLogCallback(m_logClass, m_logPriority));
m_consoleCallbacks.push_back(m_callbacks.back());
}
};
/////////////////////////////////////////////////////////////////////////////
@@ -366,3 +429,13 @@ logstream::logToFile( const SGPath& aPath, sgDebugClass c, sgDebugPriority p )
global_privateLogstream->addCallback(new FileLogCallback(aPath.str(), c, p));
}
namespace simgear
{
void requestConsole()
{
sglog(); // force creation
global_privateLogstream->requestConsole();
}
} // of namespace simgear

View File

@@ -42,7 +42,23 @@ public:
virtual ~LogCallback() {}
virtual void operator()(sgDebugClass c, sgDebugPriority p,
const char* file, int line, const std::string& aMessage) = 0;
void setLogLevels(sgDebugClass c, sgDebugPriority p);
protected:
LogCallback(sgDebugClass c, sgDebugPriority p);
bool shouldLog(sgDebugClass c, sgDebugPriority p) const;
private:
sgDebugClass m_class;
sgDebugPriority m_priority;
};
/**
* Helper force a console on platforms where it might optional, when
* we need to show a console. This basically means Windows at the
* moment - on other plaforms it's a no-op
*/
void requestConsole();
} // of namespace simgear
@@ -103,6 +119,8 @@ private:
logstream& sglog();
/** \def SG_LOG(C,P,M)
* Log a message.
* @param C debug class