Skip to content

Commit 0738b7e

Browse files
Merge branch 'dev' into develop
2 parents 929287b + 3af7383 commit 0738b7e

32 files changed

+689
-170
lines changed

.codespellrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[codespell]
2-
skip = *.dat,typos-config.toml,.git,.venv,./ci,./Dist,./mk,./Tests/ExamplesTest/expected_output,./Tests/ExamplesTest/pcap_examples,./Tests/Packet++Test/PacketExamples,./Tests/Pcap++Test/PcapExamples,./3rdParty,./Examples/PcapSearch/dirent-for-Visual-Studio
2+
skip = *.dat,typos-config.toml,.git,.venv,venv,./out,./ci,./Dist,./mk,./Tests/ExamplesTest/expected_output,./Tests/ExamplesTest/pcap_examples,./Tests/Packet++Test/PacketExamples,./Tests/Pcap++Test/PcapExamples,./3rdParty,./Examples/PcapSearch/dirent-for-Visual-Studio
33
ignore-words = codespell-ignore-list.txt
44
count =

Common++/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ set(
2222
header/Logger.h
2323
header/LRUList.h
2424
header/MacAddress.h
25+
header/ObjectPool.h
2526
header/OUILookup.h
2627
header/PcapPlusPlusVersion.h
2728
header/PointerVector.h

Common++/header/IpAddress.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -876,5 +876,4 @@ namespace pcpp
876876
oss << network.toString();
877877
return oss;
878878
}
879-
880879
} // namespace pcpp

Common++/header/Logger.h

Lines changed: 222 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
#pragma once
22

33
#include <cstdio>
4-
#include <iostream>
5-
#include <sstream>
6-
#include <iomanip>
74
#include <cstdint>
5+
#include <memory>
6+
#include <array>
7+
#include <mutex>
8+
#include <ostream>
9+
#include <sstream>
10+
#include "DeprecationUtils.h"
11+
#include "ObjectPool.h"
812

913
#ifndef LOG_MODULE
1014
# define LOG_MODULE UndefinedLogModule
@@ -17,35 +21,29 @@
1721
# define PCAPPP_FILENAME __FILE__
1822
#endif
1923

20-
#define PCPP_LOG(level, message) \
21-
do \
22-
{ \
23-
std::ostringstream* sstream = pcpp::Logger::getInstance().internalCreateLogStream(); \
24-
(*sstream) << message; \
25-
pcpp::Logger::getInstance().internalPrintLogMessage(sstream, level, PCAPPP_FILENAME, __FUNCTION__, __LINE__); \
26-
} while (0)
27-
28-
#define PCPP_LOG_DEBUG(message) \
29-
do \
30-
{ \
31-
if (pcpp::Logger::getInstance().logsEnabled() && pcpp::Logger::getInstance().isDebugEnabled(LOG_MODULE)) \
32-
{ \
33-
PCPP_LOG(pcpp::Logger::Debug, message); \
34-
} \
35-
} while (0)
24+
/// @file
3625

37-
#define PCPP_LOG_ERROR(message) \
38-
do \
39-
{ \
40-
PCPP_LOG(pcpp::Logger::Error, message); \
41-
} while (0)
26+
// Compile time log levels.
27+
// Allows for conditional removal of unwanted log calls at compile time.
28+
#define PCPP_LOG_LEVEL_OFF 0
29+
#define PCPP_LOG_LEVEL_ERROR 1
30+
#define PCPP_LOG_LEVEL_INFO 2
31+
#define PCPP_LOG_LEVEL_DEBUG 3
4232

43-
/// @file
33+
// All log messages built via a PCPP_LOG_* macro below the PCPP_ACTIVE_LOG_LEVEL will be removed at compile time.
34+
// Uses the PCPP_ACTIVE_LOG_LEVEL if it is defined, otherwise defaults to PCAP_LOG_LEVEL_DEBUG
35+
#ifndef PCPP_ACTIVE_LOG_LEVEL
36+
# define PCPP_ACTIVE_LOG_LEVEL PCPP_LOG_LEVEL_DEBUG
37+
#endif // !PCPP_ACTIVE_LOG_LEVEL
4438

