File indexing completed on 2025-07-11 08:51:34
0001
0002
0003
0004
0005 #pragma once
0006
0007 #include <iostream>
0008 #include <sstream>
0009 #include <chrono>
0010 #include <iomanip>
0011 #include <time.h>
0012 #include <atomic>
0013 #include <fstream>
0014
0015 #ifndef JANA2_USE_LOGGER_MUTEX
0016 #define JANA2_USE_LOGGER_MUTEX 0
0017 #endif
0018 #if JANA2_USE_LOGGER_MUTEX
0019 #include <mutex>
0020 #endif
0021
0022
0023 struct JLogger {
0024 static thread_local int thread_id;
0025 static std::atomic_int next_thread_id;
0026
0027 enum class Level { TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF };
0028 Level level;
0029 std::ostream *destination;
0030 std::string group;
0031 bool show_level = true;
0032 bool show_group = false;
0033 bool show_timestamp = true;
0034 bool show_threadstamp = false;
0035
0036 explicit JLogger(JLogger::Level level = JLogger::Level::INFO,
0037 std::ostream* destination = &std::cout,
0038 std::string group = "")
0039 : level(level), destination(destination), group(std::move(group)) {};
0040
0041 JLogger(const JLogger&) = default;
0042 JLogger& operator=(const JLogger&) = default;
0043
0044 void SetGroup(std::string group) {this->group = group; }
0045 void ShowGroup(bool show) {show_group = show; }
0046 void ShowLevel(bool show) {show_level = show; }
0047 void ShowTimestamp(bool show) {show_timestamp = show; }
0048 void ShowThreadstamp(bool show) {show_threadstamp = show; }
0049 };
0050
0051
0052
0053 inline std::ostream& operator<<(std::ostream& s, JLogger::Level l) {
0054 switch (l) {
0055 case JLogger::Level::TRACE: return s << "trace";
0056 case JLogger::Level::DEBUG: return s << "debug";
0057 case JLogger::Level::INFO: return s << "info";
0058 case JLogger::Level::WARN: return s << "warn";
0059 case JLogger::Level::ERROR: return s << "error";
0060 case JLogger::Level::FATAL: return s << "fatal";
0061 default: return s << "off";
0062 }
0063 }
0064
0065
0066 class JLogMessage : public std::stringstream {
0067 private:
0068 std::string m_prefix;
0069 std::ostream* m_destination;
0070
0071 public:
0072 JLogMessage(const std::string& prefix="") : m_prefix(prefix), m_destination(&std::cout){
0073 }
0074
0075 JLogMessage(JLogMessage&& moved_from) : std::stringstream(std::move(moved_from)) {
0076 m_prefix = moved_from.m_prefix;
0077 m_destination = moved_from.m_destination;
0078 }
0079
0080 JLogMessage(const JLogger& logger, JLogger::Level level) {
0081 m_destination = logger.destination;
0082 std::ostringstream builder;
0083 if (logger.show_timestamp) {
0084 auto now = std::chrono::system_clock::now();
0085 std::time_t current_time = std::chrono::system_clock::to_time_t(now);
0086 tm tm_buf;
0087 localtime_r(¤t_time, &tm_buf);
0088
0089
0090 auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
0091 builder << std::put_time(&tm_buf, "%H:%M:%S.");
0092 builder << std::setfill('0') << std::setw(3) << milliseconds.count() << std::setfill(' ') << " ";
0093 }
0094 if (logger.show_threadstamp) {
0095 if (logger.thread_id == -1) {
0096 logger.thread_id = logger.next_thread_id;
0097 logger.next_thread_id += 1;
0098 }
0099 builder << "#" << std::setw(3) << std::setfill('0') << logger.thread_id << " ";
0100 }
0101 if (logger.show_level) {
0102 switch (level) {
0103 case JLogger::Level::TRACE: builder << "[trace] "; break;
0104 case JLogger::Level::DEBUG: builder << "[debug] "; break;
0105 case JLogger::Level::INFO: builder << " [info] "; break;
0106 case JLogger::Level::WARN: builder << " [warn] "; break;
0107 case JLogger::Level::ERROR: builder << "[error] "; break;
0108 case JLogger::Level::FATAL: builder << "[fatal] "; break;
0109 default: builder << "[?????] ";
0110 }
0111 }
0112 if (logger.show_group && !logger.group.empty()) {
0113 builder << logger.group << " > ";
0114 }
0115 m_prefix = builder.str();
0116 }
0117
0118 virtual ~JLogMessage() {
0119 #if JANA2_USE_LOGGER_MUTEX
0120 static std::mutex cout_mutex;
0121 std::lock_guard<std::mutex> lock(cout_mutex);
0122 #endif
0123 std::string line;
0124 std::ostringstream oss;
0125 while (std::getline(*this, line)) {
0126 oss << m_prefix << line << std::endl;
0127 }
0128 *m_destination << oss.str();
0129 m_destination->flush();
0130 }
0131 };
0132
0133
0134 template <typename T>
0135 JLogMessage operator<<(const JLogger& logger, T&& t) {
0136 JLogMessage message(logger, logger.level);
0137 message << t;
0138 return message;
0139 }
0140
0141 inline JLogMessage operator<<(const JLogger& logger, std::ostream& (*manip)(std::ostream&)) {
0142 JLogMessage message(logger, logger.level);
0143 message << manip;
0144 return message;
0145 }
0146
0147
0148
0149
0150 #define LOG JLogMessage()
0151
0152 #define LOG_IF(predicate) if (predicate) JLogMessage()
0153
0154 #define LOG_END std::endl
0155
0156 #define LOG_AT_LEVEL(logger, msglevel) if ((logger).level <= msglevel) JLogMessage((logger), msglevel)
0157
0158 #define LOG_FATAL(logger) LOG_AT_LEVEL(logger, JLogger::Level::FATAL)
0159 #define LOG_ERROR(logger) LOG_AT_LEVEL(logger, JLogger::Level::ERROR)
0160 #define LOG_WARN(logger) LOG_AT_LEVEL(logger, JLogger::Level::WARN)
0161 #define LOG_INFO(logger) LOG_AT_LEVEL(logger, JLogger::Level::INFO)
0162 #define LOG_DEBUG(logger) LOG_AT_LEVEL(logger, JLogger::Level::DEBUG)
0163 #define LOG_TRACE(logger) LOG_AT_LEVEL(logger, JLogger::Level::TRACE)
0164
0165
0166
0167
0168 extern JLogger jout;
0169 extern JLogger jerr;
0170 #define jendl std::endl
0171 #define default_cout_logger jout
0172 #define default_cerr_logger jerr
0173 #ifndef _DBG_
0174 #define _DBG_ jerr<<__FILE__<<":"<<__LINE__<<" "
0175 #endif
0176 #ifndef _DBG__
0177 #define _DBG__ jerr<<__FILE__<<":"<<__LINE__<<std::endl
0178 #endif
0179