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.hpp
9  * \author Andrey Semashev
10  * \date   08.01.2008
11  *
12  * The header contains implementation of a Syslog sink backend along with its setup facilities.
13  */
14 
15 #ifndef BOOST_LOG_SINKS_SYSLOG_BACKEND_HPP_INCLUDED_
16 #define BOOST_LOG_SINKS_SYSLOG_BACKEND_HPP_INCLUDED_
17 
18 #include <boost/log/detail/config.hpp>
19 
20 #ifdef BOOST_HAS_PRAGMA_ONCE
21 #pragma once
22 #endif
23 
24 #ifndef BOOST_LOG_WITHOUT_SYSLOG
25 
26 #include <string>
27 #include <boost/log/detail/asio_fwd.hpp>
28 #include <boost/log/detail/light_function.hpp>
29 #include <boost/log/detail/parameter_tools.hpp>
30 #include <boost/log/sinks/basic_sink_backend.hpp>
31 #include <boost/log/sinks/syslog_constants.hpp>
32 #include <boost/log/sinks/attribute_mapping.hpp>
33 #include <boost/log/attributes/attribute_value_set.hpp>
34 #include <boost/log/keywords/facility.hpp>
35 #include <boost/log/keywords/use_impl.hpp>
36 #include <boost/log/keywords/ident.hpp>
37 #include <boost/log/keywords/ip_version.hpp>
38 #include <boost/log/detail/header.hpp>
39 
40 namespace boost {
41 
42 BOOST_LOG_OPEN_NAMESPACE
43 
44 namespace sinks {
45 
46 //! Supported IP protocol versions
47 enum ip_versions
48 {
49     v4,
50     v6
51 };
52 
53 namespace syslog {
54 
55     //! The enumeration defined the possible implementation types for the syslog backend
56     enum impl_types
57     {
58 #ifdef BOOST_LOG_USE_NATIVE_SYSLOG
59         native = 0                  //!< Use native syslog API
60 #ifndef BOOST_LOG_NO_ASIO
61         ,
62 #endif
63 #endif
64 #ifndef BOOST_LOG_NO_ASIO
65         udp_socket_based = 1        //!< Use UDP sockets, according to RFC3164
66 #endif
67     };
68 
69     /*!
70      * \brief Straightforward severity level mapping
71      *
72      * This type of mapping assumes that attribute with a particular name always
73      * provides values that map directly onto the Syslog levels. The mapping
74      * simply returns the extracted attribute value converted to the Syslog severity level.
75      */
76     template< typename AttributeValueT = int >
77     class direct_severity_mapping :
78         public basic_direct_mapping< level, AttributeValueT >
79     {
80         //! Base type
81         typedef basic_direct_mapping< level, AttributeValueT > base_type;
82 
83     public:
84         /*!
85          * Constructor
86          *
87          * \param name Attribute name
88          */
direct_severity_mapping(attribute_name const & name)89         explicit direct_severity_mapping(attribute_name const& name) :
90             base_type(name, info)
91         {
92         }
93     };
94 
95     /*!
96      * \brief Customizable severity level mapping
97      *
98      * The class allows to setup a custom mapping between an attribute and Syslog severity levels.
99      * The mapping should be initialized similarly to the standard \c map container, by using
100      * indexing operator and assignment.
101      */
102     template< typename AttributeValueT = int >
103     class custom_severity_mapping :
104         public basic_custom_mapping< level, AttributeValueT >
105     {
106         //! Base type
107         typedef basic_custom_mapping< level, AttributeValueT > base_type;
108 
109     public:
110         /*!
111          * Constructor
112          *
113          * \param name Attribute name
114          */
custom_severity_mapping(attribute_name const & name)115         explicit custom_severity_mapping(attribute_name const& name) :
116             base_type(name, info)
117         {
118         }
119     };
120 
121 } // namespace syslog
122 
123 /*!
124  * \brief An implementation of a syslog sink backend
125  *
126  * The backend provides support for the syslog protocol, defined in RFC3164.
127  * The backend sends log records to a remote host via UDP. The host name can
128  * be specified by calling the \c set_target_address method. By default log
129  * records will be sent to localhost:514. The local address can be specified
130  * as well, by calling the \c set_local_address method. By default syslog
131  * packets will be sent from any local address available.
132  *
133  * It is safe to create several sink backends with the same local addresses -
134  * the backends within the process will share the same socket. The same applies
135  * to different processes that use the syslog backends to send records from
136  * the same socket. However, it is not guaranteed to work if some third party
137  * facility is using the socket.
138  *
139  * On systems with native syslog implementation it may be preferable to utilize
140  * the POSIX syslog API instead of direct socket management in order to bypass
141  * possible security limitations that may be in action. To do so one has to pass
142  * the <tt>use_impl = native</tt> to the backend constructor. Note, however,
143  * that in that case you will only have one chance to specify syslog facility and
144  * process identification string - on the first native syslog backend construction.
145  * Other native syslog backends will ignore these parameters.
146  * Obviously, the \c set_local_address and \c set_target_address
147  * methods have no effect for native backends. Using <tt>use_impl = native</tt>
148  * on platforms with no native support for POSIX syslog API will have no effect.
149  */
150 class syslog_backend :
151     public basic_formatted_sink_backend< char >
152 {
153     //! Base type
154     typedef basic_formatted_sink_backend< char > base_type;
155     //! Implementation type
156     struct implementation;
157 
158 public:
159     //! Character type
160     typedef base_type::char_type char_type;
161     //! String type that is used to pass message test
162     typedef base_type::string_type string_type;
163 
164     //! Syslog severity level mapper type
165     typedef boost::log::aux::light_function< syslog::level (record_view const&) > severity_mapper_type;
166 
167 private:
168     //! Pointer to the implementation
169     implementation* m_pImpl;
170 
171 public:
172     /*!
173      * Constructor. Creates a UDP socket-based backend with <tt>syslog::user</tt> facility code.
174      * IPv4 protocol will be used.
175      */
176     BOOST_LOG_API syslog_backend();
177     /*!
178      * Constructor. Creates a sink backend with the specified named parameters.
179      * The following named parameters are supported:
180      *
181      * \li \c facility - Specifies the facility code. If not specified, <tt>syslog::user</tt> will be used.
182      * \li \c use_impl - Specifies the backend implementation. Can be one of:
183      *                   \li \c native - Use the native syslog API, if available. If no native API
184      *                                   is available, it is equivalent to \c udp_socket_based.
185      *                   \li \c udp_socket_based - Use the UDP socket-based implementation, conforming to
186      *                                             RFC3164 protocol specification. This is the default.
187      * \li \c ip_version - Specifies IP protocol version to use, in case if socket-based implementation
188      *                     is used. Can be either \c v4 (the default one) or \c v6.
189      * \li \c ident - Process identification string. This parameter is only supported by native syslog implementation.
190      */
191 #ifndef BOOST_LOG_DOXYGEN_PASS
192     BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_CALL(syslog_backend, construct)
193 #else
194     template< typename... ArgsT >
195     explicit syslog_backend(ArgsT... const& args);
196 #endif
197 
198     /*!
199      * Destructor
200      */
201     BOOST_LOG_API ~syslog_backend();
202 
203     /*!
204      * The method installs the function object that maps application severity levels to syslog levels
205      */
206     BOOST_LOG_API void set_severity_mapper(severity_mapper_type const& mapper);
207 
208 #if !defined(BOOST_LOG_NO_ASIO)
209 
210     /*!
211      * The method sets the local host name which log records will be sent from. The host name
212      * is resolved to obtain the final IP address.
213      *
214      * \note Does not have effect if the backend was constructed to use native syslog API
215      *
216      * \param addr The local address
217      * \param port The local port number
218      */
219     BOOST_LOG_API void set_local_address(std::string const& addr, unsigned short port = 514);
220     /*!
221      * The method sets the local address which log records will be sent from.
222      *
223      * \note Does not have effect if the backend was constructed to use native syslog API
224      *
225      * \param addr The local address
226      * \param port The local port number
227      */
228     BOOST_LOG_API void set_local_address(boost::asio::ip::address const& addr, unsigned short port = 514);
229 
230     /*!
231      * The method sets the remote host name where log records will be sent to. The host name
232      * is resolved to obtain the final IP address.
233      *
234      * \note Does not have effect if the backend was constructed to use native syslog API
235      *
236      * \param addr The remote host address
237      * \param port The port number on the remote host
238      */
239     BOOST_LOG_API void set_target_address(std::string const& addr, unsigned short port = 514);
240     /*!
241      * The method sets the address of the remote host where log records will be sent to.
242      *
243      * \note Does not have effect if the backend was constructed to use native syslog API
244      *
245      * \param addr The remote host address
246      * \param port The port number on the remote host
247      */
248     BOOST_LOG_API void set_target_address(boost::asio::ip::address const& addr, unsigned short port = 514);
249 
250 #endif // !defined(BOOST_LOG_NO_ASIO)
251 
252     /*!
253      * The method passes the formatted message to the syslog API or sends to a syslog server
254      */
255     BOOST_LOG_API void consume(record_view const& rec, string_type const& formatted_message);
256 
257 private:
258 #ifndef BOOST_LOG_DOXYGEN_PASS
259     //! The method creates the backend implementation
260     template< typename ArgsT >
construct(ArgsT const & args)261     void construct(ArgsT const& args)
262     {
263         construct(
264             args[keywords::facility | syslog::user],
265 #if !defined(BOOST_LOG_NO_ASIO)
266             args[keywords::use_impl | syslog::udp_socket_based],
267 #else
268             args[keywords::use_impl | syslog::native],
269 #endif
270             args[keywords::ip_version | v4],
271             args[keywords::ident | std::string()]);
272     }
273     BOOST_LOG_API void construct(
274         syslog::facility facility, syslog::impl_types use_impl, ip_versions ip_version, std::string const& ident);
275 #endif // BOOST_LOG_DOXYGEN_PASS
276 };
277 
278 } // namespace sinks
279 
280 BOOST_LOG_CLOSE_NAMESPACE // namespace log
281 
282 } // namespace boost
283 
284 #include <boost/log/detail/footer.hpp>
285 
286 #endif // BOOST_LOG_WITHOUT_SYSLOG
287 
288 #endif // BOOST_LOG_SINKS_SYSLOG_BACKEND_HPP_INCLUDED_
289