-
Notifications
You must be signed in to change notification settings - Fork 682
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
Overhaul of the Logging Infrastructure #1596
base: dev
Are you sure you want to change the base?
Changes from 12 commits
0293115
45115e3
dfb98c5
9062c48
1e856f0
02618fc
32ff8f9
12492d2
f21f85d
0faf2e8
ae72e81
43d7b1c
87042f5
be95ab8
4b21a99
00034e9
b2055c0
cfc3d56
ac2a383
3776653
76079a7
52b9007
c71dd27
803c98a
9d44f76
af63a9b
02e717a
3410231
379c074
bc82caf
69aa615
17ec9a2
2029b4b
c09a11a
f1b7cd6
6b8c104
e972e67
85ae097
a1e7d56
445197b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
#include <sstream> | ||
#include <iomanip> | ||
#include <stdint.h> | ||
#include "DeprecationUtils.h" | ||
|
||
#ifndef LOG_MODULE | ||
# define LOG_MODULE UndefinedLogModule | ||
|
@@ -17,29 +18,6 @@ | |
# define PCAPPP_FILENAME __FILE__ | ||
#endif | ||
|
||
#define PCPP_LOG(level, message) \ | ||
do \ | ||
{ \ | ||
std::ostringstream* sstream = pcpp::Logger::getInstance().internalCreateLogStream(); \ | ||
(*sstream) << message; \ | ||
pcpp::Logger::getInstance().internalPrintLogMessage(sstream, level, PCAPPP_FILENAME, __FUNCTION__, __LINE__); \ | ||
} while (0) | ||
|
||
#define PCPP_LOG_DEBUG(message) \ | ||
do \ | ||
{ \ | ||
if (pcpp::Logger::getInstance().logsEnabled() && pcpp::Logger::getInstance().isDebugEnabled(LOG_MODULE)) \ | ||
{ \ | ||
PCPP_LOG(pcpp::Logger::Debug, message); \ | ||
} \ | ||
} while (0) | ||
|
||
#define PCPP_LOG_ERROR(message) \ | ||
do \ | ||
{ \ | ||
PCPP_LOG(pcpp::Logger::Error, message); \ | ||
} while (0) | ||
|
||
/// @file | ||
|
||
/** | ||
|
@@ -79,6 +57,7 @@ namespace pcpp | |
PacketLogModuleGreLayer, ///< GreLayer module (Packet++) | ||
PacketLogModuleSSLLayer, ///< SSLLayer module (Packet++) | ||
PacketLogModuleSllLayer, ///< SllLayer module (Packet++) | ||
PacketLogModuleSll2Layer, ///< Sll2Layer module (Packet++) | ||
PacketLogModuleNflogLayer, ///< NflogLayer module (Packet++) | ||
PacketLogModuleDhcpLayer, ///< DhcpLayer module (Packet++) | ||
PacketLogModuleDhcpV6Layer, ///< DhcpV6Layer module (Packet++) | ||
|
@@ -113,10 +92,68 @@ namespace pcpp | |
PcapLogModuleDpdkDevice, ///< DpdkDevice module (Pcap++) | ||
PcapLogModuleKniDevice, ///< KniDevice module (Pcap++) | ||
PcapLogModuleXdpDevice, ///< XdpDevice module (Pcap++) | ||
NetworkUtils, ///< NetworkUtils module (Pcap++) | ||
PcapLogModuleNetworkUtils, ///< Network Utils module (Pcap++) | ||
NumOfLogModules | ||
}; | ||
|
||
/** | ||
* @struct LogSource | ||
* Represents the source of a log message. | ||
* Contains information about the source file, function, line number, and the log module. | ||
*/ | ||
struct LogSource | ||
{ | ||
/** | ||
* Default constructor for LogSource. | ||
*/ | ||
constexpr LogSource() = default; | ||
|
||
/** | ||
* Constructor for LogSource with only the log module. | ||
* @param logModule The log module. | ||
*/ | ||
explicit constexpr LogSource(LogModule logModule) : logModule(logModule) | ||
{} | ||
|
||
/** | ||
* Constructor for LogSource with all parameters. | ||
* @param logModule The log module. | ||
* @param file The source file. | ||
* @param function The source function. | ||
* @param line The line number. | ||
*/ | ||
constexpr LogSource(LogModule logModule, const char* file, const char* function, int line) | ||
: file(file), function(function), line(line), logModule(logModule) | ||
{} | ||
|
||
const char* file = nullptr; /**< The source file. */ | ||
const char* function = nullptr; /**< The source function. */ | ||
int line = 0; /**< The line number. */ | ||
LogModule logModule = UndefinedLogModule; /**< The log module. */ | ||
}; | ||
|
||
/** | ||
* An enum representing the log level. Currently 3 log levels are supported: Error, Info and Debug. Info is the | ||
* default log level | ||
*/ | ||
enum class LogLevel | ||
{ | ||
Off, ///< No log messages are emitted. | ||
Error, ///< Error level logs are emitted. | ||
Info, ///< Info level logs and above are emitted. | ||
Debug ///< Debug level logs and above are emitted. | ||
}; | ||
|
||
inline std::ostream& operator<<(std::ostream& s, LogLevel v) | ||
{ | ||
return s << static_cast<std::underlying_type<LogLevel>::type>(v); | ||
} | ||
|
||
// Forward declaration | ||
template <class T> void log(LogSource source, LogLevel level, T const& message); | ||
template <> void log(LogSource source, LogLevel level, std::string const& message); | ||
template <> void log(LogSource source, LogLevel level, const char* const& message); | ||
|
||
/** | ||
* @class Logger | ||
* PcapPlusPlus logger manager. | ||
|
@@ -139,16 +176,14 @@ namespace pcpp | |
class Logger | ||
{ | ||
public: | ||
/** | ||
* An enum representing the log level. Currently 3 log levels are supported: Error, Info and Debug. Info is the | ||
* default log level | ||
*/ | ||
enum LogLevel | ||
{ | ||
Error, ///< Error log level | ||
Info, ///< Info log level | ||
Debug ///< Debug log level | ||
}; | ||
// Deprecated, Use the LogLevel in the pcpp namespace instead. | ||
using LogLevel = pcpp::LogLevel; | ||
PCPP_DEPRECATED("Use the LogLevel in the pcpp namespace instead.") | ||
static const LogLevel Error = LogLevel::Error; | ||
PCPP_DEPRECATED("Use the LogLevel in the pcpp namespace instead.") | ||
static const LogLevel Info = LogLevel::Info; | ||
PCPP_DEPRECATED("Use the LogLevel in the pcpp namespace instead.") | ||
static const LogLevel Debug = LogLevel::Debug; | ||
|
||
/** | ||
* @typedef LogPrinter | ||
|
@@ -196,7 +231,18 @@ namespace pcpp | |
*/ | ||
bool isDebugEnabled(LogModule module) const | ||
{ | ||
return m_LogModulesArray[module] == Debug; | ||
return m_LogModulesArray[module] == LogLevel::Debug; | ||
} | ||
|
||
/** | ||
* @brief Check whether a log level should be emitted by the logger. | ||
* @param level The level of the log message. | ||
* @param module PcapPlusPlus module | ||
* @return True if the message should be emitted. False otherwise. | ||
*/ | ||
bool shouldLog(LogLevel level, LogModule module) const | ||
{ | ||
return level != LogLevel::Off && m_LogModulesArray[module] >= level; | ||
} | ||
|
||
/** | ||
|
@@ -259,20 +305,6 @@ namespace pcpp | |
return m_LogsEnabled; | ||
} | ||
|
||
template <class T> Logger& operator<<(const T& msg) | ||
{ | ||
(*m_LogStream) << msg; | ||
return *this; | ||
} | ||
|
||
std::ostringstream* internalCreateLogStream(); | ||
|
||
/** | ||
* An internal method to print log messages. Shouldn't be used externally. | ||
*/ | ||
void internalPrintLogMessage(std::ostringstream* logStream, Logger::LogLevel logLevel, const char* file, | ||
const char* method, int line); | ||
|
||
/** | ||
* Get access to Logger singleton | ||
* @todo: make this singleton thread-safe/ | ||
|
@@ -284,17 +316,82 @@ namespace pcpp | |
return instance; | ||
} | ||
|
||
template <class T> friend void pcpp::log(LogSource source, LogLevel level, T const& message); | ||
|
||
private: | ||
bool m_LogsEnabled; | ||
Logger::LogLevel m_LogModulesArray[NumOfLogModules]; | ||
LogLevel m_LogModulesArray[NumOfLogModules]; | ||
LogPrinter m_LogPrinter; | ||
std::string m_LastError; | ||
std::ostringstream* m_LogStream; | ||
|
||
// private c'tor - this class is a singleton | ||
Logger(); | ||
|
||
void printLogMessage(LogSource source, LogLevel logLevel, std::string const& message); | ||
static void defaultLogPrinter(LogLevel logLevel, const std::string& logMessage, const std::string& file, | ||
const std::string& method, const int line); | ||
}; | ||
|
||
template <class T> inline void log(LogSource source, LogLevel level, T const& message) | ||
{ | ||
auto& logger = Logger::getInstance(); | ||
if (logger.shouldLog(level, source.logModule)) | ||
{ | ||
std::ostringstream sstream; | ||
sstream << message; | ||
logger.printLogMessage(source, level, sstream.str()); | ||
} | ||
}; | ||
|
||
// Specialization for string to skip the stringstream | ||
template <> inline void log(LogSource source, LogLevel level, std::string const& message) | ||
{ | ||
auto& logger = Logger::getInstance(); | ||
if (logger.shouldLog(level, source.logModule)) | ||
{ | ||
logger.printLogMessage(source, level, message); | ||
} | ||
}; | ||
|
||
// Specialization for const char* to skip the stringstream | ||
template <> inline void log(LogSource source, LogLevel level, const char* const& message) | ||
{ | ||
auto& logger = Logger::getInstance(); | ||
if (logger.shouldLog(level, source.logModule)) | ||
{ | ||
logger.printLogMessage(source, level, message); | ||
} | ||
}; | ||
|
||
template <class T> inline void logError(LogSource source, T const& message) | ||
{ | ||
log(source, LogLevel::Error, message); | ||
}; | ||
|
||
template <class T> inline void logInfo(LogSource source, T const& message) | ||
{ | ||
log(source, LogLevel::Info, message); | ||
}; | ||
|
||
template <class T> inline void logDebug(LogSource source, T const& message) | ||
{ | ||
log(source, LogLevel::Debug, message); | ||
}; | ||
} // namespace pcpp | ||
|
||
#define PCPP_LOG(level, message) \ | ||
do \ | ||
{ \ | ||
if (pcpp::Logger::getInstance().shouldLog(level, LOG_MODULE)) \ | ||
{ \ | ||
std::ostringstream sstream; \ | ||
sstream << message; \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please check if this change affects the PcapPlusPlus binary sizes? I made a change in this PR a couple of years ago to significantly reduce the binary sizes: #748 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a breakdown on the install directory for the x64 release w/npcap. Folder1 is the new size. Folder2 is the old size.
Full breakdown: npcap-x64-release.txt There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you test it with MSVC or MinGW? Also, did you have a chance to test on Linux also? I don't remember in which platform the impact was the highest, but I think it was Linux 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Msvc, I dont think I have mingw setup. I should be able to test the sizes on Unix via WSL. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Dimi1010 I see you're still working on it. Please let me know when the changes are done and when you want me to review the PR again. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @seladb Ok, ended up keeping the optimization. As bc82caf: Release builds ended up being:
|
||
pcpp::log(pcpp::LogSource(LOG_MODULE, PCAPPP_FILENAME, __FUNCTION__, __LINE__), level, sstream.str()); \ | ||
} \ | ||
} while (0) | ||
|
||
#define PCPP_LOG_DEBUG(message) PCPP_LOG(pcpp::LogLevel::Debug, message) | ||
|
||
#define PCPP_LOG_INFO(message) PCPP_LOG(pcpp::LogLevel::Info, message) | ||
|
||
#define PCPP_LOG_ERROR(message) PCPP_LOG(pcpp::LogLevel::Error, message) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@seladb Do we absolutely need to store the last error? Because the way it works, if the logger is made to be used by more than one thread the value is completely useless as it can be changed at any time by any thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, however we currently expose the
getLastError()
method which might be used by some users so we can't just remove it...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so we are left with the options:
getLastError
method as it eould be a different thread.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can leave the current functionality for now. It's not perfect but probably good enough and no one complained so far 🙂