4539
/// @namespace pcpp
4640
/// @brief The main namespace for the PcapPlusPlus lib
4741
namespace pcpp
4842
{
43+
/// Cross-platform and thread-safe version of strerror
44+
/// @param errnum Value of errno
45+
/// @return String representation of the error number
46+
std::string getErrorString(int errnum);
4947

5048
/// An enum representing all PcapPlusPlus modules
5149
enum LogModule : uint8_t
@@ -75,6 +73,7 @@ namespace pcpp
7573
PacketLogModuleGreLayer, ///< GreLayer module (Packet++)
7674
PacketLogModuleSSLLayer, ///< SSLLayer module (Packet++)
7775
PacketLogModuleSllLayer, ///< SllLayer module (Packet++)
76+
PacketLogModuleSll2Layer, ///< Sll2Layer module (Packet++)
7877
PacketLogModuleNflogLayer, ///< NflogLayer module (Packet++)
7978
PacketLogModuleDhcpLayer, ///< DhcpLayer module (Packet++)
8079
PacketLogModuleDhcpV6Layer, ///< DhcpV6Layer module (Packet++)
@@ -109,15 +108,100 @@ namespace pcpp
109108
PcapLogModuleDpdkDevice, ///< DpdkDevice module (Pcap++)
110109
PcapLogModuleKniDevice, ///< KniDevice module (Pcap++)
111110
PcapLogModuleXdpDevice, ///< XdpDevice module (Pcap++)
112-
NetworkUtils, ///< NetworkUtils module (Pcap++)
113-
PacketLogModuleDoIpLayer, ///< DoipLayer module (Packet++)
114-
NumOfLogModules,
111+
PcapLogModuleNetworkUtils, ///< Network Utils module (Pcap++)
112+
NumOfLogModules
115113
};
116114

117-
/// Cross-platform and thread-safe version of strerror
118-
/// @param errnum Value of errno
119-
/// @return String representation of the error number
120-
std::string getErrorString(int errnum);
115+
/// @struct LogSource
116+
/// Represents the source of a log message.
117+
/// Contains information about the source file, function, line number, and the log module.
118+
struct LogSource
119+
{
120+
/// Default constructor for LogSource.
121+
constexpr LogSource() = default;
122+
123+
/// Constructor for LogSource with only the log module.
124+
/// @param logModule The log module.
125+
explicit constexpr LogSource(LogModule logModule) : logModule(logModule)
126+
{}
127+
128+
/// Constructor for LogSource with all parameters.
129+
/// @param logModule The log module.
130+
/// @param file The source file.
131+
/// @param function The source function.
132+
/// @param line The line number.
133+
constexpr LogSource(LogModule logModule, const char* file, const char* function, int line)
134+
: file(file), function(function), line(line), logModule(logModule)
135+
{}
136+
137+
const char* file = nullptr; /**< The source file. */
138+
const char* function = nullptr; /**< The source function. */
139+
int line = 0; /**< The line number. */
140+
LogModule logModule = UndefinedLogModule; /**< The log module. */
141+
};
142+
143+
/// An enum representing the log level. Currently 4 log levels are supported: Off, Error, Info and Debug. Info is
144+
/// the default log level
145+
enum class LogLevel
146+
{
147+
Off = PCPP_LOG_LEVEL_OFF, ///< No log messages are emitted.
148+
Error = PCPP_LOG_LEVEL_ERROR, ///< Error level logs are emitted.
149+
Info = PCPP_LOG_LEVEL_INFO, ///< Info level logs and above are emitted.
150+
Debug = PCPP_LOG_LEVEL_DEBUG ///< Debug level logs and above are emitted.
151+
};
152+
153+
inline std::ostream& operator<<(std::ostream& s, LogLevel v)
154+
{
155+
return s << static_cast<std::underlying_type<LogLevel>::type>(v);
156+
}
157+
158+
// Forward declaration
159+
class Logger;
160+
161+
namespace internal
162+
{
163+
/// @class LogContext
164+
/// @brief A context encapsulating the details of a single log message to be passed to the Logger.
165+
class LogContext
166+
{
167+
public:
168+
friend class pcpp::Logger;
169+
170+
/// @brief Creates a context with an empty message with Info level and no source.
171+
LogContext() = default;
172+
173+
/// @brief Creates a context with an empty message with the given level and source.
174+
/// @param level The log level for this message.
175+
/// @param source The log source.
176+
explicit LogContext(LogLevel level, LogSource const& source = {}) : m_Source(source), m_Level(level)
177+
{}
178+
179+
/// @brief Initializes the context with an empty message and the given level and source.
180+
/// @param level The log level for this message.
181+
/// @param source The log source.
182+
void init(LogLevel level, LogSource const& source)
183+
{
184+
m_Source = source;
185+
m_Level = level;
186+
m_Stream.clear();
187+
m_Stream.str({});
188+
}
189+
190+
/// @brief Appends to the message.
191+
/// @param value The value to append.
192+
/// @return A reference to this context.
193+
template <class T> inline LogContext& operator<<(T const& value)
194+
{
195+
m_Stream << value;
196+
return *this;
197+
}
198+
199+
private:
200+
std::ostringstream m_Stream;
201+
LogSource m_Source;
202+
LogLevel m_Level = LogLevel::Info;
203+
};
204+
} // namespace internal
121205

