Home > Software design >  how to split log messages into file and screen in wxwidgets
how to split log messages into file and screen in wxwidgets

Time:09-07

When I read the WxWidgets documentation, I get the impression that the developers wrote it just for themselves, just to remember what they did 20 years ago.

Regardless, I figured out how to send log messages to a file:

wxLog::SetActiveTarget(new wxLogStderr(fopen(logPath   "/wxApp.log", "w   ")));

and also I figured out how to change the format of the log messages:

wxLog::GetActiveTarget()->SetFormatter(new MyLogger);

But I didn't understand anything else.
So I want to ask my question here.

I want to make a log for my application.
Moreover, I want:

  1. all log messages to be written to a file
  2. at the same time some of these messages are displayed on the screen using wxTextCtrl.

    So I want to filter the log messages that are displayed on the screen, depending on the logging level:
    for example, I want to display in wxTextCtrl only log messages with "wxLOG_Info" and "wxLOG_Error" levels.

How can this be done in Windows and Linux in C ? It's best to show a code example.

CodePudding user response:

I may be missing something but this seems very simple?

For example, this could be the simplest possible log target which logs some messages into a wxTextCtrl and all of them into a wxFFile.

#include <wx/wx.h>
#include <wx/ffile.h>

class MyLogTarget : public wxLog
{
public:
    // textCtrl must have longer lifetime than MyLogTarget
    MyLogTarget(wxTextCtrl* textCtrl, const wxString& fileName)
        : m_textCtrl(textCtrl), m_file(fileName, "a")
    {}
protected:
    void DoLogTextAtLevel(wxLogLevel level, const wxString& msg) override
    {
        // preserve debug logging
        if ( level == wxLOG_Debug || level == wxLOG_Trace )
            wxLog::DoLogTextAtLevel(level, msg);

        if ( level == wxLOG_Info || level == wxLOG_Error )
            m_textCtrl->AppendText(msg   "\n");
        
        if ( m_file.IsOpened() )
            m_file.Write(msg   "\n");
    }
private:
    wxTextCtrl* m_textCtrl;
    wxFFile     m_file;
};

class MyFrame : public wxFrame
{
public:
    MyFrame(wxWindow* parent = nullptr) : wxFrame(parent, wxID_ANY, "Test")
    {
        wxTextCtrl* logCtrl = new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2);
        wxLog::SetActiveTarget(new MyLogTarget(logCtrl, "log.txt"));

        wxLogDebug("Debug test");
        wxLogMessage("Message test");
        wxLogInfo("Info test");
        wxLogError("Error test");
    }
    ~MyFrame()
    {
        delete wxLog::SetActiveTarget(nullptr);
    }
};

class MyApp : public wxApp
{
public:
    bool OnInit() override
    {
        (new MyFrame())->Show();
        return true;
    }
}; wxIMPLEMENT_APP(MyApp);

Please notice that this would have to be extended to be usable in a real application, for example, handle the file encoding / flushing / cleaning / error handling (without getting into the endless logging loop), use the full path for the file (e.g., obtained with wxStandardPaths), use a log chain to preserve (some of?) the default wxWidgets logging...

If you want to use separate log targets for logging into a text control and a file, it is still very simple except that you have to chain the log targets, as explained in the docs.

  • Related