/src/PcapPlusPlus/Common++/src/Logger.cpp
Line | Count | Source |
1 | | #include "Logger.h" |
2 | | |
3 | | #include <iostream> |
4 | | #include <iomanip> |
5 | | #include <sstream> |
6 | | #include <cstring> |
7 | | #include <mutex> |
8 | | |
9 | | namespace pcpp |
10 | | { |
11 | | |
12 | | namespace |
13 | | { |
14 | | /// Default log printer function that prints to std::cerr. |
15 | | void printToCerr(LogLevel logLevel, const std::string& logMessage, const std::string& file, |
16 | | const std::string& method, const int line) |
17 | 0 | { |
18 | | // This mutex is used to prevent multiple threads from writing to the console at the same time. |
19 | 0 | static std::mutex logMutex; |
20 | |
|
21 | 0 | std::ostringstream sstream; |
22 | 0 | sstream << file << ": " << method << ":" << line; |
23 | |
|
24 | 0 | std::unique_lock<std::mutex> const lock(logMutex); |
25 | 0 | std::cerr << std::left << "[" << std::setw(5) << Logger::logLevelAsString(logLevel) << ": " << std::setw(45) |
26 | 0 | << sstream.str() << "] " << logMessage << std::endl; |
27 | 0 | } |
28 | | } // namespace |
29 | | |
30 | | // Alpine Linux incorrectly declares strerror_r |
31 | | // https://stackoverflow.com/questions/41953104/strerror-r-is-incorrectly-declared-on-alpine-linux |
32 | | char* checkError(int /*unused*/, char* buffer, int /*unused*/) |
33 | 0 | { |
34 | 0 | return buffer; |
35 | 0 | } |
36 | | |
37 | | char* checkError(char* result, const char* /*unused*/, int /*unused*/) |
38 | 0 | { |
39 | 0 | return result; |
40 | 0 | } |
41 | | |
42 | | std::string getErrorString(int errnum) |
43 | 0 | { |
44 | 0 | std::array<char, BUFSIZ> buffer{}; |
45 | | #if defined(_WIN32) |
46 | | strerror_s(buffer.data(), buffer.size(), errnum); |
47 | | return buffer.data(); |
48 | | #else |
49 | 0 | return checkError(strerror_r(errnum, buffer.data(), BUFSIZ), buffer.data(), errnum); |
50 | 0 | #endif |
51 | 0 | } |
52 | | |
53 | | thread_local std::array<char, 255> Logger::m_LastError = { 0 }; |
54 | | |
55 | 1 | Logger::Logger() : m_LogsEnabled(true), m_LogPrinter(&printToCerr) |
56 | 1 | { |
57 | 1 | m_LogModulesArray.fill(LogLevel::Info); |
58 | 1 | } |
59 | | |
60 | | std::string Logger::logLevelAsString(LogLevel logLevel) |
61 | 0 | { |
62 | 0 | switch (logLevel) |
63 | 0 | { |
64 | 0 | case LogLevel::Off: |
65 | 0 | return "OFF"; |
66 | 0 | case LogLevel::Error: |
67 | 0 | return "ERROR"; |
68 | 0 | case LogLevel::Warn: |
69 | 0 | return "WARN"; |
70 | 0 | case LogLevel::Info: |
71 | 0 | return "INFO"; |
72 | 0 | case LogLevel::Debug: |
73 | 0 | return "DEBUG"; |
74 | 0 | default: |
75 | 0 | return "UNKNOWN"; |
76 | 0 | } |
77 | 0 | } |
78 | | |
79 | | void Logger::resetLogPrinter() |
80 | 0 | { |
81 | 0 | m_LogPrinter = &printToCerr; // Reset to the default log printer |
82 | 0 | } |
83 | | |
84 | | std::unique_ptr<internal::LogContext> Logger::createLogContext() |
85 | 0 | { |
86 | 0 | return createLogContext(LogLevel::Info, {}); // call the other createLogContext method |
87 | 0 | } |
88 | | std::unique_ptr<internal::LogContext> Logger::createLogContext(LogLevel level, LogSource const& source) |
89 | 1.29k | { |
90 | 1.29k | if (m_UseContextPooling) |
91 | 1.29k | { |
92 | 1.29k | auto ctx = m_LogContextPool.acquireObject(); |
93 | 1.29k | ctx->init(level, source); |
94 | 1.29k | return ctx; |
95 | 1.29k | } |
96 | 0 | return std::make_unique<internal::LogContext>(level, source); |
97 | 1.29k | } |
98 | | |
99 | | void Logger::emit(std::unique_ptr<internal::LogContext> message) |
100 | 1.29k | { |
101 | 1.29k | emit(message->m_Source, message->m_Level, message->m_Stream.str()); |
102 | | // Pushes the message back to the pool if pooling is enabled. Otherwise, the message is deleted. |
103 | 1.29k | if (m_UseContextPooling) |
104 | 1.29k | { |
105 | 1.29k | m_LogContextPool.releaseObject(std::move(message)); |
106 | 1.29k | } |
107 | 1.29k | } |
108 | | |
109 | | void Logger::emit(LogSource const& source, LogLevel logLevel, std::string const& message) |
110 | 1.29k | { |
111 | | // If the log level is an error, save the error to the last error message variable. |
112 | 1.29k | if (logLevel == LogLevel::Error) |
113 | 264 | { |
114 | 264 | static_assert(m_LastError.size() >= 1, |
115 | 264 | "Last error buffer size must be at least 1 to hold a null terminator"); |
116 | | |
117 | | // Copy the message to the last error buffer, leaving space for null terminator |
118 | 264 | auto const copied = message.copy(m_LastError.data(), m_LastError.size() - 1); |
119 | 264 | m_LastError[copied] = '\0'; |
120 | 264 | } |
121 | 1.29k | if (m_LogsEnabled) |
122 | 0 | { |
123 | 0 | m_LogPrinter(logLevel, message, source.file, source.function, source.line); |
124 | 0 | } |
125 | 1.29k | } |
126 | | } // namespace pcpp |