122206
/// @class Logger
123207
/// PcapPlusPlus logger manager.
@@ -139,14 +223,14 @@ namespace pcpp
139223
class Logger
140224
{
141225
public:
142-
/// An enum representing the log level. Currently 3 log levels are supported: Error, Info and Debug. Info is the
143-
/// default log level
144-
enum LogLevel : uint8_t
145-
{
146-
Error, ///< Error log level
147-
Info, ///< Info log level
148-
Debug ///< Debug log level
149-
};
226+
// Deprecated, Use the LogLevel in the pcpp namespace instead.
227+
using LogLevel = pcpp::LogLevel;
228+
PCPP_DEPRECATED("Use the LogLevel in the pcpp namespace instead.")
229+
static const LogLevel Error = LogLevel::Error;
230+
PCPP_DEPRECATED("Use the LogLevel in the pcpp namespace instead.")
231+
static const LogLevel Info = LogLevel::Info;
232+
PCPP_DEPRECATED("Use the LogLevel in the pcpp namespace instead.")
233+
static const LogLevel Debug = LogLevel::Debug;
150234

151235
/// @typedef LogPrinter
152236
/// Log printer callback. Used for printing the logs in a custom way.
@@ -155,7 +239,10 @@ namespace pcpp
155239
/// @param[in] file The source file in PcapPlusPlus code the log message is coming from
156240
/// @param[in] method The method in PcapPlusPlus code the log message is coming from
157241
/// @param[in] line The line in PcapPlusPlus code the log message is coming from
158-
using LogPrinter = void (*)(LogLevel, const std::string&, const std::string&, const std::string&, const int);
242+
/// @remarks The printer callback should support being called from multiple threads simultaneously.
243+
using LogPrinter =
244+
std::add_pointer<void(LogLevel logLevel, const std::string& logMessage, const std::string& file,
245+
const std::string& method, const int line)>::type;
159246

160247
/// A static method for converting the log level enum to a string.
161248
/// @param[in] logLevel A log level enum
@@ -183,7 +270,16 @@ namespace pcpp
183270
/// @return True if this module log level is "debug". False otherwise
184271
bool isDebugEnabled(LogModule module) const
185272
{
186-
return m_LogModulesArray[module] == Debug;
273+
return m_LogModulesArray[module] == LogLevel::Debug;
274+
}
275+
276+
/// @brief Check whether a log level should be emitted by the logger.
277+
/// @param level The level of the log message.
278+
/// @param module PcapPlusPlus module
279+
/// @return True if the message should be emitted. False otherwise.
280+
bool shouldLog(LogLevel level, LogModule module) const
281+
{
282+
return level != LogLevel::Off && m_LogModulesArray[module] >= level;
187283
}
188284

189285
/// Set all PcapPlusPlus modules to a certain log level
@@ -210,8 +306,9 @@ namespace pcpp
210306
}
211307

212308
/// @return Get the last error message
213-
std::string getLastError()
309+
std::string getLastError() const
214310
{
311+
std::lock_guard<std::mutex> lock(m_LastErrorMtx);
215312
return m_LastError;
216313
}
217314

@@ -234,17 +331,32 @@ namespace pcpp
234331
return m_LogsEnabled;
235332
}
236333

237-
template <class T> Logger& operator<<(const T& msg)
334+
/// @brief Controls if the logger should use a pool of LogContext objects.
335+
///
336+
/// If enabled is set to false, preallocate and maxPoolSize are ignored.
337+
/// @param enabled True to enable context pooling, false to disable.
338+
/// @param preallocate The number of LogContext objects to preallocate in the pool.
339+
/// @param maxPoolSize The maximum number of LogContext objects to keep in the pool.
340+
/// @remarks Disabling the pooling clears the pool.
341+
void useContextPooling(bool enabled, std::size_t preallocate = 2, std::size_t maxPoolSize = 10)
238342
{
239-
(*m_LogStream) << msg;
240-
return *this;
241-
}
343+
m_UseContextPooling = enabled;
242344

