RaveOS-Base/releng/airootfs/root/calamares-build/usr/include/libcalamares/utils/Logger.h
2025-03-19 22:24:02 +01:00

404 lines
9.5 KiB
C++

/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2010-2011 Christian Muehlhaeuser <muesli@tomahawk-player.org>
* SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017-2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef UTILS_LOGGER_H
#define UTILS_LOGGER_H
#include "DllMacro.h"
#include <QDebug>
#include <QSharedPointer>
#include <QVariant>
#include <memory>
namespace Logger
{
class Once;
struct FuncSuppressor
{
explicit constexpr FuncSuppressor( const char[] );
const char* m_s;
};
struct NoQuote_t
{
};
struct Quote_t
{
};
DLLEXPORT extern const FuncSuppressor Continuation;
DLLEXPORT extern const FuncSuppressor SubEntry;
DLLEXPORT extern const NoQuote_t NoQuote;
DLLEXPORT extern const Quote_t Quote;
enum
{
LOG_DISABLE = 0,
LOGERROR = 1,
LOGWARNING = 2,
LOGDEBUG = 6,
LOGVERBOSE = 8
};
class DLLEXPORT CDebug : public QDebug
{
public:
explicit CDebug( unsigned int debugLevel = LOGDEBUG, const char* func = nullptr );
virtual ~CDebug();
friend CDebug& operator<<( CDebug&&, const FuncSuppressor& );
friend CDebug& operator<<( CDebug&&, const Once& );
inline unsigned int level() const { return m_debugLevel; }
private:
QString m_msg;
unsigned int m_debugLevel;
const char* m_funcinfo = nullptr;
};
inline CDebug&
operator<<( CDebug&& s, const FuncSuppressor& f )
{
if ( s.m_funcinfo )
{
s.m_funcinfo = nullptr;
s.m_msg = QString( f.m_s );
}
return s;
}
inline QDebug&
operator<<( QDebug& s, const FuncSuppressor& f )
{
return s << f.m_s;
}
inline QDebug&
operator<<( QDebug& s, const NoQuote_t& )
{
return s.noquote().nospace();
}
inline QDebug&
operator<<( QDebug& s, const Quote_t& )
{
return s.quote().space();
}
/**
* @brief The full path of the log file.
*/
DLLEXPORT QString logFile();
/**
* @brief Start logging to the log file.
*
* Call this (once) to start logging to the log file (usually
* ~/.cache/calamares/session.log ). An existing log file is
* rolled over if it is too large.
*/
DLLEXPORT void setupLogfile();
/**
* @brief Set a log level for future logging.
*
* Pass in a value from the LOG* enum, above. Use 0 to
* disable logging. Values greater than LOGVERBOSE are
* limited to LOGVERBOSE, which will log everything.
*
* Practical values are 0, 1, 2, and 6.
*/
DLLEXPORT void setupLogLevel( unsigned int level );
/** @brief Return the configured log-level. */
DLLEXPORT unsigned int logLevel();
/** @brief Would the given @p level really be logged? */
DLLEXPORT bool logLevelEnabled( unsigned int level );
/**
* @brief Row-oriented formatted logging.
*
* Use DebugRow to produce multiple rows of 2-column output
* in a debugging statement. For instance,
* cDebug() << DebugRow<int,int>(1,12)
* << DebugRow<int,int>(2,24)
* will produce a single timestamped debug line with continuations.
* Each DebugRow produces one line of output, with the two values.
*/
template < typename T, typename U >
struct DebugRow
{
public:
explicit DebugRow( const T& t, const U& u )
: first( t )
, second( u )
{
}
const T first;
const U second;
};
/**
* @brief List-oriented formatted logging.
*
* Use DebugList to produce multiple rows of output in a debugging
* statement. For instance,
* cDebug() << DebugList( QStringList() << "foo" << "bar" )
* will produce a single timestamped debug line with continuations.
* Each element of the list of strings will be logged on a separate line.
*/
/* TODO: Calamares 3.3, bump requirements to C++17, and rename
* this to DebugList, dropping the convenience-definition
* below. In C++17, class template argument deduction is
* added, so `DebugList( whatever )` determines the right
* type already (also for QStringList).
*/
template < typename T >
struct DebugListT
{
using list_t = QList< T >;
explicit DebugListT( const list_t& l )
: list( l )
{
}
const list_t& list;
};
///@brief Convenience for QStringList, needs no template parameters
struct DebugList : public DebugListT< QString >
{
explicit DebugList( const list_t& l )
: DebugListT( l )
{
}
};
/**
* @brief Map-oriented formatted logging.
*
* Use DebugMap to produce multiple rows of output in a debugging
* statement from a map. The output is intentionally a bit-yaml-ish.
* cDebug() << DebugMap( map )
* will produce a single timestamped debug line with continuations.
* The continued lines will have a key (from the map) and a value
* on each line.
*/
struct DebugMap
{
public:
explicit DebugMap( const QVariantMap& m )
: map( m )
{
}
const QVariantMap& map;
};
/** @brief When logging commands, don't log everything.
*
* The command-line arguments to some commands may contain the
* encrypted password set by the user. Don't log that password,
* since the log may get posted to bug reports, or stored in
* the target system.
*/
struct RedactedCommand
{
RedactedCommand( const QStringList& l )
: list( l )
{
}
const QStringList& list;
};
DLLEXPORT QDebug& operator<<( QDebug& s, const RedactedCommand& l );
/** @brief When logging "private" identifiers, keep them consistent but private
*
* Send a string to a logger in such a way that each time it is logged,
* it logs the same way, but without revealing the actual contents.
* This can be applied to user names, UUIDs, etc.
*/
struct DLLEXPORT RedactedName
{
RedactedName( const char* context, const QString& s );
RedactedName( const QString& context, const QString& s );
operator QString() const;
private:
const uint m_id;
const QString m_context;
};
inline QDebug&
operator<<( QDebug& s, const RedactedName& n )
{
return s << NoQuote << QString( n ) << Quote;
}
/**
* @brief Formatted logging of a pointer
*
* Pointers are printed as void-pointer, so just an address (unlike, say,
* QObject pointers which show an address and some metadata) preceded
* by an '@'. This avoids C-style (void*) casts in the code.
*
* Shared pointers are indicated by 'S@' and unique pointers by 'U@'.
*/
struct Pointer
{
public:
explicit Pointer( const void* p )
: ptr( p )
, kind( 0 )
{
}
template < typename T >
explicit Pointer( const std::shared_ptr< T >& p )
: ptr( p.get() )
, kind( 'S' )
{
}
template < typename T >
explicit Pointer( const std::unique_ptr< T >& p )
: ptr( p.get() )
, kind( 'U' )
{
}
const void* const ptr;
const char kind;
};
/** @brief output operator for DebugRow */
template < typename T, typename U >
inline QDebug&
operator<<( QDebug& s, const DebugRow< T, U >& t )
{
s << Continuation << t.first << ':' << ' ' << t.second;
return s;
}
/** @brief output operator for DebugList, assuming operator<< for T exists */
template < typename T = QString >
inline QDebug&
operator<<( QDebug& s, const DebugListT< T >& c )
{
for ( const auto& i : c.list )
{
s << Continuation << i;
}
return s;
}
/** @brief supporting method for outputting a DebugMap */
DLLEXPORT QString toString( const QVariant& v );
/** @brief output operator for DebugMap */
inline QDebug&
operator<<( QDebug& s, const DebugMap& t )
{
for ( auto it = t.map.constBegin(); it != t.map.constEnd(); ++it )
{
s << Continuation << it.key().toUtf8().constData() << ':' << ' ' << toString( it.value() ).toUtf8().constData();
}
return s;
}
inline QDebug&
operator<<( QDebug& s, const Pointer& p )
{
s << NoQuote;
if ( p.kind )
{
s << p.kind;
}
s << '@' << p.ptr << Quote;
return s;
}
/** @brief Convenience object for supplying SubEntry to a debug stream
*
* In a function with convoluted control paths, it may be unclear
* when to supply SubEntry to a debug stream -- it is convenient
* for the **first** debug statement from a given function to print
* the function header, and all subsequent onces to get SubEntry.
*
* Create an object of type Once and send it (first) to all CDebug
* objects; this will print the function header only once within the
* lifetime of that Once object.
*/
class Once
{
public:
Once()
: m( true )
{
}
friend CDebug& operator<<( CDebug&&, const Once& );
/** @brief Restore the object to "fresh" state
*
* It may be necessary to allow the Once object to stream the
* function header again -- for instance, after logging an error,
* any following debug log might want to re-introduce the header.
*/
void refresh() { m = true; }
/** @brief Is this object "fresh"?
*
* Once a Once-object has printed (once) it is no longer fresh.
*/
operator bool() const { return m; }
private:
mutable bool m = false;
};
inline CDebug&
operator<<( CDebug&& s, const Once& o )
{
if ( !logLevelEnabled( s.level() ) )
{
// This won't print, so it's not using the "onceness"
return s;
}
if ( o.m )
{
o.m = false;
return s;
}
s.m_funcinfo = nullptr;
s << SubEntry;
return s;
}
} // namespace Logger
#define cVerbose() Logger::CDebug( Logger::LOGVERBOSE, Q_FUNC_INFO )
#define cDebug() Logger::CDebug( Logger::LOGDEBUG, Q_FUNC_INFO )
#define cWarning() Logger::CDebug( Logger::LOGWARNING, Q_FUNC_INFO )
#define cError() Logger::CDebug( Logger::LOGERROR, Q_FUNC_INFO )
#endif