Time for action—saving the log file
We will make use of the std::ofstream
class to redirect the OSG internal notify messages to an external log file. The virtual function notify()
of the osg::NotifyHandler
derived class should be overridden to apply standard file stream operations, and a global function osg::setNotifyHandler()
is called before everything starts as well.
- Include the necessary headers:
#include <osgDB/ReadFile> #include <osgViewer/Viewer> #include <fstream>
- Implement the derived class
LogFileHandler
, which will redirect notify messages to the file stream:class LogFileHandler : public osg::NotifyHandler { public: LogFileHandler( const std::string& file ) { _log.open( file.c_str() ); } virtual ~LogFileHandler() { _log.close(); } virtual void notify(osg::NotifySeverity severity, const char* msg) { _log << msg; } protected: std::ofstream _log; };
- Now set a new notify handler to the entire OSG system, and work under the INFO level to see more verbose messages. The function
osgDB::readNodeFiles
here directly reads all usable filenames from the command line and merges them into the root node. We also add anOSG_FATAL
macro to check if there is no scene graph data loaded:int main( int argc, char** argv ) { osg::setNotifyLevel( osg::INFO ); osg::setNotifyHandler( new LogFileHandler("output.txt") ); osg::ArgumentParser arguments( &argc, argv ); osg::ref_ptr<osg::Node> root = osgDB::readNodeFiles( arguments ); if ( !root ) { OSG_FATAL << arguments.getApplicationName() <<": No data loaded." << std::endl; return -1; } osgViewer::Viewer viewer; viewer.setSceneData( root.get() ); return viewer.run(); }
- Build and start the example. All information will be saved in the log file
output.txt
, which is also indicated in the example. Try the command line with the newly-generated executableMyProject.exe
this time:# MyProject.exe dumptruck.osg
- Press the Esc key to quit, and then open the resulting log file in the working directory with notepad (on Windows) or any text editor:
- Don't be discouraged if you can't read and understand all of the information listed here. It only shows how OSG is starting and getting every part to work properly. It will be of great help in future development.
What just happened?
By default, OSG will send messages to the standard output stream std::cout
and error stream std::cerr
. However, these messages can be easily redirected to other streams and even the GUI text windows. A log file here is friendly to end users and helps them a lot, while sending feedbacks.
Besides, setting the osg::setNotifyLevel()
function will make the notify level reset to the specified level or a higher level. The notifier system then ignores statements from lower levels and prints nothing to the output stream. For instance, assuming that you have the following lines in your application:
osg::setNotifyLevel( osg::FATAL ); … osg::notify(osg::WARN) << "Some warn message." << std::endl;
The message with the notifier level lower than FATAL
will not be printed any more.
The environment variable OSG_NOTIFY_LEVEL
, which was mentioned in the previous chapter, can be used to control the displayed message level, too, for any OSG-based applications.