text: #ifndef PCAPPP_LOGGER
  #define PCAPPP_LOGGER
  
  #include <stdio.h>
  #include <iostream>
  #include <sstream>
  #include <iomanip>
  #include <stdint.h>
  
  #ifndef LOG_MODULE
  #define LOG_MODULE UndefinedLogModule
  #endif
  
  /// @file
  
  /**
   * \namespace pcpp
   * \brief The main namespace for the PcapPlusPlus lib
   */
  namespace pcpp
  {
  
  	/**
  	 * An enum representing all PcapPlusPlus modules
  	 */
  	enum LogModule
  	{
  		UndefinedLogModule,
  		CommonLogModuleIpUtils, ///< IP Utils module (Common++)
  		CommonLogModuleTablePrinter, ///< Table printer module (Common++)
  		CommonLogModuleGenericUtils, ///< Generic Utils (Common++)
  		PacketLogModuleRawPacket, ///< RawPacket module (Packet++)
  		PacketLogModulePacket, ///< Packet module (Packet++)
  		PacketLogModuleLayer, ///< Layer module (Packet++)
  		PacketLogModuleArpLayer, ///< ArpLayer module (Packet++)
  		PacketLogModuleEthLayer, ///< EthLayer module (Packet++)
  		PacketLogModuleIPv4Layer, ///< IPv4Layer module (Packet++)
  		PacketLogModuleIPv6Layer, ///< IPv6Layer module (Packet++)
  		PacketLogModulePayloadLayer, ///< PayloadLayer module (Packet++)
  		PacketLogModuleTcpLayer, ///< TcpLayer module (Packet++)
  		PacketLogModuleUdpLayer, ///< UdpLayer module (Packet++)
  		PacketLogModuleVlanLayer, ///< VlanLayer module (Packet++)
  		PacketLogModuleHttpLayer, ///< HttpLayer module (Packet++)
  		PacketLogModulePPPoELayer, ///< PPPoELayer module (Packet++)
  		PacketLogModuleDnsLayer, ///< DnsLayer module (Packet++)
  		PacketLogModuleMplsLayer, ///< MplsLayer module (Packet++)
  		PacketLogModuleIcmpLayer, ///< IcmpLayer module (Packet++)
  		PacketLogModuleGreLayer, ///< GreLayer module (Packet++)
  		PacketLogModuleSSLLayer, ///< SSLLayer module (Packet++)
  		PacketLogModuleSllLayer, ///< SllLayer module (Packet++)
  		PacketLogModuleDhcpLayer, ///< DhcpLayer module (Packet++)
  		PacketLogModuleDhcpV6Layer, ///< DhcpV6Layer module (Packet++)
  		PacketLogModuleIgmpLayer, ///< IgmpLayer module (Packet++)
  		PacketLogModuleSipLayer, ///< SipLayer module (Packet++)
  		PacketLogModuleSdpLayer, ///< SdpLayer module (Packet++)
  		PacketLogModuleRadiusLayer, ///< RadiusLayer module (Packet++)
  		PacketLogModuleGtpLayer, ///< GtpLayer module (Packet++)
  		PacketLogModuleBgpLayer, ///< GtpLayer module (Packet++)
  		PacketLogModuleSSHLayer, ///< SSHLayer module (Packet++)
  		PacketLogModuleTcpReassembly, ///< TcpReassembly module (Packet++)
  		PacketLogModuleIPReassembly, ///< IPReassembly module (Packet++)
  		PacketLogModuleIPSecLayer, ///< IPSecLayers module (Packet++)
  		PcapLogModuleWinPcapLiveDevice, ///< WinPcapLiveDevice module (Pcap++)
  		PcapLogModuleRemoteDevice, ///< WinPcapRemoteDevice module (Pcap++)
  		PcapLogModuleLiveDevice, ///< PcapLiveDevice module (Pcap++)
  		PcapLogModuleFileDevice, ///< FileDevice module (Pcap++)
  		PcapLogModulePfRingDevice, ///< PfRingDevice module (Pcap++)
  		PcapLogModuleMBufRawPacket, ///< MBufRawPacket module (Pcap++)
  		PcapLogModuleDpdkDevice, ///< DpdkDevice module (Pcap++)
  		PcapLogModuleKniDevice, ///< KniDevice module (Pcap++)
  		NetworkUtils, ///< NetworkUtils module (Pcap++)
  		NumOfLogModules
  	};
  
  	/**
  	 * @class Logger
  	 * PcapPlusPlus logger manager.
  	 * PcapPlusPlus uses this logger to output both error and debug logs.
  	 * There are currently 3 log levels: Logger#Error, Logger#Info and Logger#Debug.
  	 *
  	 * PcapPlusPlus is divided into modules (described in #LogModule enum). The user can set the log level got each module or to all modules at once.
  	 * The default is Logger#Info which outputs only error messages. Changing log level for modules can be done dynamically while the application is running.
  	 * 
  	 * The logger also exposes a method to retrieve the last error log message.
  	 * 
  	 * Logs are printed to console by default in a certain format. The user can set a different print function to change the format or to print to
  	 * other media (such as files, etc.).
  	 * 
  	 * PcapPlusPlus logger is a singleton which can be reached from anywhere in the code.
  	 * 
  	 * Note: Logger#Info level logs are currently only used in DPDK devices to set DPDK log level to RTE_LOG_NOTICE.
  	 */
  	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
  		};
  
  		/**
  		 * @typedef LogPrinter
  		 * Log printer callback. Used for printing the logs in a custom way.
  		 * @param[in] logLevel The log level for this log message
  		 * @param[in] logMessage The log message
  		 * @param[in] file The source file in PcapPlusPlus code the log message is coming from
  		 * @param[in] method The method in PcapPlusPlus code the log message is coming from
  		 * @param[in] line The line in PcapPlusPlus code the log message is coming from
  		 */
  		typedef void (*LogPrinter)(LogLevel logLevel, const std::string& logMessage, const std::string& file, const std::string& method, const int line);
  
  		/**
  		 * A static method for converting the log level enum to a string.
  		 * @param[in] logLevel A log level enum
  		 * @return The log level as a string
  		 */
  		static std::string logLevelAsString(LogLevel logLevel);
  
  		/**
  		 * Get the log level for a certain module
  		 * @param[in] module PcapPlusPlus module
  		 * @return The log level set for this module
  		 */
  		LogLevel getLogLevel(LogModule module) { return m_LogModulesArray[module]; }
  
  		/**
  		 * Set the log level for a certain PcapPlusPlus module
  		 * @param[in] module PcapPlusPlus module
  		 * @param[in] level The log level to set the module to
  		 */
  		void setLogLevel(LogModule module, LogLevel level) { m_LogModulesArray[module] = level; }
  
  		/**
  		 * Check whether a certain module is set to debug log level
  		 * @param[in] module PcapPlusPlus module
  		 * @return True if this module log level is "debug". False otherwise
  		 */
  		bool isDebugEnabled(LogModule module) const { return m_LogModulesArray[module] == Debug; }
  
  		/**
  		 * Set all PcapPlusPlus modules to a certain log level
  		 * @param[in] level The log level to set all modules to
  		 */
  		void setAllModlesToLogLevel(LogLevel level) { for (int i=1; i<NumOfLogModules; i++) m_LogModulesArray[i] = level; }
  
  		/**
  		 * Set a custom log printer.
  		 * @param[in] printer A log printer function that will be called for every log message
  		 */
  		void setLogPrinter(LogPrinter printer) { m_LogPrinter = printer; }
  
  		/**
  		 * Set the log printer back to the default printer
  		 */
  		void resetLogPrinter() { m_LogPrinter = &defaultLogPrinter; }
  
  		/**
  		 * @return Get the last error message
  		 */
  		std::string getLastError() { return m_LastError; }
  
  		/**
  		 * Suppress logs in all PcapPlusPlus modules
  		 */
  		void suppressLogs() { m_LogsEnabled = false; }
  
  		/**
  		 * Enable logs in all PcapPlusPlus modules
  		 */
  		void enableLogs() { m_LogsEnabled = true; }
  
  		/**
  		 * Get an indication if logs are currently enabled.
  		 * @return True if logs are currently enabled, false otherwise
  		 */
  		bool logsEnabled() const { return m_LogsEnabled; }
  
  		/**
  		 * An internal method to print log messages. Shouldn't be used externally.
  		 */
  		inline void internalPrintLogMessage(LogLevel logLevel, const std::string& logMessage, const std::string& file, const std::string& method, const int line);
  
  		/**
  		 * Get access to Logger singleton
  		 * @todo: make this singleton thread-safe/
  		 * @return a pointer to the Logger singleton
  		**/
  		static Logger& getInstance()
  		{
  			static Logger instance;
  			return instance;
  		}
  	private:
  		bool m_LogsEnabled;
  		Logger::LogLevel m_LogModulesArray[NumOfLogModules];
  		LogPrinter m_LogPrinter;
  		std::string m_LastError;
  
  		// private c'tor - this class is a singleton
  		Logger();
  
  		static void defaultLogPrinter(LogLevel logLevel, const std::string& logMessage, const std::string& file, const std::string& method, const int line);
  	};
  
  #define LOG_DEBUG(message) do { \
  		if (pcpp::Logger::getInstance().logsEnabled() && pcpp::Logger::getInstance().isDebugEnabled(LOG_MODULE)) { \
  			std::ostringstream logStream; \
  			logStream << message; \
  			pcpp::Logger::getInstance().internalPrintLogMessage(pcpp::Logger::Debug, logStream.str(), __FILE__, __FUNCTION__, __LINE__); \
  		} \
  	} while(0)
  
  #define LOG_ERROR(message) do { \
  		std::ostringstream logStream; \
  		logStream << message; \
  		pcpp::Logger::getInstance().internalPrintLogMessage(pcpp::Logger::Error, logStream.str(), __FILE__, __FUNCTION__, __LINE__); \
  	} while (0)
  
  void Logger::internalPrintLogMessage(LogLevel logLevel, const std::string& logMessage, const std::string& file, const std::string& method, const int line)
  {
  	if (logLevel == Logger::Error)
  	{
  		m_LastError = logMessage;
  	}
  	if (m_LogsEnabled)
  	{
  		m_LogPrinter(logLevel, logMessage, file, method, line);
  	}
  }
  
  } // namespace pcpp
  
  #endif /* PCAPPP_LOGGER */
  