243-
static std::ostringstream* internalCreateLogStream();
345+
if (m_UseContextPooling)
346+
{
347+
m_LogContextPool.setMaxSize(maxPoolSize);
244348

245-
/// An internal method to print log messages. Shouldn't be used externally.
246-
void internalPrintLogMessage(std::ostringstream* logStream, Logger::LogLevel logLevel, const char* file,
247-
const char* method, int line);
349+
if (preallocate > 0)
350+
{
351+
m_LogContextPool.preallocate(preallocate);
352+
}
353+
}
354+
else
355+
{
356+
// Clear the pool if we're disabling pooling.
357+
m_LogContextPool.clear();
358+
}
359+
}
248360

249361
/// Get access to Logger singleton
250362
/// @todo: make this singleton thread-safe/
@@ -255,17 +367,74 @@ namespace pcpp
255367
return instance;
256368
}
257369

370+
/// @brief Creates a new LogContext with Info level and no source.
371+
/// @return A new LogContext.
372+
std::unique_ptr<internal::LogContext> createLogContext();
373+
374+
/// @brief Creates a new LogContext with the given level and source.
375+
/// @param level The log level for this message.
376+
/// @param source The log source.
377+
/// @return A new LogContext.
378+
std::unique_ptr<internal::LogContext> createLogContext(LogLevel level, LogSource const& source = {});
379+
380+
/// @brief Directly emits a log message bypassing all level checks.
381+
/// @param source The log source.
382+
/// @param level The log level for this message. This is only used for the log printer.
383+
/// @param message The log message.
384+
void emit(LogSource const& source, LogLevel level, std::string const& message);
385+
386+
/// @brief Directly emits a log message bypassing all level checks.
387+
/// @param message The log message.
388+
void emit(std::unique_ptr<internal::LogContext> message);
389+
258390
private:
259391
bool m_LogsEnabled;
260-
Logger::LogLevel m_LogModulesArray[NumOfLogModules]{};
392+
std::array<LogLevel, NumOfLogModules> m_LogModulesArray;
261393
LogPrinter m_LogPrinter;
394+
395+
mutable std::mutex m_LastErrorMtx;
262396
std::string m_LastError;
263-
std::ostringstream* m_LogStream{};
397+
398+
bool m_UseContextPooling = true;
399+
// Keep a maximum of 10 LogContext objects in the pool.
400+
internal::DynamicObjectPool<internal::LogContext> m_LogContextPool{ 10, 2 };
264401

265402
// private c'tor - this class is a singleton
266403
Logger();
267404

268405
static void defaultLogPrinter(LogLevel logLevel, const std::string& logMessage, const std::string& file,
269406
const std::string& method, int line);
270407
};
408+
271409
} // namespace pcpp
410+
411+
#define PCPP_LOG(level, message) \
412+
do \
413+
{ \
414+
auto& logger = pcpp::Logger::getInstance(); \
415+
if (logger.shouldLog(level, LOG_MODULE)) \
416+
{ \
417+
auto ctx = \
418+
logger.createLogContext(level, pcpp::LogSource(LOG_MODULE, PCAPPP_FILENAME, __FUNCTION__, __LINE__)); \
419+
(*ctx) << message; \
420+
logger.emit(std::move(ctx)); \
421+
} \
422+
} while (0)
423+
424+
#if PCPP_ACTIVE_LOG_LEVEL >= PCPP_LOG_LEVEL_DEBUG
425+
# define PCPP_LOG_DEBUG(message) PCPP_LOG(pcpp::LogLevel::Debug, message)
426+
#else
427+
# define PCPP_LOG_DEBUG(message) (void)0
428+
#endif
429+
430+
#if PCPP_ACTIVE_LOG_LEVEL >= PCPP_LOG_LEVEL_INFO
431+
# define PCPP_LOG_INFO(message) PCPP_LOG(pcpp::LogLevel::Info, message)
432+
#else
433+
# define PCPP_LOG_INFO(message) (void)0
434+
#endif
435+
436+
#if PCPP_ACTIVE_LOG_LEVEL >= PCPP_LOG_LEVEL_ERROR
437+
# define PCPP_LOG_ERROR(message) PCPP_LOG(pcpp::LogLevel::Error, message)
438+
#else
439+
# define PCPP_LOG_ERROR(message) (void)0
440+
#endif

0 commit comments

Comments
 (0)