1 | /* |
2 | * Copyright Andrey Semashev 2007 - 2015. |
3 | * Distributed under the Boost Software License, Version 1.0. |
4 | * (See accompanying file LICENSE_1_0.txt or copy at |
5 | * http://www.boost.org/LICENSE_1_0.txt) |
6 | */ |
7 | /*! |
8 | * \file syslog_backend.cpp |
9 | * \author Andrey Semashev |
10 | * \date 08.01.2008 |
11 | * |
12 | * \brief This header is the Boost.Log library implementation, see the library documentation |
13 | * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. |
14 | */ |
15 | |
16 | #ifndef BOOST_LOG_WITHOUT_SYSLOG |
17 | |
18 | #include "windows_version.hpp" |
19 | #include <boost/log/detail/config.hpp> |
20 | #include <ctime> |
21 | #include <algorithm> |
22 | #include <stdexcept> |
23 | #include <boost/limits.hpp> |
24 | #include <boost/assert.hpp> |
25 | #include <boost/smart_ptr/weak_ptr.hpp> |
26 | #include <boost/smart_ptr/shared_ptr.hpp> |
27 | #include <boost/smart_ptr/make_shared_object.hpp> |
28 | #include <boost/throw_exception.hpp> |
29 | #if !defined(BOOST_LOG_NO_ASIO) |
30 | #include <boost/asio/buffer.hpp> |
31 | #include <boost/asio/socket_base.hpp> |
32 | #include <boost/asio/io_service.hpp> |
33 | #include <boost/asio/ip/udp.hpp> |
34 | #include <boost/asio/ip/address.hpp> |
35 | #include <boost/asio/ip/host_name.hpp> |
36 | #endif |
37 | #include <boost/system/error_code.hpp> |
38 | #include <boost/date_time/c_time.hpp> |
39 | #include <boost/log/sinks/syslog_backend.hpp> |
40 | #include <boost/log/detail/singleton.hpp> |
41 | #include <boost/log/detail/snprintf.hpp> |
42 | #include <boost/log/exceptions.hpp> |
43 | #if !defined(BOOST_LOG_NO_THREADS) |
44 | #include <boost/thread/locks.hpp> |
45 | #include <boost/thread/mutex.hpp> |
46 | #endif |
47 | #include "unique_ptr.hpp" |
48 | |
49 | #ifdef BOOST_LOG_USE_NATIVE_SYSLOG |
50 | #include <syslog.h> |
51 | #endif // BOOST_LOG_USE_NATIVE_SYSLOG |
52 | |
53 | #include <boost/log/detail/header.hpp> |
54 | |
55 | namespace boost { |
56 | |
57 | BOOST_LOG_OPEN_NAMESPACE |
58 | |
59 | namespace sinks { |
60 | |
61 | namespace syslog { |
62 | |
63 | //! The function constructs log record level from an integer |
64 | BOOST_LOG_API level make_level(int lev) |
65 | { |
66 | if (static_cast< unsigned int >(lev) >= 8) |
67 | BOOST_THROW_EXCEPTION(std::out_of_range("syslog level value is out of range" )); |
68 | return static_cast< level >(lev); |
69 | } |
70 | |
71 | //! The function constructs log source facility from an integer |
72 | BOOST_LOG_API facility make_facility(int fac) |
73 | { |
74 | if ((static_cast< unsigned int >(fac) & 7U) != 0 |
75 | || static_cast< unsigned int >(fac) > (23U * 8U)) |
76 | { |
77 | BOOST_THROW_EXCEPTION(std::out_of_range("syslog facility code value is out of range" )); |
78 | } |
79 | return static_cast< facility >(fac); |
80 | } |
81 | |
82 | } // namespace syslog |
83 | |
84 | //////////////////////////////////////////////////////////////////////////////// |
85 | //! Syslog sink backend implementation |
86 | //////////////////////////////////////////////////////////////////////////////// |
87 | struct syslog_backend::implementation |
88 | { |
89 | #ifdef BOOST_LOG_USE_NATIVE_SYSLOG |
90 | struct native; |
91 | #endif // BOOST_LOG_USE_NATIVE_SYSLOG |
92 | #if !defined(BOOST_LOG_NO_ASIO) |
93 | struct udp_socket_based; |
94 | #endif |
95 | |
96 | //! Level mapper |
97 | severity_mapper_type m_LevelMapper; |
98 | |
99 | //! Logging facility (portable or native, depending on the backend implementation) |
100 | const int m_Facility; |
101 | |
102 | //! Constructor |
103 | explicit implementation(int facility) : |
104 | m_Facility(facility) |
105 | { |
106 | } |
107 | //! Virtual destructor |
108 | virtual ~implementation() {} |
109 | |
110 | //! The method sends the formatted message to the syslog host |
111 | virtual void send(syslog::level lev, string_type const& formatted_message) = 0; |
112 | }; |
113 | |
114 | |
115 | //////////////////////////////////////////////////////////////////////////////// |
116 | // Native syslog API support |
117 | //////////////////////////////////////////////////////////////////////////////// |
118 | |
119 | #ifdef BOOST_LOG_USE_NATIVE_SYSLOG |
120 | |
121 | BOOST_LOG_ANONYMOUS_NAMESPACE { |
122 | |
123 | //! Syslog service initializer (implemented as a weak singleton) |
124 | #if !defined(BOOST_LOG_NO_THREADS) |
125 | class native_syslog_initializer : |
126 | private log::aux::lazy_singleton< native_syslog_initializer, mutex > |
127 | #else |
128 | class native_syslog_initializer |
129 | #endif |
130 | { |
131 | #if !defined(BOOST_LOG_NO_THREADS) |
132 | friend class log::aux::lazy_singleton< native_syslog_initializer, mutex >; |
133 | typedef log::aux::lazy_singleton< native_syslog_initializer, mutex > mutex_holder; |
134 | #endif |
135 | |
136 | public: |
137 | native_syslog_initializer(std::string const& ident, int facility) |
138 | { |
139 | ::openlog(ident: (ident.empty() ? static_cast< const char* >(NULL) : ident.c_str()), option: 0, facility: facility); |
140 | } |
141 | ~native_syslog_initializer() |
142 | { |
143 | ::closelog(); |
144 | } |
145 | |
146 | static shared_ptr< native_syslog_initializer > get_instance(std::string const& ident, int facility) |
147 | { |
148 | #if !defined(BOOST_LOG_NO_THREADS) |
149 | lock_guard< mutex > lock(mutex_holder::get()); |
150 | #endif |
151 | static weak_ptr< native_syslog_initializer > instance; |
152 | shared_ptr< native_syslog_initializer > p(instance.lock()); |
153 | if (!p) |
154 | { |
155 | p = boost::make_shared< native_syslog_initializer >(args: ident, args&: facility); |
156 | instance = p; |
157 | } |
158 | return p; |
159 | } |
160 | }; |
161 | |
162 | } // namespace |
163 | |
164 | struct syslog_backend::implementation::native : |
165 | public implementation |
166 | { |
167 | //! Reference to the syslog service initializer |
168 | const shared_ptr< native_syslog_initializer > m_pSyslogInitializer; |
169 | |
170 | //! Constructor |
171 | native(syslog::facility const& fac, std::string const& ident) : |
172 | implementation(convert_facility(fac)), |
173 | m_pSyslogInitializer(native_syslog_initializer::get_instance(ident, facility: this->m_Facility)) |
174 | { |
175 | } |
176 | |
177 | //! The method sends the formatted message to the syslog host |
178 | void send(syslog::level lev, string_type const& formatted_message) |
179 | { |
180 | int native_level; |
181 | switch (lev) |
182 | { |
183 | case syslog::emergency: |
184 | native_level = LOG_EMERG; break; |
185 | case syslog::alert: |
186 | native_level = LOG_ALERT; break; |
187 | case syslog::critical: |
188 | native_level = LOG_CRIT; break; |
189 | case syslog::error: |
190 | native_level = LOG_ERR; break; |
191 | case syslog::warning: |
192 | native_level = LOG_WARNING; break; |
193 | case syslog::notice: |
194 | native_level = LOG_NOTICE; break; |
195 | case syslog::debug: |
196 | native_level = LOG_DEBUG; break; |
197 | default: |
198 | native_level = LOG_INFO; break; |
199 | } |
200 | |
201 | ::syslog(pri: this->m_Facility | native_level, fmt: "%s" , formatted_message.c_str()); |
202 | } |
203 | |
204 | private: |
205 | //! The function converts portable facility codes to the native codes |
206 | static int convert_facility(syslog::facility const& fac) |
207 | { |
208 | // POSIX does not specify anything except for LOG_USER and LOG_LOCAL* |
209 | #ifndef LOG_KERN |
210 | #define LOG_KERN LOG_USER |
211 | #endif |
212 | #ifndef LOG_DAEMON |
213 | #define LOG_DAEMON LOG_KERN |
214 | #endif |
215 | #ifndef LOG_MAIL |
216 | #define LOG_MAIL LOG_USER |
217 | #endif |
218 | #ifndef LOG_AUTH |
219 | #define LOG_AUTH LOG_DAEMON |
220 | #endif |
221 | #ifndef LOG_SYSLOG |
222 | #define LOG_SYSLOG LOG_DAEMON |
223 | #endif |
224 | #ifndef LOG_LPR |
225 | #define LOG_LPR LOG_DAEMON |
226 | #endif |
227 | #ifndef LOG_NEWS |
228 | #define LOG_NEWS LOG_USER |
229 | #endif |
230 | #ifndef LOG_UUCP |
231 | #define LOG_UUCP LOG_USER |
232 | #endif |
233 | #ifndef LOG_CRON |
234 | #define LOG_CRON LOG_DAEMON |
235 | #endif |
236 | #ifndef LOG_AUTHPRIV |
237 | #define LOG_AUTHPRIV LOG_AUTH |
238 | #endif |
239 | #ifndef LOG_FTP |
240 | #define LOG_FTP LOG_DAEMON |
241 | #endif |
242 | |
243 | static const int native_facilities[24] = |
244 | { |
245 | LOG_KERN, |
246 | LOG_USER, |
247 | LOG_MAIL, |
248 | LOG_DAEMON, |
249 | LOG_AUTH, |
250 | LOG_SYSLOG, |
251 | LOG_LPR, |
252 | LOG_NEWS, |
253 | LOG_UUCP, |
254 | LOG_CRON, |
255 | LOG_AUTHPRIV, |
256 | LOG_FTP, |
257 | |
258 | // reserved values |
259 | LOG_USER, |
260 | LOG_USER, |
261 | LOG_USER, |
262 | LOG_USER, |
263 | |
264 | LOG_LOCAL0, |
265 | LOG_LOCAL1, |
266 | LOG_LOCAL2, |
267 | LOG_LOCAL3, |
268 | LOG_LOCAL4, |
269 | LOG_LOCAL5, |
270 | LOG_LOCAL6, |
271 | LOG_LOCAL7 |
272 | }; |
273 | |
274 | std::size_t n = static_cast< unsigned int >(fac) / 8U; |
275 | BOOST_ASSERT(n < sizeof(native_facilities) / sizeof(*native_facilities)); |
276 | return native_facilities[n]; |
277 | } |
278 | }; |
279 | |
280 | #endif // BOOST_LOG_USE_NATIVE_SYSLOG |
281 | |
282 | |
283 | //////////////////////////////////////////////////////////////////////////////// |
284 | // Socket-based implementation |
285 | //////////////////////////////////////////////////////////////////////////////// |
286 | |
287 | #if !defined(BOOST_LOG_NO_ASIO) |
288 | |
289 | BOOST_LOG_ANONYMOUS_NAMESPACE { |
290 | |
291 | //! The shared UDP socket |
292 | struct syslog_udp_socket |
293 | { |
294 | private: |
295 | //! The socket primitive |
296 | asio::ip::udp::socket m_Socket; |
297 | |
298 | public: |
299 | //! The constructor creates a socket bound to the specified local address and port |
300 | explicit syslog_udp_socket(asio::io_service& service, asio::ip::udp const& protocol, asio::ip::udp::endpoint const& local_address) : |
301 | m_Socket(service) |
302 | { |
303 | m_Socket.open(protocol); |
304 | m_Socket.set_option(asio::socket_base::reuse_address(true)); |
305 | m_Socket.bind(endpoint: local_address); |
306 | } |
307 | //! The destructor closes the socket |
308 | ~syslog_udp_socket() |
309 | { |
310 | boost::system::error_code ec; |
311 | m_Socket.shutdown(what: asio::socket_base::shutdown_both, ec); |
312 | m_Socket.close(ec); |
313 | } |
314 | |
315 | //! The method sends the syslog message to the specified endpoint |
316 | void send_message(int pri, const char* local_host_name, asio::ip::udp::endpoint const& target, const char* message); |
317 | |
318 | private: |
319 | syslog_udp_socket(syslog_udp_socket const&); |
320 | syslog_udp_socket& operator= (syslog_udp_socket const&); |
321 | }; |
322 | |
323 | //! The class contains the UDP service for syslog sockets to function |
324 | class syslog_udp_service : |
325 | public log::aux::lazy_singleton< syslog_udp_service, shared_ptr< syslog_udp_service > > |
326 | { |
327 | friend class log::aux::lazy_singleton< syslog_udp_service, shared_ptr< syslog_udp_service > >; |
328 | typedef log::aux::lazy_singleton< syslog_udp_service, shared_ptr< syslog_udp_service > > base_type; |
329 | |
330 | public: |
331 | //! The core IO service instance |
332 | asio::io_service m_IOService; |
333 | //! The local host name to put into log message |
334 | std::string m_LocalHostName; |
335 | |
336 | #if !defined(BOOST_LOG_NO_THREADS) |
337 | //! A synchronization primitive to protect the host name resolver |
338 | mutex m_Mutex; |
339 | //! The resolver is used to acquire connection endpoints |
340 | asio::ip::udp::resolver m_HostNameResolver; |
341 | #endif // !defined(BOOST_LOG_NO_THREADS) |
342 | |
343 | private: |
344 | //! Default constructor |
345 | syslog_udp_service() |
346 | #if !defined(BOOST_LOG_NO_THREADS) |
347 | : m_HostNameResolver(m_IOService) |
348 | #endif // !defined(BOOST_LOG_NO_THREADS) |
349 | { |
350 | boost::system::error_code err; |
351 | m_LocalHostName = asio::ip::host_name(ec&: err); |
352 | } |
353 | //! Initializes the singleton instance |
354 | static void init_instance() |
355 | { |
356 | base_type::get_instance().reset(p: new syslog_udp_service()); |
357 | } |
358 | }; |
359 | |
360 | //! The method sends the syslog message to the specified endpoint |
361 | void syslog_udp_socket::send_message( |
362 | int pri, const char* local_host_name, asio::ip::udp::endpoint const& target, const char* message) |
363 | { |
364 | std::time_t t = std::time(NULL); |
365 | std::tm ts; |
366 | std::tm* time_stamp = boost::date_time::c_time::localtime(t: &t, result: &ts); |
367 | |
368 | // Month will have to be injected separately, as involving locale won't do here |
369 | static const char months[12][4] = |
370 | { |
371 | "Jan" , "Feb" , "Mar" , "Apr" , "May" , "Jun" , "Jul" , "Aug" , "Sep" , "Oct" , "Nov" , "Dec" |
372 | }; |
373 | |
374 | // The packet size is mandated in RFC3164, plus one for the terminating zero |
375 | char packet[1025]; |
376 | int n = boost::log::aux::snprintf |
377 | ( |
378 | s: packet, |
379 | maxlen: sizeof(packet), |
380 | format: "<%d> %s % 2d %02d:%02d:%02d %s %s" , |
381 | pri, |
382 | months[time_stamp->tm_mon], |
383 | time_stamp->tm_mday, |
384 | time_stamp->tm_hour, |
385 | time_stamp->tm_min, |
386 | time_stamp->tm_sec, |
387 | local_host_name, |
388 | message |
389 | ); |
390 | if (n > 0) |
391 | { |
392 | std::size_t packet_size = static_cast< std::size_t >(n) >= sizeof(packet) ? sizeof(packet) - 1u : static_cast< std::size_t >(n); |
393 | m_Socket.send_to(buffers: asio::buffer(data&: packet, max_size_in_bytes: packet_size), destination: target); |
394 | } |
395 | } |
396 | |
397 | } // namespace |
398 | |
399 | struct syslog_backend::implementation::udp_socket_based : |
400 | public implementation |
401 | { |
402 | //! Protocol to be used |
403 | asio::ip::udp m_Protocol; |
404 | //! Pointer to the list of sockets |
405 | shared_ptr< syslog_udp_service > m_pService; |
406 | //! Pointer to the socket being used |
407 | log::aux::unique_ptr< syslog_udp_socket > m_pSocket; |
408 | //! The target host to send packets to |
409 | asio::ip::udp::endpoint m_TargetHost; |
410 | |
411 | //! Constructor |
412 | explicit udp_socket_based(syslog::facility const& fac, asio::ip::udp const& protocol) : |
413 | implementation(fac), |
414 | m_Protocol(protocol), |
415 | m_pService(syslog_udp_service::get()) |
416 | { |
417 | if (m_Protocol == asio::ip::udp::v4()) |
418 | { |
419 | m_TargetHost = asio::ip::udp::endpoint(asio::ip::address_v4(0x7F000001), 514); // 127.0.0.1:514 |
420 | } |
421 | else |
422 | { |
423 | // ::1, port 514 |
424 | asio::ip::address_v6::bytes_type addr; |
425 | std::fill_n(first: addr.data(), n: addr.size() - 1, value: static_cast< unsigned char >(0)); |
426 | addr[addr.size() - 1] = 1; |
427 | m_TargetHost = asio::ip::udp::endpoint(asio::ip::address_v6(addr), 514); |
428 | } |
429 | } |
430 | |
431 | //! The method sends the formatted message to the syslog host |
432 | void send(syslog::level lev, string_type const& formatted_message) |
433 | { |
434 | if (!m_pSocket.get()) |
435 | { |
436 | asio::ip::udp::endpoint any_local_address; |
437 | m_pSocket.reset(p: new syslog_udp_socket(m_pService->m_IOService, m_Protocol, any_local_address)); |
438 | } |
439 | |
440 | m_pSocket->send_message( |
441 | pri: this->m_Facility | static_cast< int >(lev), |
442 | local_host_name: m_pService->m_LocalHostName.c_str(), |
443 | target: m_TargetHost, |
444 | message: formatted_message.c_str()); |
445 | } |
446 | }; |
447 | |
448 | #endif // !defined(BOOST_LOG_NO_ASIO) |
449 | |
450 | //////////////////////////////////////////////////////////////////////////////// |
451 | // Sink backend implementation |
452 | //////////////////////////////////////////////////////////////////////////////// |
453 | BOOST_LOG_API syslog_backend::syslog_backend() |
454 | { |
455 | construct(args: log::aux::empty_arg_list()); |
456 | } |
457 | |
458 | //! Destructor |
459 | BOOST_LOG_API syslog_backend::~syslog_backend() |
460 | { |
461 | delete m_pImpl; |
462 | } |
463 | |
464 | //! The method installs the function object that maps application severity levels to Syslog levels |
465 | BOOST_LOG_API void syslog_backend::set_severity_mapper(severity_mapper_type const& mapper) |
466 | { |
467 | m_pImpl->m_LevelMapper = mapper; |
468 | } |
469 | |
470 | //! The method writes the message to the sink |
471 | BOOST_LOG_API void syslog_backend::consume(record_view const& rec, string_type const& formatted_message) |
472 | { |
473 | m_pImpl->send( |
474 | lev: m_pImpl->m_LevelMapper.empty() ? syslog::info : m_pImpl->m_LevelMapper(rec), |
475 | formatted_message); |
476 | } |
477 | |
478 | |
479 | //! The method creates the backend implementation |
480 | BOOST_LOG_API void syslog_backend::construct(syslog::facility fac, syslog::impl_types use_impl, ip_versions ip_version, std::string const& ident) |
481 | { |
482 | #ifdef BOOST_LOG_USE_NATIVE_SYSLOG |
483 | if (use_impl == syslog::native) |
484 | { |
485 | typedef implementation::native native_impl; |
486 | m_pImpl = new native_impl(fac, ident); |
487 | return; |
488 | } |
489 | #endif // BOOST_LOG_USE_NATIVE_SYSLOG |
490 | |
491 | #if !defined(BOOST_LOG_NO_ASIO) |
492 | typedef implementation::udp_socket_based udp_socket_based_impl; |
493 | switch (ip_version) |
494 | { |
495 | case v4: |
496 | m_pImpl = new udp_socket_based_impl(fac, asio::ip::udp::v4()); |
497 | break; |
498 | case v6: |
499 | m_pImpl = new udp_socket_based_impl(fac, asio::ip::udp::v6()); |
500 | break; |
501 | default: |
502 | BOOST_LOG_THROW_DESCR(setup_error, "Incorrect IP version specified" ); |
503 | } |
504 | #endif |
505 | } |
506 | |
507 | #if !defined(BOOST_LOG_NO_ASIO) |
508 | |
509 | //! The method sets the local address which log records will be sent from. |
510 | BOOST_LOG_API void syslog_backend::set_local_address(std::string const& addr, unsigned short port) |
511 | { |
512 | #if !defined(BOOST_LOG_NO_THREADS) |
513 | typedef implementation::udp_socket_based udp_socket_based_impl; |
514 | if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl)) |
515 | { |
516 | char service_name[std::numeric_limits< int >::digits10 + 3]; |
517 | boost::log::aux::snprintf(s: service_name, maxlen: sizeof(service_name), format: "%d" , static_cast< int >(port)); |
518 | asio::ip::udp::resolver::query q( |
519 | impl->m_Protocol, |
520 | addr, |
521 | service_name, |
522 | asio::ip::resolver_query_base::address_configured | asio::ip::resolver_query_base::passive); |
523 | asio::ip::udp::endpoint local_address; |
524 | |
525 | { |
526 | lock_guard< mutex > _(impl->m_pService->m_Mutex); |
527 | local_address = *impl->m_pService->m_HostNameResolver.resolve(q); |
528 | } |
529 | |
530 | impl->m_pSocket.reset(p: new syslog_udp_socket(impl->m_pService->m_IOService, impl->m_Protocol, local_address)); |
531 | } |
532 | #else |
533 | // Boost.ASIO requires threads for the host name resolver, |
534 | // so without threads we simply assume the string already contains IP address |
535 | set_local_address(boost::asio::ip::address::from_string(addr), port); |
536 | #endif // !defined(BOOST_LOG_NO_THREADS) |
537 | } |
538 | //! The method sets the local address which log records will be sent from. |
539 | BOOST_LOG_API void syslog_backend::set_local_address(boost::asio::ip::address const& addr, unsigned short port) |
540 | { |
541 | typedef implementation::udp_socket_based udp_socket_based_impl; |
542 | if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl)) |
543 | { |
544 | impl->m_pSocket.reset(p: new syslog_udp_socket( |
545 | impl->m_pService->m_IOService, impl->m_Protocol, asio::ip::udp::endpoint(addr, port))); |
546 | } |
547 | } |
548 | |
549 | //! The method sets the address of the remote host where log records will be sent to. |
550 | BOOST_LOG_API void syslog_backend::set_target_address(std::string const& addr, unsigned short port) |
551 | { |
552 | #if !defined(BOOST_LOG_NO_THREADS) |
553 | typedef implementation::udp_socket_based udp_socket_based_impl; |
554 | if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl)) |
555 | { |
556 | char service_name[std::numeric_limits< int >::digits10 + 3]; |
557 | boost::log::aux::snprintf(s: service_name, maxlen: sizeof(service_name), format: "%d" , static_cast< int >(port)); |
558 | asio::ip::udp::resolver::query q(impl->m_Protocol, addr, service_name, asio::ip::resolver_query_base::address_configured); |
559 | asio::ip::udp::endpoint remote_address; |
560 | |
561 | { |
562 | lock_guard< mutex > _(impl->m_pService->m_Mutex); |
563 | remote_address = *impl->m_pService->m_HostNameResolver.resolve(q); |
564 | } |
565 | |
566 | impl->m_TargetHost = remote_address; |
567 | } |
568 | #else |
569 | // Boost.ASIO requires threads for the host name resolver, |
570 | // so without threads we simply assume the string already contains IP address |
571 | set_target_address(boost::asio::ip::address::from_string(addr), port); |
572 | #endif // !defined(BOOST_LOG_NO_THREADS) |
573 | } |
574 | //! The method sets the address of the remote host where log records will be sent to. |
575 | BOOST_LOG_API void syslog_backend::set_target_address(boost::asio::ip::address const& addr, unsigned short port) |
576 | { |
577 | typedef implementation::udp_socket_based udp_socket_based_impl; |
578 | if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl)) |
579 | { |
580 | impl->m_TargetHost = asio::ip::udp::endpoint(addr, port); |
581 | } |
582 | } |
583 | |
584 | #endif // !defined(BOOST_LOG_NO_ASIO) |
585 | |
586 | } // namespace sinks |
587 | |
588 | BOOST_LOG_CLOSE_NAMESPACE // namespace log |
589 | |
590 | } // namespace boost |
591 | |
592 | #include <boost/log/detail/footer.hpp> |
593 | |
594 | #endif // !defined(BOOST_LOG_WITHOUT_SYSLOG) |
595 | |