1//
2// RemoteSyslogChannel.cpp
3//
4// Library: Net
5// Package: Logging
6// Module: RemoteSyslogChannel
7//
8// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Net/RemoteSyslogChannel.h"
16#include "Poco/Message.h"
17#include "Poco/DateTimeFormatter.h"
18#include "Poco/NumberFormatter.h"
19#include "Poco/Net/SocketAddress.h"
20#include "Poco/Net/DNS.h"
21#include "Poco/LoggingFactory.h"
22#include "Poco/Instantiator.h"
23#include "Poco/String.h"
24
25
26namespace Poco {
27namespace Net {
28
29
30const std::string RemoteSyslogChannel::BSD_TIMEFORMAT("%b %f %H:%M:%S");
31const std::string RemoteSyslogChannel::SYSLOG_TIMEFORMAT("%Y-%m-%dT%H:%M:%S.%i%z");
32const std::string RemoteSyslogChannel::PROP_NAME("name");
33const std::string RemoteSyslogChannel::PROP_FACILITY("facility");
34const std::string RemoteSyslogChannel::PROP_FORMAT("format");
35const std::string RemoteSyslogChannel::PROP_LOGHOST("loghost");
36const std::string RemoteSyslogChannel::PROP_HOST("host");
37const std::string RemoteSyslogChannel::STRUCTURED_DATA("structured-data");
38
39
40RemoteSyslogChannel::RemoteSyslogChannel():
41 _logHost("localhost"),
42 _name("-"),
43 _facility(SYSLOG_USER),
44 _bsdFormat(false),
45 _open(false)
46{
47}
48
49
50RemoteSyslogChannel::RemoteSyslogChannel(const std::string& address, const std::string& name, int facility, bool bsdFormat):
51 _logHost(address),
52 _name(name),
53 _facility(facility),
54 _bsdFormat(bsdFormat),
55 _open(false)
56{
57 if (_name.empty()) _name = "-";
58}
59
60
61RemoteSyslogChannel::~RemoteSyslogChannel()
62{
63 try
64 {
65 close();
66 }
67 catch (...)
68 {
69 poco_unexpected();
70 }
71}
72
73
74void RemoteSyslogChannel::open()
75{
76 if (_open) return;
77
78 if (_logHost.find(':') != std::string::npos)
79 _socketAddress = SocketAddress(_logHost);
80 else
81 _socketAddress = SocketAddress(_logHost, SYSLOG_PORT);
82
83 // reset socket for the case that it has been previously closed
84 _socket = DatagramSocket(_socketAddress.family());
85
86 if (_host.empty())
87 {
88 try
89 {
90 _host = DNS::thisHost().name();
91 }
92 catch (Poco::Exception&)
93 {
94 _host = _socket.address().host().toString();
95 }
96 }
97
98 _open = true;
99}
100
101
102void RemoteSyslogChannel::close()
103{
104 if (_open)
105 {
106 _socket.close();
107 _open = false;
108 }
109}
110
111
112void RemoteSyslogChannel::log(const Message& msg)
113{
114 Poco::FastMutex::ScopedLock lock(_mutex);
115
116 if (!_open) open();
117
118 std::string m;
119 m.reserve(1024);
120 m += '<';
121 Poco::NumberFormatter::append(m, getPrio(msg) + _facility);
122 m += '>';
123 if (_bsdFormat)
124 {
125 Poco::DateTimeFormatter::append(m, msg.getTime(), BSD_TIMEFORMAT);
126 m += ' ';
127 m += _host;
128 }
129 else
130 {
131 m += "1 "; // version
132 Poco::DateTimeFormatter::append(m, msg.getTime(), SYSLOG_TIMEFORMAT);
133 m += ' ';
134 m += _host;
135 m += ' ';
136 m += _name;
137 m += ' ';
138 Poco::NumberFormatter::append(m, static_cast<Poco::UInt64>(msg.getPid()));
139 m += ' ';
140 m += msg.getSource();
141 m += ' ';
142 if (msg.has(STRUCTURED_DATA))
143 {
144 m += msg.get(STRUCTURED_DATA);
145 }
146 else
147 {
148 m += "-";
149 }
150 }
151 m += ' ';
152 m += msg.getText();
153
154 _socket.sendTo(m.data(), static_cast<int>(m.size()), _socketAddress);
155}
156
157
158void RemoteSyslogChannel::setProperty(const std::string& name, const std::string& value)
159{
160 if (name == PROP_NAME)
161 {
162 _name = value;
163 if (_name.empty()) _name = "-";
164 }
165 else if (name == PROP_FACILITY)
166 {
167 std::string facility;
168 if (Poco::icompare(value, 4, "LOG_") == 0)
169 facility = Poco::toUpper(value.substr(4));
170 else if (Poco::icompare(value, 4, "SYSLOG_") == 0)
171 facility = Poco::toUpper(value.substr(7));
172 else
173 facility = Poco::toUpper(value);
174
175 if (facility == "KERN")
176 _facility = SYSLOG_KERN;
177 else if (facility == "USER")
178 _facility = SYSLOG_USER;
179 else if (facility == "MAIL")
180 _facility = SYSLOG_MAIL;
181 else if (facility == "DAEMON")
182 _facility = SYSLOG_DAEMON;
183 else if (facility == "AUTH")
184 _facility = SYSLOG_AUTH;
185 else if (facility == "AUTHPRIV")
186 _facility = SYSLOG_AUTHPRIV;
187 else if (facility == "SYSLOG")
188 _facility = SYSLOG_SYSLOG;
189 else if (facility == "LPR")
190 _facility = SYSLOG_LPR;
191 else if (facility == "NEWS")
192 _facility = SYSLOG_NEWS;
193 else if (facility == "UUCP")
194 _facility = SYSLOG_UUCP;
195 else if (facility == "CRON")
196 _facility = SYSLOG_CRON;
197 else if (facility == "FTP")
198 _facility = SYSLOG_FTP;
199 else if (facility == "NTP")
200 _facility = SYSLOG_NTP;
201 else if (facility == "LOGAUDIT")
202 _facility = SYSLOG_LOGAUDIT;
203 else if (facility == "LOGALERT")
204 _facility = SYSLOG_LOGALERT;
205 else if (facility == "CLOCK")
206 _facility = SYSLOG_CLOCK;
207 else if (facility == "LOCAL0")
208 _facility = SYSLOG_LOCAL0;
209 else if (facility == "LOCAL1")
210 _facility = SYSLOG_LOCAL1;
211 else if (facility == "LOCAL2")
212 _facility = SYSLOG_LOCAL2;
213 else if (facility == "LOCAL3")
214 _facility = SYSLOG_LOCAL3;
215 else if (facility == "LOCAL4")
216 _facility = SYSLOG_LOCAL4;
217 else if (facility == "LOCAL5")
218 _facility = SYSLOG_LOCAL5;
219 else if (facility == "LOCAL6")
220 _facility = SYSLOG_LOCAL6;
221 else if (facility == "LOCAL7")
222 _facility = SYSLOG_LOCAL7;
223 }
224 else if (name == PROP_LOGHOST)
225 {
226 _logHost = value;
227 }
228 else if (name == PROP_HOST)
229 {
230 _host = value;
231 }
232 else if (name == PROP_FORMAT)
233 {
234 _bsdFormat = (value == "bsd" || value == "rfc3164");
235 }
236 else
237 {
238 Channel::setProperty(name, value);
239 }
240}
241
242
243std::string RemoteSyslogChannel::getProperty(const std::string& name) const
244{
245 if (name == PROP_NAME)
246 {
247 if (_name != "-")
248 return _name;
249 else
250 return "";
251 }
252 else if (name == PROP_FACILITY)
253 {
254 if (_facility == SYSLOG_KERN)
255 return "KERN";
256 else if (_facility == SYSLOG_USER)
257 return "USER";
258 else if (_facility == SYSLOG_MAIL)
259 return "MAIL";
260 else if (_facility == SYSLOG_DAEMON)
261 return "DAEMON";
262 else if (_facility == SYSLOG_AUTH)
263 return "AUTH";
264 else if (_facility == SYSLOG_AUTHPRIV)
265 return "AUTHPRIV";
266 else if (_facility == SYSLOG_SYSLOG)
267 return "SYSLOG";
268 else if (_facility == SYSLOG_LPR)
269 return "LPR";
270 else if (_facility == SYSLOG_NEWS)
271 return "NEWS";
272 else if (_facility == SYSLOG_UUCP)
273 return "UUCP";
274 else if (_facility == SYSLOG_CRON)
275 return "CRON";
276 else if (_facility == SYSLOG_FTP)
277 return "FTP";
278 else if (_facility == SYSLOG_NTP)
279 return "NTP";
280 else if (_facility == SYSLOG_LOGAUDIT)
281 return "LOGAUDIT";
282 else if (_facility == SYSLOG_LOGALERT)
283 return "LOGALERT";
284 else if (_facility == SYSLOG_CLOCK)
285 return "CLOCK";
286 else if (_facility == SYSLOG_LOCAL0)
287 return "LOCAL0";
288 else if (_facility == SYSLOG_LOCAL1)
289 return "LOCAL1";
290 else if (_facility == SYSLOG_LOCAL2)
291 return "LOCAL2";
292 else if (_facility == SYSLOG_LOCAL3)
293 return "LOCAL3";
294 else if (_facility == SYSLOG_LOCAL4)
295 return "LOCAL4";
296 else if (_facility == SYSLOG_LOCAL5)
297 return "LOCAL5";
298 else if (_facility == SYSLOG_LOCAL6)
299 return "LOCAL6";
300 else if (_facility == SYSLOG_LOCAL7)
301 return "LOCAL7";
302 else
303 return "";
304 }
305 else if (name == PROP_LOGHOST)
306 {
307 return _logHost;
308 }
309 else if (name == PROP_HOST)
310 {
311 return _host;
312 }
313 else if (name == PROP_FORMAT)
314 {
315 return _bsdFormat ? "rfc3164" : "rfc5424";
316 }
317 else
318 {
319 return Channel::getProperty(name);
320 }
321}
322
323
324int RemoteSyslogChannel::getPrio(const Message& msg)
325{
326 switch (msg.getPriority())
327 {
328 case Message::PRIO_TRACE:
329 case Message::PRIO_DEBUG:
330 return SYSLOG_DEBUG;
331 case Message::PRIO_INFORMATION:
332 return SYSLOG_INFORMATIONAL;
333 case Message::PRIO_NOTICE:
334 return SYSLOG_NOTICE;
335 case Message::PRIO_WARNING:
336 return SYSLOG_WARNING;
337 case Message::PRIO_ERROR:
338 return SYSLOG_ERROR;
339 case Message::PRIO_CRITICAL:
340 return SYSLOG_CRITICAL;
341 case Message::PRIO_FATAL:
342 return SYSLOG_ALERT;
343 default:
344 return 0;
345 }
346}
347
348
349void RemoteSyslogChannel::registerChannel()
350{
351 Poco::LoggingFactory::defaultFactory().registerChannelClass("RemoteSyslogChannel", new Poco::Instantiator<RemoteSyslogChannel, Poco::Channel>);
352}
353
354
355} } // namespace Poco::Net
356