OSG修改日志输出到文件

版权声明:未经同意,不能用于商业用途,版权归本博主所有 https://blog.csdn.net/qq_16123279/article/details/82464831

osg嵌入到MFC后,就没有控制台了,为了方便看OSG的各种信息,所以要把输入日志打印到文本。

源码路径:
头文件:OpenSceneGraph-3.7.0\include\osg\Notify
源文件:OpenSceneGraph-3.7.0\src\osg\Notify.cpp

日志通知等级

enum NotifySeverity {
    ALWAYS=0,
    FATAL=1,
    WARN=2,
    NOTICE=3,
    INFO=4,
    DEBUG_INFO=5,
    DEBUG_FP=6
};

先别激动,来看看什什么等级的日志能notify

#define OSG_NOTIFY(level) if (osg::isNotifyEnabled(level)) osg::notify(level)
#define OSG_ALWAYS OSG_NOTIFY(osg::ALWAYS)
#define OSG_FATAL OSG_NOTIFY(osg::FATAL)
#define OSG_WARN OSG_NOTIFY(osg::WARN)
#define OSG_NOTICE OSG_NOTIFY(osg::NOTICE)
#define OSG_INFO OSG_NOTIFY(osg::INFO)
#define OSG_DEBUG OSG_NOTIFY(osg::DEBUG_INFO)
#define OSG_DEBUG_FP OSG_NOTIFY(osg::DEBUG_FP)

if (osg::isNotifyEnabled(level)) osg::notify(level),如果osg::isNotifyEnabled(level))返回真就通知,来看看里面都写了什么逻辑:

#ifndef OSG_NOTIFY_DISABLED
bool osg::isNotifyEnabled( osg::NotifySeverity severity )
{
    //入参要小于你设置的等级才会被通知,就是说你设置成ALWAYS,
    //永远不会触发notify(),你想全部消息都通告的话就设置成DEBUG_FP
    return severity<=getNotifySingleton()._notifyLevel;
}
#endif

上面说的好好注意下,我被坑过,以为把等级设置成ALWAYS是全部消息都打印,其实上什么消息都不被打印!!!!!

默认的通知等级跟通知输出设置

struct NotifySingleton
{
    NotifySingleton()
    {
        // _notifyLevel
        // =============

        _notifyLevel = osg::NOTICE; // Default value

        std::string OSGNOTIFYLEVEL;
        if(getEnvVar("OSG_NOTIFY_LEVEL", OSGNOTIFYLEVEL) || getEnvVar("OSGNOTIFYLEVEL", OSGNOTIFYLEVEL))
        {

            std::string stringOSGNOTIFYLEVEL(OSGNOTIFYLEVEL);

            // Convert to upper case
            for(std::string::iterator i=stringOSGNOTIFYLEVEL.begin();
                i!=stringOSGNOTIFYLEVEL.end();
                ++i)
            {
                *i=toupper(*i);
            }

            if(stringOSGNOTIFYLEVEL.find("ALWAYS")!=std::string::npos)          _notifyLevel=osg::ALWAYS;
            else if(stringOSGNOTIFYLEVEL.find("FATAL")!=std::string::npos)      _notifyLevel=osg::FATAL;
            else if(stringOSGNOTIFYLEVEL.find("WARN")!=std::string::npos)       _notifyLevel=osg::WARN;
            else if(stringOSGNOTIFYLEVEL.find("NOTICE")!=std::string::npos)     _notifyLevel=osg::NOTICE;
            else if(stringOSGNOTIFYLEVEL.find("DEBUG_INFO")!=std::string::npos) _notifyLevel=osg::DEBUG_INFO;
            else if(stringOSGNOTIFYLEVEL.find("DEBUG_FP")!=std::string::npos)   _notifyLevel=osg::DEBUG_FP;
            else if(stringOSGNOTIFYLEVEL.find("DEBUG")!=std::string::npos)      _notifyLevel=osg::DEBUG_INFO;
            else if(stringOSGNOTIFYLEVEL.find("INFO")!=std::string::npos)       _notifyLevel=osg::INFO;
            else std::cout << "Warning: invalid OSG_NOTIFY_LEVEL set ("<<stringOSGNOTIFYLEVEL<<")"<<std::endl;

        }

        // Setup standard notify handler
        osg::NotifyStreamBuffer *buffer = dynamic_cast<osg::NotifyStreamBuffer *>(_notifyStream.rdbuf());
        if (buffer && !buffer->getNotifyHandler())
            buffer->setNotifyHandler(new StandardNotifyHandler);
    }

    osg::NotifySeverity _notifyLevel;
    osg::NullStream     _nullStream;
    osg::NotifyStream   _notifyStream;
};

可以看出来,默认等级是osg::NOTICE,然后会到系统的环境变量名为:OSG_NOTIFY_LEVEL去读用户设置的通告等级,环境变量设置的格式为:
[变量名:值]->[OSG_NOTIFY_LEVEL :NOTICE ]

用户能干预的设置

再看头文件有4个导出的函数为:

extern OSG_EXPORT void setNotifyLevel(NotifySeverity severity);

/** get the notify level. */
extern OSG_EXPORT NotifySeverity getNotifyLevel();

/** initialize notify level. */
extern OSG_EXPORT bool initNotifyLevel();

#ifdef OSG_NOTIFY_DISABLED
    inline bool isNotifyEnabled(NotifySeverity) { return false; }
#else
    /** is notification enabled, given the current setNotifyLevel() setting? */
    extern OSG_EXPORT bool isNotifyEnabled(NotifySeverity severity);
#endif

extern OSG_EXPORT void setNotifyHandler(NotifyHandler *handler);

/** Get currrent notification handler. */
extern OSG_EXPORT NotifyHandler *getNotifyHandler();

这些函数就是用户能调用的,看函数名不难理解其用意,其中我们需要关心的就是
setNotifyLevelsetNotifyHandler,一个是设置通知的等级,一个是设置如何处理通告。通告的等级不难理解,如何处理通知看函数的传入参数为NotifyHandler *handler,所以我们需要继承这个类重写里面的方法来实现。

class OSG_EXPORT NotifyHandler : public osg::Referenced
{
public:
    virtual void notify(osg::NotifySeverity severity, const char *message) = 0;
};

写好后在调用的地方set一下就ok了。

实战例子

//重定向osg日志输出
class RoadbedNotifyHandler :public osg::NotifyHandler
{
public:
    virtual void notify(osg::NotifySeverity severity, const char *message)
    {
        if (severity <= osg::WARN)
            app_print_info(message_type::MT_INFO,message);
        else
        {
            std::string logFileName= string_tools::CString_to_string(file_tools::get_app_path_with_xg());
            logFileName += "3D_Error.log";

            FILE* fp=nullptr;
            fopen_s(&fp, logFileName.c_str(), "w");
            if (!fp)
            {
                app_print_info(message_type::MT_ERROR, _T("3D日志创建失败!"));
                return;
            }
            else
            {
                fprintf_s(fp, message);
                fputchar('\n');
                fclose(fp);
            }
        }
    }
};

/*调用*/
//设置成INFO就行了,DEBUG_FP每一帧都有N条消息吃不消
osg::setNotifyLevel(osg::NotifySeverity::INFO);
osg::setNotifyHandler(new RoadbedNotifyHandler);

猜你喜欢

转载自blog.csdn.net/qq_16123279/article/details/82464831