From Maciej Krol,"With advent of GUI applications in OSG there is a growing need to redirect notification messages to third party systems. For example windows applications do not have console output, it would be appropriate to redirect notifications to GUI widget or debug output. I have revamped notification system to fit this need. New notification stream is using NotifyHandler as a message sink. Handler is called whenever stream is synchronized (i.e. after <<std::endl). Standard streams std::cout and std::cerr are no longer used although by default StandardNotifyHandler is a message sink. Custom notification handler can be set with osg::setNotifyHandler(NotifyHandler *) function.

Two implementations of NotifyHandler are currently available:
- StandardNotifyHandler, calls fputs(message, stderr) for severity <= WARN and fputs(message, stdout) for severity > WARN
- WinDebugNotifyHandler, windows users can redirect notifications to windows debug output, notifications can be viewed in output window of the debugger i.e. MSVC or DebugView (http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx) (see screenshot).

I have seen on osg-users that some people do std::cerr.rdbuf(otherStream.rdbuf()) to redirect notifications. This trick will no longer work since osg::notify() returns internal osg::NotifyStream not std::cout or std::cerr. You can use osg::notify().rdbuf(otherStream.rdbuf()) to do this instead.

Additionally I've made some minor fixes:
- Minor imrovements to osg::notify documentation
- NullStream could crash by deleting stream buffer other than default NullStreamBuffer in the destructor i.e. after osg::notify(osg::DEBUG_FP).rdbuf(otherStream.rdbuf())"
This commit is contained in:
Robert Osfield
2009-05-18 12:04:07 +00:00
parent 7dead3f52d
commit d38fb904d3
2 changed files with 191 additions and 43 deletions

View File

@@ -12,16 +12,95 @@
*/
#include <osg/Notify>
#include <osg/ApplicationUsage>
#include <osg/ref_ptr>
#include <string>
#include <stdlib.h>
#include <stdio.h>
#include <sstream>
#include <iostream>
#include <fstream>
using namespace std;
namespace osg
{
class NullStreamBuffer : public std::streambuf
{
private:
std::streamsize xsputn(const std::streambuf::char_type *str, std::streamsize n)
{
return n;
}
};
struct NullStream : public std::ostream
{
public:
NullStream():
std::ostream(&_buffer) {}
protected:
NullStreamBuffer _buffer;
};
/** Stream buffer calling notify handler when buffer is synchronized (usually on std::endl).
* Stream stores last notification severity to pass it to handler call.
*/
struct NotifyStreamBuffer : public std::stringbuf
{
NotifyStreamBuffer() : _severity(osg::NOTICE)
{
}
void setNotifyHandler(osg::NotifyHandler *handler) { _handler = handler; }
osg::NotifyHandler *getNotifyHandler() const { return _handler.get(); }
/** Sets severity for next call of notify handler */
void setCurrentSeverity(osg::NotifySeverity severity) { _severity = severity; }
osg::NotifySeverity getCurrentSeverity() const { return _severity; }
private:
int sync()
{
sputc(0); // string termination
if (_handler.valid())
_handler->notify(_severity, pbase());
pubseekpos(0, std::ios_base::out); // or str(std::string())
return 0;
}
osg::ref_ptr<osg::NotifyHandler> _handler;
osg::NotifySeverity _severity;
};
struct NotifyStream : public std::ostream
{
public:
NotifyStream():
std::ostream(&_buffer) {}
void setCurrentSeverity(osg::NotifySeverity severity)
{
_buffer.setCurrentSeverity(severity);
}
osg::NotifySeverity getCurrentSeverity() const
{
return _buffer.getCurrentSeverity();
}
protected:
NotifyStreamBuffer _buffer;
};
}
using namespace osg;
static osg::ApplicationUsageProxy Notify_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE, "OSG_NOTIFY_LEVEL <mode>", "FATAL | WARN | NOTICE | DEBUG_INFO | DEBUG_FP | DEBUG | INFO | ALWAYS");
osg::NotifySeverity g_NotifyLevel = osg::NOTICE;
osg::NullStream g_NullStream;
osg::NotifyStream g_NotifyStream;
void osg::setNotifyLevel(osg::NotifySeverity severity)
{
@@ -36,6 +115,19 @@ osg::NotifySeverity osg::getNotifyLevel()
return g_NotifyLevel;
}
void osg::setNotifyHandler(osg::NotifyHandler *handler)
{
osg::NotifyStreamBuffer *buffer = static_cast<osg::NotifyStreamBuffer *>(g_NotifyStream.rdbuf());
if (buffer)
buffer->setNotifyHandler(handler);
}
osg::NotifyHandler *getNotifyHandler()
{
osg::initNotifyLevel();
osg::NotifyStreamBuffer *buffer = static_cast<osg::NotifyStreamBuffer *>(g_NotifyStream.rdbuf());
return buffer ? buffer->getNotifyHandler() : 0;
}
bool osg::initNotifyLevel()
{
@@ -75,6 +167,11 @@ bool osg::initNotifyLevel()
}
// Setup standard notify handler
osg::NotifyStreamBuffer *buffer = dynamic_cast<osg::NotifyStreamBuffer *>(g_NotifyStream.rdbuf());
if (buffer && !buffer->getNotifyHandler())
buffer->setNotifyHandler(new StandardNotifyHandler);
s_NotifyInit = true;
return true;
@@ -86,45 +183,38 @@ bool osg::isNotifyEnabled( osg::NotifySeverity severity )
return severity<=g_NotifyLevel;
}
class NullStreamBuffer : public std::streambuf
{
private:
virtual streamsize xsputn (const char_type*, streamsize n)
{
return n;
}
};
struct NullStream : public std::ostream
{
NullStream():
std::ostream(new NullStreamBuffer) {}
virtual ~NullStream()
{
delete rdbuf();
rdbuf(0);
}
};
std::ostream& osg::notify(const osg::NotifySeverity severity)
{
// set up global notify null stream for inline notify
static NullStream s_NotifyNulStream;
static bool initialized = false;
if (!initialized)
{
std::cerr<<""; // dummy op to force construction of cerr, before a reference is passed back to calling code.
std::cout<<""; // dummy op to force construction of cout, before a reference is passed back to calling code.
initialized = osg::initNotifyLevel();
}
if (severity<=g_NotifyLevel)
{
if (severity<=osg::WARN) return std::cerr;
else return std::cout;
g_NotifyStream.setCurrentSeverity(severity);
return g_NotifyStream;
}
return s_NotifyNulStream;
return g_NullStream;
}
void osg::StandardNotifyHandler::notify(osg::NotifySeverity severity, const char *message)
{
if (severity <= osg::WARN)
fputs(message, stderr);
else
fputs(message, stdout);
}
#if defined(WIN32) && !defined(__CYGWIN__)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
void osg::WinDebugNotifyHandler::notify(osg::NotifySeverity severity, const char *message)
{
OutputDebugStringA(message);
}
#endif