root/OpenSceneGraph/trunk/src/osg/Notify.cpp @ 10229

Revision 10229, 6.1 kB (checked in by robert, 5 years ago)

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())"

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13#include <osg/Notify>
14#include <osg/ApplicationUsage>
15#include <osg/ref_ptr>
16#include <string>
17#include <stdlib.h>
18#include <stdio.h>
19#include <sstream>
20#include <iostream>
21
22namespace osg
23{
24
25class NullStreamBuffer : public std::streambuf
26{
27private:
28    std::streamsize xsputn(const std::streambuf::char_type *str, std::streamsize n)
29    {
30        return n;
31    }
32};
33
34struct NullStream : public std::ostream
35{
36public:
37    NullStream():
38        std::ostream(&_buffer) {}
39
40protected:
41    NullStreamBuffer _buffer;
42};
43
44/** Stream buffer calling notify handler when buffer is synchronized (usually on std::endl).
45 * Stream stores last notification severity to pass it to handler call.
46 */
47struct NotifyStreamBuffer : public std::stringbuf
48{
49    NotifyStreamBuffer() : _severity(osg::NOTICE)
50    {
51    }
52
53    void setNotifyHandler(osg::NotifyHandler *handler) { _handler = handler; }
54    osg::NotifyHandler *getNotifyHandler() const { return _handler.get(); }
55
56    /** Sets severity for next call of notify handler */
57    void setCurrentSeverity(osg::NotifySeverity severity) { _severity = severity; }
58    osg::NotifySeverity getCurrentSeverity() const { return _severity; }
59
60private:
61
62    int sync()
63    {
64        sputc(0); // string termination
65        if (_handler.valid())
66            _handler->notify(_severity, pbase());
67        pubseekpos(0, std::ios_base::out); // or str(std::string())
68        return 0;
69    }
70
71    osg::ref_ptr<osg::NotifyHandler> _handler;
72    osg::NotifySeverity _severity;
73};
74
75struct NotifyStream : public std::ostream
76{
77public:
78    NotifyStream():
79        std::ostream(&_buffer) {}
80
81    void setCurrentSeverity(osg::NotifySeverity severity)
82    {
83        _buffer.setCurrentSeverity(severity);
84    }
85
86    osg::NotifySeverity getCurrentSeverity() const
87    {
88        return _buffer.getCurrentSeverity();
89    }
90
91protected:
92    NotifyStreamBuffer _buffer;
93};
94
95}
96
97using namespace osg;
98
99static osg::ApplicationUsageProxy Notify_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE, "OSG_NOTIFY_LEVEL <mode>", "FATAL | WARN | NOTICE | DEBUG_INFO | DEBUG_FP | DEBUG | INFO | ALWAYS");
100
101osg::NotifySeverity g_NotifyLevel = osg::NOTICE;
102osg::NullStream g_NullStream;
103osg::NotifyStream g_NotifyStream;
104
105void osg::setNotifyLevel(osg::NotifySeverity severity)
106{
107    osg::initNotifyLevel();
108    g_NotifyLevel = severity;
109}
110
111
112osg::NotifySeverity osg::getNotifyLevel()
113{
114    osg::initNotifyLevel();
115    return g_NotifyLevel;
116}
117
118void osg::setNotifyHandler(osg::NotifyHandler *handler)
119{
120    osg::NotifyStreamBuffer *buffer = static_cast<osg::NotifyStreamBuffer *>(g_NotifyStream.rdbuf());
121    if (buffer)
122        buffer->setNotifyHandler(handler);
123}
124
125osg::NotifyHandler *getNotifyHandler()
126{
127    osg::initNotifyLevel();
128    osg::NotifyStreamBuffer *buffer = static_cast<osg::NotifyStreamBuffer *>(g_NotifyStream.rdbuf());
129    return buffer ? buffer->getNotifyHandler() : 0;
130}
131
132bool osg::initNotifyLevel()
133{
134    static bool s_NotifyInit = false;
135
136    if (s_NotifyInit) return true;
137   
138    // g_NotifyLevel
139    // =============
140
141    g_NotifyLevel = osg::NOTICE; // Default value
142
143    char* OSGNOTIFYLEVEL=getenv("OSG_NOTIFY_LEVEL");
144    if (!OSGNOTIFYLEVEL) OSGNOTIFYLEVEL=getenv("OSGNOTIFYLEVEL");
145    if(OSGNOTIFYLEVEL)
146    {
147
148        std::string stringOSGNOTIFYLEVEL(OSGNOTIFYLEVEL);
149
150        // Convert to upper case
151        for(std::string::iterator i=stringOSGNOTIFYLEVEL.begin();
152            i!=stringOSGNOTIFYLEVEL.end();
153            ++i)
154        {
155            *i=toupper(*i);
156        }
157
158        if(stringOSGNOTIFYLEVEL.find("ALWAYS")!=std::string::npos)          g_NotifyLevel=osg::ALWAYS;
159        else if(stringOSGNOTIFYLEVEL.find("FATAL")!=std::string::npos)      g_NotifyLevel=osg::FATAL;
160        else if(stringOSGNOTIFYLEVEL.find("WARN")!=std::string::npos)       g_NotifyLevel=osg::WARN;
161        else if(stringOSGNOTIFYLEVEL.find("NOTICE")!=std::string::npos)     g_NotifyLevel=osg::NOTICE;
162        else if(stringOSGNOTIFYLEVEL.find("DEBUG_INFO")!=std::string::npos) g_NotifyLevel=osg::DEBUG_INFO;
163        else if(stringOSGNOTIFYLEVEL.find("DEBUG_FP")!=std::string::npos)   g_NotifyLevel=osg::DEBUG_FP;
164        else if(stringOSGNOTIFYLEVEL.find("DEBUG")!=std::string::npos)      g_NotifyLevel=osg::DEBUG_INFO;
165        else if(stringOSGNOTIFYLEVEL.find("INFO")!=std::string::npos)       g_NotifyLevel=osg::INFO;
166        else std::cout << "Warning: invalid OSG_NOTIFY_LEVEL set ("<<stringOSGNOTIFYLEVEL<<")"<<std::endl;
167 
168    }
169
170    // Setup standard notify handler
171    osg::NotifyStreamBuffer *buffer = dynamic_cast<osg::NotifyStreamBuffer *>(g_NotifyStream.rdbuf());
172    if (buffer && !buffer->getNotifyHandler())
173        buffer->setNotifyHandler(new StandardNotifyHandler);
174
175    s_NotifyInit = true;
176
177    return true;
178
179}
180
181bool osg::isNotifyEnabled( osg::NotifySeverity severity )
182{
183    return severity<=g_NotifyLevel;
184}
185
186std::ostream& osg::notify(const osg::NotifySeverity severity)
187{
188    static bool initialized = false;
189    if (!initialized)
190    {
191        initialized = osg::initNotifyLevel();
192    }
193
194    if (severity<=g_NotifyLevel)
195    {
196        g_NotifyStream.setCurrentSeverity(severity);
197        return g_NotifyStream;
198    }
199    return g_NullStream;
200}
201
202void osg::StandardNotifyHandler::notify(osg::NotifySeverity severity, const char *message)
203{
204    if (severity <= osg::WARN)
205        fputs(message, stderr);
206    else
207        fputs(message, stdout);
208}
209
210#if defined(WIN32) && !defined(__CYGWIN__)
211
212#define WIN32_LEAN_AND_MEAN
213#include <windows.h>
214
215void osg::WinDebugNotifyHandler::notify(osg::NotifySeverity severity, const char *message)
216{
217    OutputDebugStringA(message);
218}
219
220#endif
Note: See TracBrowser for help on using the browser.