1
1
#pragma once
2
2
3
3
#include < cstdio>
4
- #include < iostream>
5
- #include < sstream>
6
- #include < iomanip>
7
4
#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"
8
12
9
13
#ifndef LOG_MODULE
10
14
# define LOG_MODULE UndefinedLogModule
17
21
# define PCAPPP_FILENAME __FILE__
18
22
#endif
19
23
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
36
25
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
42
32
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
44
38
45
39
// / @namespace pcpp
46
40
// / @brief The main namespace for the PcapPlusPlus lib
47
41
namespace pcpp
48
42
{
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);
49
47
50
48
// / An enum representing all PcapPlusPlus modules
51
49
enum LogModule : uint8_t
@@ -75,6 +73,7 @@ namespace pcpp
75
73
PacketLogModuleGreLayer, // /< GreLayer module (Packet++)
76
74
PacketLogModuleSSLLayer, // /< SSLLayer module (Packet++)
77
75
PacketLogModuleSllLayer, // /< SllLayer module (Packet++)
76
+ PacketLogModuleSll2Layer, // /< Sll2Layer module (Packet++)
78
77
PacketLogModuleNflogLayer, // /< NflogLayer module (Packet++)
79
78
PacketLogModuleDhcpLayer, // /< DhcpLayer module (Packet++)
80
79
PacketLogModuleDhcpV6Layer, // /< DhcpV6Layer module (Packet++)
@@ -109,15 +108,100 @@ namespace pcpp
109
108
PcapLogModuleDpdkDevice, // /< DpdkDevice module (Pcap++)
110
109
PcapLogModuleKniDevice, // /< KniDevice module (Pcap++)
111
110
PcapLogModuleXdpDevice, // /< XdpDevice module (Pcap++)
112
- NetworkUtils, // /< NetworkUtils module (Pcap++)
113
- PacketLogModuleDoIpLayer, // /< DoipLayer module (Packet++)
114
- NumOfLogModules,
111
+ PcapLogModuleNetworkUtils, // /< Network Utils module (Pcap++)
112
+ NumOfLogModules
115
113
};
116
114
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
121
205
122
206
// / @class Logger
123
207
// / PcapPlusPlus logger manager.
@@ -139,14 +223,14 @@ namespace pcpp
139
223
class Logger
140
224
{
141
225
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 ;
150
234
151
235
// / @typedef LogPrinter
152
236
// / Log printer callback. Used for printing the logs in a custom way.
@@ -155,7 +239,10 @@ namespace pcpp
155
239
// / @param[in] file The source file in PcapPlusPlus code the log message is coming from
156
240
// / @param[in] method The method in PcapPlusPlus code the log message is coming from
157
241
// / @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;
159
246
160
247
// / A static method for converting the log level enum to a string.
161
248
// / @param[in] logLevel A log level enum
@@ -183,7 +270,16 @@ namespace pcpp
183
270
// / @return True if this module log level is "debug". False otherwise
184
271
bool isDebugEnabled (LogModule module ) const
185
272
{
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;
187
283
}
188
284
189
285
// / Set all PcapPlusPlus modules to a certain log level
@@ -210,8 +306,9 @@ namespace pcpp
210
306
}
211
307
212
308
// / @return Get the last error message
213
- std::string getLastError ()
309
+ std::string getLastError () const
214
310
{
311
+ std::lock_guard<std::mutex> lock (m_LastErrorMtx);
215
312
return m_LastError;
216
313
}
217
314
@@ -234,17 +331,32 @@ namespace pcpp
234
331
return m_LogsEnabled;
235
332
}
236
333
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 )
238
342
{
239
- (*m_LogStream) << msg;
240
- return *this ;
241
- }
343
+ m_UseContextPooling = enabled;
242
344
243
- static std::ostringstream* internalCreateLogStream ();
345
+ if (m_UseContextPooling)
346
+ {
347
+ m_LogContextPool.setMaxSize (maxPoolSize);
244
348
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
+ }
248
360
249
361
// / Get access to Logger singleton
250
362
// / @todo: make this singleton thread-safe/
@@ -255,17 +367,74 @@ namespace pcpp
255
367
return instance;
256
368
}
257
369
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
+
258
390
private:
259
391
bool m_LogsEnabled;
260
- Logger:: LogLevel m_LogModulesArray[ NumOfLogModules]{} ;
392
+ std::array< LogLevel, NumOfLogModules> m_LogModulesArray ;
261
393
LogPrinter m_LogPrinter;
394
+
395
+ mutable std::mutex m_LastErrorMtx;
262
396
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 };
264
401
265
402
// private c'tor - this class is a singleton
266
403
Logger ();
267
404
268
405
static void defaultLogPrinter (LogLevel logLevel, const std::string& logMessage, const std::string& file,
269
406
const std::string& method, int line);
270
407
};
408
+
271
409
} // 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