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