Files
CoreUtils/Log.h
T
Brad ArantandClaude Sonnet 5 05374bdb15 Fix MString::read() infinite retry loop, HTTPRequest parser fd leak, Log deadlock, log rotation symlink handling, and JString bounds checks
- MString::read() now gives up after repeated I/O errors instead of
  looping forever and crashing via realloc() failure (root cause of a
  recurring barant.com production crash).
- HTTPRequest::parse() no longer leaks lineParser/headerParser on a
  malformed request.
- Log gained size-based rotation (config-driven) and a non-static-mutex
  fix; a separate fix stopped rotation from destroying the logs symlink
  on its first trigger.
- File.cpp: symlink-preserving rotation support.
- JString: fixed an array-index out-of-bounds and a setString issue.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-06 17:38:14 +00:00

126 lines
3.4 KiB
C++

#ifndef __Log_h__
#define __Log_h__
#include "File.h"
#include "LogListener.h"
#include <mutex>
#include <string>
#include <sstream>
namespace coreutils {
class ConsoleServer;
static const int LOG_NONE = 0;
static const int LOG_INFO = 1;
static const int LOG_WARN = 2;
static const int LOG_EXCEPT = 4;
static const int LOG_DEBUG_1 = 8;
static const int LOG_DEBUG_2 = 16;
static const int LOG_DEBUG_3 = 32;
static const int LOG_DEBUG_4 = 64;
///
/// Log
///
/// Provides easy to access and use logging features to maintain a
/// history of activity and provide information for activity debugging.
///
class Log : public std::ostringstream {
public:
///
/// Constructor method that accepts a pointer to a log listener
/// This enables the Log object to send new log
/// messages to the connected listener.
///
/// @param consoleServer a pointer to the console server that will
/// be used to echo log entries.
///
Log(LogListener *logListener);
///
/// Constructor method accepts a file object that will be used to
/// echo all log entries. This provides a permanent disk file record
/// of all logged activity.
///
Log(File *logFile);
///
/// Constructor method that is used to send a message to the log.
///
/// @param level the logging level to associate with this message.
///
/// To send log message: Log(LOG_INFO) << "This is a log message.";
///
Log(int level);
///
/// The destructor for the log object.
///
~Log();
bool output = false;
///
/// Set the logListener to point to the instantiated LogListener
/// object for the application.
///
static LogListener *logListener;
///
/// Specify a File object where the log entries will be written as
/// a permanent record to disk.
///
static File *logFile;
///
/// A meaningless sequenctial number that starts from 0 at the
/// beginning of the logging process.
///
static int seq;
///
/// Rotation threshold for the static logFile, in bytes - checked
/// after every write that reaches it. Default 100MB. Change it
/// any time (takes effect on the next log call); 0 disables
/// rotation entirely.
///
static size_t maxLogSize;
///
/// How many rotated-out backups (logFile.1, logFile.2, ...) to
/// keep once maxLogSize is hit - the oldest beyond this count is
/// deleted outright, not just renamed away. Default 5.
///
static int maxLogBackups;
private:
// Static, not per-instance - every Log(level) call constructs
// and destructs its own temporary Log object, so a per-instance
// mutex (the original declaration here) provided no actual
// mutual exclusion between concurrent threads at all, each
// locking a separate mutex of their own. Only became load-bearing
// once rotation was added: two threads racing between "check
// size" and "close/rename/reopen" on the one shared logFile
// could otherwise write to a stale fd mid-rotation or rotate out
// from under an in-flight write.
static std::mutex mtx;
};
}
#endif