You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

112 lines
4.8 KiB

/*
* Copyright (C) 2002,2003,2009,2011,2012,2019 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* Singleton, thread-safe file logger with daily log rotation.
*
* One CLogger instance is created at startup and registered via setInstance().
* All threads call the static getInstance() accessor or, more commonly, use the
* wxLogXxx macros below. The macros are compatibility shims that preserve the
* original wxWidgets wxLogMessage/wxLogError call sites without pulling in the
* wxWidgets library.
*
* Log levels follow the MMDVMHost convention so that config file values map
* directly to enum values without translation:
*
* Config value 0 — no logging (disabled)
* Config value 1 — LOG_DEBUG (most verbose)
* Config value 2 — LOG_MESSAGE
* Config value 3 — LOG_INFO
* Config value 4 — LOG_WARNING
* Config value 5 — LOG_ERROR
* Config value 6 — LOG_FATAL (least verbose)
*
* Both fileLevel and displayLevel use these values: a message is written to
* the respective sink only when its level >= the configured threshold. Setting
* a threshold to 0 disables that sink entirely; 6 passes only LOG_FATAL.
*
* When built with MQTT=1, log lines are also forwarded to the MQTT broker on
* the "{name}/log" topic via the global g_mqtt connection, filtered by the
* minimum level stored in g_mqttLevel.
*/
#ifndef Logger_H
#define Logger_H
#include <atomic>
#include <string>
#include <cstdio>
#include <mutex>
#if defined(MQTT)
class CMQTTConnection;
extern CMQTTConnection* g_mqtt; // Global MQTT connection (set in main())
extern unsigned int g_mqttLevel; // Minimum LogLevel to forward over MQTT
#endif
// Ordered to match MMDVMHost: enum value == config file level.
// Level 0 ("no logging") has no corresponding enum constant.
enum LogLevel {
LOG_DEBUG = 1,
LOG_MESSAGE = 2,
LOG_INFO = 3,
LOG_WARNING = 4,
LOG_ERROR = 5,
LOG_FATAL = 6
};
class CLogger {
public:
// directory — where daily log files are written; may be empty when fileLevel == 0.
// name — base filename stem (e.g. "dstarrepeaterd").
// fileLevel — minimum LogLevel to write to the log file (0 = disabled).
// displayLevel — minimum LogLevel to write to stdout (0 = disabled).
CLogger(const std::string& directory, const std::string& name,
unsigned int fileLevel = 2U, unsigned int displayLevel = 2U);
~CLogger();
void log(LogLevel level, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
static CLogger* getInstance();
static void setInstance(CLogger* logger);
private:
std::string m_name; // Base filename stem (e.g. "dstarrepeater")
std::string m_directory; // Directory where daily log files are written
FILE* m_file; // Currently open log file handle (nullptr when disabled)
int m_day; // Day-of-year when m_file was opened; triggers rotation
std::mutex m_mutex; // Serialises concurrent log() calls from multiple threads
unsigned int m_fileLevel; // Minimum level to write to file (0 = disabled)
unsigned int m_displayLevel; // Minimum level to write to stdout (0 = disabled)
static std::atomic<CLogger*> s_instance; // The singleton logger
void openFile(const struct tm* tm);
void writeLog(const char* msg, time_t timestamp);
};
// Compatibility macros matching the wxWidgets wxLogXxx API. Existing call
// sites throughout the codebase use these names and can remain unchanged.
#define wxLogFatalError(fmt, ...) do { if (CLogger::getInstance()) CLogger::getInstance()->log(LOG_FATAL, fmt, ##__VA_ARGS__); } while(0)
#define wxLogError(fmt, ...) do { if (CLogger::getInstance()) CLogger::getInstance()->log(LOG_ERROR, fmt, ##__VA_ARGS__); } while(0)
#define wxLogWarning(fmt, ...) do { if (CLogger::getInstance()) CLogger::getInstance()->log(LOG_WARNING, fmt, ##__VA_ARGS__); } while(0)
#define wxLogMessage(fmt, ...) do { if (CLogger::getInstance()) CLogger::getInstance()->log(LOG_MESSAGE, fmt, ##__VA_ARGS__); } while(0)
#define wxLogInfo(fmt, ...) do { if (CLogger::getInstance()) CLogger::getInstance()->log(LOG_INFO, fmt, ##__VA_ARGS__); } while(0)
#endif

Powered by TurnKey Linux.