view Utils/LogFile.cpp @ 1:0b3630a29ad8

Initial version based on previous repository. Project was ported to QT6 and in now cmake based.
author Ideenmodellierer <tiefenrauscher@web.de>
date Thu, 27 Nov 2025 18:40:28 +0100
parents
children
line wrap: on
line source

//////////////////////////////////////////////////////////////////////////////
/// \file   LogFile.cpp
/// \brief  Put Log message into a log file.
/// \author JD Gascuel.
/// \copyright (c) 2011-2016 JD Gascuel. All rights reserved.
/// $Id$
//////////////////////////////////////////////////////////////////////////////
//
// BSD 2-Clause License:
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////

#include "Utils/LogFile.h"

#include <QCoreApplication>
#include <QDir>
#include <QMutex>
#include <QSettings>
#include <QRegularExpression>

#ifndef WIN32
#   include <sys/stat.h>            // umask
#else
#   include <io.h>                  // umask
#endif

static QMutex mutex;

//////////////////////////////////////////////////////////////////////////////

LogFile::LogFile(int argc, char *argv[])
  : LogAppender(argc, argv),
    _holdFiles(5),
    _fileNameFormat("%a-%n.txt"),
    _logFile(NULL)
{
    setMinLevel(defaultMinLevel());
    for(int i=1; i<argc; ++i)
    {
        if( strcmp("-dd", argv[i]) == 0 )
            setMinLevel(Log::LEVEL_DEBUG);
        else if( strcmp("-d", argv[i]) == 0 )
            setMinLevel(Log::LEVEL_TRACE);
    }
}

LogFile::~LogFile()
{
    if( _logFile )
        fclose(_logFile);
    _logFile = NULL;
}

const char *LogFile::type() const
{
    return "File";
}

Log::Level LogFile::defaultMinLevel() const
{
    return Log::LEVEL_TRACE;
}


const char* LogFile::defaultFormat() const
{
    return "[%d %t] %o %F:%l: %m";
}

//////////////////////////////////////////////////////////////////////////////

QString LogFile::filePath(bool pattern) const
{
    QString path =
#ifdef Q_OS_MAC
        QString("/tmp")
#else
        QDir::tempPath()
#endif
        + "/"
        + _fileNameFormat;
    path.replace("%n", pattern ? "*" : "001")
        .replace("%a", Log::applicationName());
    return path;
}

//////////////////////////////////////////////////////////////////////////////

void LogFile::cleanup()
{
    QString name = filePath(true);
    QDir dir(name.section('/', 0, -2));
    name = name.section('/', -1);

    // ---- Make sure the directory exists, and is writable by everyone.
    int oldUMask = umask(0);
    if( ! dir.exists() )
        QDir::current().mkdir( dir.absolutePath() );

    // ---- Then perform the cleanup, if necessary
    QFileInfoList list = dir.entryInfoList(QStringList(name), QDir::Files, QDir::Name | QDir::Reversed);
   // QRegExp parse(name.replace("*", "([0-9]+)"));
    QRegularExpression parse(name.replace("*", "([0-9]+)"));

    for(int i=0; i<list.count(); ++i)
    {
        QString log = list[i].fileName();
#if 0
        if( parse.exactMatch(log) )
        {
            int num = parse.cap(1).toInt();
            if( num >= _holdFiles )
                dir.remove(log);
            else
            {
                QString newName = _fileNameFormat;
                newName.replace("%n", QString().sprintf("%03d", num+1))
                       .replace("%a", Log::applicationName());
                dir.rename(log, newName);
            }
        }
#endif
        QRegularExpressionMatch match = parse.match(log); // match erzeugen
        if (match.hasMatch())                             // entspricht exactMatch
        {
            int num = match.captured(1).toInt();          // entspricht cap(1)

            if (num >= _holdFiles)
                dir.remove(log);
            else
            {
                QString newName = _fileNameFormat;
  //              newName.replace("%n", QString().sprintf("%03d", num+1))
  //                  .replace("%a", Log::applicationName());
                QString number = QString::number(num + 1).rightJustified(3, '0');
                newName.replace("%n", number)
                    .replace("%a", Log::applicationName());
                dir.rename(log, newName);
            }
        }
    }

    umask(oldUMask);
}

//////////////////////////////////////////////////////////////////////////////

void LogFile::operator()(const Log &log)
{
    // stdio FILE is not reentrant. So a lock here is mandatory.
    QMutexLocker locker(&mutex);

    //---- Open the current log file -----------------------------------------
    if( ! _logFile )
    {
        //---- Clean old log files
        cleanup();
        //---- Then open the new one.
        QString name = filePath();
        _logFile = fopen(name.toLocal8Bit().constData(), "at+");
    }

    //---- Output log line ---------------------------------------------------
    if( _logFile )  // File open succeded ?
    {
        QString line = format(log);
        fprintf(_logFile, "%s\n", line.toUtf8().constData());
        fflush(_logFile);
    }
}