2 ctdb logging code - syslog backend
4 Copyright (C) Andrew Tridgell 2008
5 Copyright (C) Martin Schwenke 2014
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "system/network.h"
23 #include "system/syslog.h"
25 #include "lib/util/debug.h"
26 #include "lib/util/blocking.h"
27 #include "lib/util/time_basic.h"
28 #include "lib/util/samba_util.h" /* get_myname */
30 #include "ctdb_private.h"
32 #include "common/logging.h"
34 /* Linux and FreeBSD define this appropriately - try good old /dev/log
35 * for anything that doesn't... */
37 #define _PATH_LOG "/dev/log"
40 #define CTDB_LOG_SYSLOG_PREFIX "syslog"
41 #define CTDB_SYSLOG_FACILITY LOG_USER
43 struct ctdb_syslog_sock_state
{
47 int (*format
)(int dbglevel
, struct ctdb_syslog_sock_state
*state
,
48 const char *str
, char *buf
, int bsize
);
51 /**********************************************************************/
53 static int ctdb_debug_to_syslog_level(int dbglevel
)
78 /**********************************************************************/
80 /* Format messages as per RFC3164. */
82 /* It appears that some syslog daemon implementations do not allow a
83 * hostname when messages are sent via a Unix domain socket, so omit
84 * it. Similarly, syslogd on FreeBSD does not understand the hostname
85 * part of the header, even when logging via UDP. Note that most
86 * implementations will log messages against "localhost" when logging
87 * via UDP. A timestamp could be sent but rsyslogd on Linux limits
88 * the timestamp logged to the precision that was received on
89 * /dev/log. It seems sane to send degenerate RFC3164 messages
90 * without a header at all, so that the daemon will generate high
91 * resolution timestamps if configured. */
92 static int format_rfc3164(int dbglevel
, struct ctdb_syslog_sock_state
*state
,
93 const char *str
, char *buf
, int bsize
)
98 pri
= CTDB_SYSLOG_FACILITY
| ctdb_debug_to_syslog_level(dbglevel
);
99 len
= snprintf(buf
, bsize
, "<%d>%s[%u]: %s%s",
100 pri
, state
->app_name
, getpid(), debug_extra
, str
);
101 len
= MIN(len
, bsize
- 1);
106 /* Format messages as per RFC5424
108 * <165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1
109 * myproc 8710 - - %% It's time to make the do-nuts.
111 static int format_rfc5424(int dbglevel
, struct ctdb_syslog_sock_state
*state
,
112 const char *str
, char *buf
, int bsize
)
116 struct timeval_buf tvbuf
;
120 pri
= CTDB_SYSLOG_FACILITY
| ctdb_debug_to_syslog_level(dbglevel
);
122 len
= snprintf(buf
, bsize
,
123 "<%d>1 %s %s %s %u - - ",
124 pri
, timeval_str_buf(&tv
, true, true, &tvbuf
),
125 state
->hostname
, state
->app_name
, getpid());
126 /* A truncated header is not useful... */
132 s
= snprintf(&buf
[len
], bsize
- len
, "%s %s", debug_extra
, str
);
133 len
= MIN(len
+ s
, bsize
- 1);
138 /**********************************************************************/
140 /* Non-blocking logging */
142 static void ctdb_log_to_syslog_sock(void *private_ptr
,
143 int dbglevel
, const char *str
)
145 struct ctdb_syslog_sock_state
*state
= talloc_get_type(
146 private_ptr
, struct ctdb_syslog_sock_state
);
148 /* RFC3164 says: The total length of the packet MUST be 1024
153 n
= state
->format(dbglevel
, state
, str
, buf
, sizeof(buf
));
155 fprintf(stderr
, "Failed to format syslog message %s\n", str
);
159 /* Could extend this to count failures, which probably
160 * indicate dropped messages due to EAGAIN or EWOULDBLOCK */
161 (void)send(state
->fd
, buf
, n
, 0);
165 ctdb_syslog_sock_state_destructor(struct ctdb_syslog_sock_state
*state
)
167 if (state
->fd
!= -1) {
174 static struct ctdb_syslog_sock_state
*
175 ctdb_log_setup_syslog_common(TALLOC_CTX
*mem_ctx
,
176 const char *app_name
)
178 struct ctdb_syslog_sock_state
*state
;
180 state
= talloc_zero(mem_ctx
, struct ctdb_syslog_sock_state
);
185 state
->app_name
= app_name
;
186 talloc_set_destructor(state
, ctdb_syslog_sock_state_destructor
);
191 static int ctdb_log_setup_syslog_un(TALLOC_CTX
*mem_ctx
,
192 const char *app_name
)
194 struct ctdb_syslog_sock_state
*state
;
195 struct sockaddr_un dest
;
198 state
= ctdb_log_setup_syslog_common(mem_ctx
, app_name
);
203 state
->fd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
204 if (state
->fd
== -1) {
205 int save_errno
= errno
;
210 dest
.sun_family
= AF_UNIX
;
211 strncpy(dest
.sun_path
, _PATH_LOG
, sizeof(dest
.sun_path
)-1);
212 ret
= connect(state
->fd
,
213 (struct sockaddr
*)&dest
, sizeof(dest
));
215 int save_errno
= errno
;
219 set_blocking(state
->fd
, false);
221 state
->hostname
= NULL
; /* Make this explicit */
222 state
->format
= format_rfc3164
;
224 debug_set_callback(state
, ctdb_log_to_syslog_sock
);
229 static int ctdb_log_setup_syslog_udp(TALLOC_CTX
*mem_ctx
,
230 const char *app_name
,
233 struct ctdb_syslog_sock_state
*state
;
234 struct sockaddr_in dest
;
237 state
= ctdb_log_setup_syslog_common(mem_ctx
, app_name
);
242 state
->fd
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
243 if (state
->fd
== -1) {
244 int save_errno
= errno
;
249 dest
.sin_family
= AF_INET
;
250 dest
.sin_port
= htons(514);
251 dest
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
252 ret
= connect(state
->fd
,
253 (struct sockaddr
*)&dest
, sizeof(dest
));
255 int save_errno
= errno
;
260 state
->hostname
= get_myname(state
);
261 if (state
->hostname
== NULL
) {
262 /* Use a fallback instead of failing initialisation */
263 state
->hostname
= "localhost";
266 state
->format
= format_rfc5424
;
268 state
->format
= format_rfc3164
;
271 debug_set_callback(state
, ctdb_log_to_syslog_sock
);
276 /**********************************************************************/
278 static void ctdb_log_to_syslog(void *private_ptr
, int dbglevel
, const char *s
)
280 syslog(ctdb_debug_to_syslog_level(dbglevel
),
281 "%s%s", debug_extra
, s
);
284 static int ctdb_log_setup_syslog(TALLOC_CTX
*mem_ctx
,
286 const char *app_name
)
288 size_t l
= strlen(CTDB_LOG_SYSLOG_PREFIX
);
290 if (logging
[l
] != '\0') {
291 /* Handle non-blocking extensions here */
294 if (logging
[l
] != ':') {
297 method
= &logging
[0] + l
+ 1;
298 if (strcmp(method
, "nonblocking") == 0) {
299 ctdb_log_setup_syslog_un(mem_ctx
, app_name
);
302 if (strcmp(method
, "udp") == 0) {
303 ctdb_log_setup_syslog_udp(mem_ctx
, app_name
, false);
306 if (strcmp(method
, "udp-rfc5424") == 0) {
307 ctdb_log_setup_syslog_udp(mem_ctx
, app_name
, true);
314 debug_set_callback(NULL
, ctdb_log_to_syslog
);
318 void ctdb_log_init_syslog(void)
320 ctdb_log_register_backend(CTDB_LOG_SYSLOG_PREFIX
,
321 ctdb_log_setup_syslog
);