Skip to content

add loglevel filter #74

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions camerad/camerad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ int main(int argc, char **argv) {
}

for (int entry=0; entry < server.config.n_entries; entry++) {
if (server.config.param[entry].compare(0, 15, "LOGLEVEL_FILTER")==0) {
set_loglevel_filter(string_to_log_level(server.config.arg[entry]));
message.str(""); message << "CONFIG:" << server.config.param[entry] << "=" << server.config.arg[entry];
logwrite( function, message.str(), LogLevel::INFO );
}

if (server.config.param[entry] == "LOGPATH") log_path = server.config.arg[entry];

Expand Down
30 changes: 28 additions & 2 deletions utils/logentry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ struct LogItem {
boost::lockfree::queue<LogItem*> log_queue(1024);
std::atomic<bool> logger_running{true};
std::thread logger_thread;
std::atomic<LogLevel> global_loglevel = LogLevel::INFO;

/***** logger_worker **********************************************************/
/**
Expand Down Expand Up @@ -59,14 +60,17 @@ void logger_worker() {

if (item->level == LogLevel::ERROR || write_failed) {
std::cerr << *(item->msg);
} else {
std::cout << *(item->msg);
}

delete item->msg;
delete item;
}

if (filestream.is_open())
if (filestream.is_open()) {
filestream.flush();
}

std::this_thread::sleep_for(std::chrono::milliseconds(5)); // slight delay to reduce CPU usage
}
Expand All @@ -89,11 +93,12 @@ void logger_worker() {
* background logger thread that processes queued log messages.
*
*/
long init_log(std::string name, std::string logpath, std::string logstderr, std::string logtmzone)
long init_log(std::string name, std::string logpath, std::string logstderr, std::string logtmzone, LogLevel min_level)
{
const std::string function = "init_log";
std::stringstream filename;
std::stringstream message;
global_loglevel = min_level;
int year, mon, mday, hour, min, sec, usec;
long error = 0;

Expand Down Expand Up @@ -174,6 +179,25 @@ void close_log() {

/***** close_log **************************************************************/

/***** set_loglevel ************************************************************/
/**
* @brief Sets the global log level threshold.
* @param[in] new_level The minimum LogLevel to allow logging.
*
* This function updates the global logging threshold used by `logwrite()`
* to decide whether a message should be queued for logging. Any log message
* with a level higher (less severe) than this threshold will be ignored.
*
* Example usage:
* set_loglevel(LogLevel::WARNING); // Log only WARNING and ERROR
*
* Thread-safe due to use of std::atomic.
*/
void set_loglevel_filter(LogLevel new_level) {
global_loglevel.store(new_level);
}
/***** set_loglevel ************************************************************/

/***** logwrite ***************************************************************/
/**
* @brief Queues a formatted log message with a timestamp and function name.
Expand All @@ -191,6 +215,8 @@ void close_log() {
*
*/
void logwrite(const std::string &function, const std::string &message, LogLevel level) {
if (level > global_loglevel.load()) return; // filter based on global threshold

char buffer[512];
std::string timestamp = get_timestamp(tmzone_log);
const char* level_str = log_level_to_string(level);
Expand Down
44 changes: 29 additions & 15 deletions utils/logentry.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** ---------------------------------------------------------------------------
* @file logentry.h
* @file logentry.h
* @brief include file for logging functions
* @author David Hale <[email protected]>
*
Expand All @@ -13,35 +13,49 @@
#include <chrono>
#include <thread>
#include <ctime>
#include <algorithm>
#include <boost/lockfree/queue.hpp>
#include "utilities.h"

extern unsigned int nextday; /// number of seconds until the next day is a global

enum class LogLevel {
ERROR,
WARNING,
INFO,
DEBUG,
VERBOSE
ERROR,
WARNING,
INFO,
DEBUG,
VERBOSE
};

inline const char* log_level_to_string(LogLevel level) {
switch (level) {
case LogLevel::ERROR: return "ERROR";
case LogLevel::WARNING: return "WARNING";
case LogLevel::INFO: return "INFO";
case LogLevel::DEBUG: return "DEBUG";
case LogLevel::VERBOSE: return "VERBOSE";
default: return "UNKNOWN";
}
switch (level) {
case LogLevel::ERROR: return "ERROR";
case LogLevel::WARNING: return "WARNING";
case LogLevel::INFO: return "INFO";
case LogLevel::DEBUG: return "DEBUG";
case LogLevel::VERBOSE: return "VERBOSE";
default: return "UNKNOWN";
}
}

long init_log(std::string name, std::string logpath, std::string logstderr, std::string logtmzone);
inline LogLevel string_to_log_level(std::string level_str) {
std::transform(level_str.begin(), level_str.end(), level_str.begin(), ::toupper);

if (level_str == "ERROR") return LogLevel::ERROR;
if (level_str == "WARNING") return LogLevel::WARNING;
if (level_str == "INFO") return LogLevel::INFO;
if (level_str == "DEBUG") return LogLevel::DEBUG;
if (level_str == "VERBOSE") return LogLevel::VERBOSE;

return LogLevel::INFO;
}

long init_log(std::string name, std::string logpath, std::string logstderr, std::string logtmzone, LogLevel min_level = LogLevel::INFO);

/// initialize the logging system
void close_log(); /// close the log file stream
void logwrite(const std::string &function, const std::string &message, LogLevel level);
void logwrite(const std::string &function, const std::string &message);
void set_loglevel_filter(LogLevel new_level);

/// create a time-stamped log entry "message" from "function"