|
2 | 2 |
|
3 | 3 | #include <boost/asio/co_spawn.hpp> |
4 | 4 | #include <boost/asio/detached.hpp> |
| 5 | +#include <boost/asio/ip/address.hpp> |
5 | 6 | #include <boost/asio/redirect_error.hpp> |
6 | 7 | #include <config.h> |
7 | 8 | #include <logger.hpp> |
8 | 9 | #include <timeHelper.hpp> |
9 | 10 |
|
| 11 | +#include <algorithm> |
| 12 | +#include <cctype> |
10 | 13 | #include <chrono> |
| 14 | +#include <cstdint> |
11 | 15 | #include <iomanip> |
12 | 16 | #include <map> |
| 17 | +#include <set> |
13 | 18 | #include <sstream> |
14 | 19 |
|
15 | 20 | #include "file_reader.hpp" |
| 21 | +#include "syslog_reader.hpp" |
16 | 22 |
|
17 | 23 | using namespace logcollector; |
18 | 24 |
|
@@ -66,9 +72,106 @@ void Logcollector::Setup(std::shared_ptr<const configuration::ConfigurationParse |
66 | 72 | configurationParser->GetConfigOrDefault(config::logcollector::DEFAULT_ENABLED, "logcollector", "enabled"); |
67 | 73 |
|
68 | 74 | SetupFileReader(configurationParser); |
| 75 | + SetupSyslogReaders(configurationParser); |
69 | 76 | AddPlatformSpecificReader(configurationParser); |
70 | 77 | } |
71 | 78 |
|
| 79 | +void Logcollector::SetupSyslogReaders( |
| 80 | + const std::shared_ptr<const configuration::ConfigurationParser> configurationParser) |
| 81 | +{ |
| 82 | + const auto syslogConfigs = configurationParser->GetConfigOrDefault<YAML::Node>( |
| 83 | + YAML::Node(YAML::NodeType::Sequence), "logcollector", "syslog"); |
| 84 | + |
| 85 | + constexpr int MIN_PORT = 1; |
| 86 | + constexpr int MAX_PORT = 65535; |
| 87 | + |
| 88 | + std::set<std::string> seenListeners; |
| 89 | + |
| 90 | + for (const auto& config : syslogConfigs) |
| 91 | + { |
| 92 | + if (!config.IsMap()) |
| 93 | + { |
| 94 | + LogWarn("Invalid agent-side syslog listener configuration: entry is not a mapping."); |
| 95 | + continue; |
| 96 | + } |
| 97 | + |
| 98 | + auto protocolStr = config["protocol"].as<std::string>(""); |
| 99 | + std::transform(protocolStr.begin(), |
| 100 | + protocolStr.end(), |
| 101 | + protocolStr.begin(), |
| 102 | + [](unsigned char c) { return static_cast<char>(std::tolower(c)); }); |
| 103 | + |
| 104 | + SyslogProtocol protocol = SyslogProtocol::Udp; |
| 105 | + if (protocolStr == "udp") |
| 106 | + { |
| 107 | + protocol = SyslogProtocol::Udp; |
| 108 | + } |
| 109 | + else if (protocolStr == "tcp") |
| 110 | + { |
| 111 | + protocol = SyslogProtocol::Tcp; |
| 112 | + } |
| 113 | + else |
| 114 | + { |
| 115 | + LogError("Invalid agent-side syslog listener configuration: unsupported protocol {}.", |
| 116 | + protocolStr.empty() ? "(missing)" : protocolStr); |
| 117 | + continue; |
| 118 | + } |
| 119 | + |
| 120 | + if (!config["port"]) |
| 121 | + { |
| 122 | + LogError("Invalid agent-side syslog listener configuration: missing port."); |
| 123 | + continue; |
| 124 | + } |
| 125 | + |
| 126 | + int port = 0; |
| 127 | + try |
| 128 | + { |
| 129 | + port = config["port"].as<int>(); |
| 130 | + } |
| 131 | + catch (const std::exception&) |
| 132 | + { |
| 133 | + LogError("Invalid agent-side syslog listener configuration: invalid port {}.", |
| 134 | + config["port"].as<std::string>("")); |
| 135 | + continue; |
| 136 | + } |
| 137 | + |
| 138 | + if (port < MIN_PORT || port > MAX_PORT) |
| 139 | + { |
| 140 | + LogError("Invalid agent-side syslog listener configuration: invalid port {}.", port); |
| 141 | + continue; |
| 142 | + } |
| 143 | + |
| 144 | + const auto bindAddress = config["bind_address"].as<std::string>("127.0.0.1"); |
| 145 | + |
| 146 | + boost::system::error_code ec; |
| 147 | + boost::asio::ip::make_address(bindAddress, ec); |
| 148 | + if (ec) |
| 149 | + { |
| 150 | + LogError("Invalid agent-side syslog listener configuration: invalid bind address {}.", bindAddress); |
| 151 | + continue; |
| 152 | + } |
| 153 | + |
| 154 | + const auto listenerId = |
| 155 | + SyslogReader::ProtocolToString(protocol) + ":" + bindAddress + ":" + std::to_string(port); |
| 156 | + |
| 157 | + if (!seenListeners.insert(listenerId).second) |
| 158 | + { |
| 159 | + LogError("Invalid agent-side syslog listener configuration: duplicate listener {}.", listenerId); |
| 160 | + continue; |
| 161 | + } |
| 162 | + |
| 163 | + AddReader(std::make_shared<SyslogReader>( |
| 164 | + [this](const std::string& location, const std::string& log, const std::string& collectorType) |
| 165 | + { PushMessage(location, log, collectorType); }, |
| 166 | + // NOLINTNEXTLINE(cppcoreguidelines-avoid-capturing-lambda-coroutines) |
| 167 | + [this](std::chrono::milliseconds duration) -> Awaitable { co_await Wait(duration); }, |
| 168 | + [this](Awaitable task) { EnqueueTask(std::move(task)); }, |
| 169 | + protocol, |
| 170 | + bindAddress, |
| 171 | + static_cast<std::uint16_t>(port))); |
| 172 | + } |
| 173 | +} |
| 174 | + |
72 | 175 | void Logcollector::SetupFileReader(const std::shared_ptr<const configuration::ConfigurationParser> configurationParser) |
73 | 176 | { |
74 | 177 | const auto fileWait = configurationParser->GetTimeConfigOrDefault( |
|
0 commit comments