Kod źródłowy i środowisko
Poniższa funkcja jest używana jako uchwyt dla wiadomości z systemu debugowania Qt. Także została ona załadowana pośrednio za pomocą qInstallMessageHandler(). Kod źródłowy w uproszczonej formie wygląda tak:
class MyLogger {
public:
// Konstruktor
QFile* _file;
QString _fileName = "filename.log";
QFileStream* _fileStream;
MyLogger() {
_file = new QFile(_fileName);
bool isOpened = _file->open(QIODevice::Append | QIODevice::Text | QIODevice::WriteOnly | QIODevice::Unbuffered);
if (!isOpened) {
// koniec z aplikacja
} else {
_fileStream = new QTextStream(_file);
}
}
// Uchwyt zainstalowany przez qInstallMessageHandler
MessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message)
{
QString myMessage = message;
// Przygotowanie wiadomości
*_fileStream << messageLine;
}
};
W takim przypadku, kiedy wiadomości zrobi się odrobinę więcej może natknąć się na dziwne błędy na temat uszkodzenia stosu takie jak "Invalid address specified to RtlValidateHeap"!Gdzie leży problem i rozwiązanie
Ciężko jest mi określić gdzie problem dokładnie leży, ponieważ siedzi to gdzieś w bibliotekach Qt. Jeśli ktoś ma jakąś większą wiedzę na ten temat to z chęcią się dowiem.
Najszybsze i najprostsze, acz nienajlepsze, rozwiazanie, to zapis bezpośrednio do pliku, czyli MessageHandler powinien wyglądać tak:
// Uchwyt zainstalowany przez qInstallMessageHandler
MessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message)
{
QString myMessage = message;
// Przygotowanie wiadomości
_file->write(myMessage.toStdString().c_str(), myMessage.toStdString().length());
}
};
Jednak z tak prostym rozwiązaniem należy uważać! Otóż może dojść do tego, że dwa szybko następujące po sobie wywołania MessageHandler mogą spowodować że dwie różne wiadomości wymieszają się w pliku i będą nie do odczytu!.Aktualizacja 2019-11-04
Okazało się, że zunięcie flagi QIODevice::Text podczas otwierania pliku zwiększa odrobine stabilność QTexyStream – czasem można było zaobserwować w _fileStream, że ustawił sobie on flagę oznaczającą błąd zapisu (dostępna za pomocą QTextStream::status()) i potem bezpiecznie ignorowane były wszystkie inne polecenia pisania do tego strumienia – takie zachowanie według mnie powinno być zawsze niezależnie od flagi czy innych zmiennych – wystąpił błąd - odłączamy się od działania i pa pa, w szczególności kiedy kod jest tworzony bezwyjątkowo.
Co ciekawsze, flaga QIODevice::Text wprowadzała kolejny problem: otóż co jakiś czas w losowych momentach dodawana była pusta linia. Także jeśli borykasz się z problemem magicznych pustych linii przy zapisie do pliku, usuń tę flagę.
Komentarze
Prześlij komentarz