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"
24 #include "lib/util/debug.h"
25 #include "lib/util/blocking.h"
26 #include "lib/util/time_basic.h"
27 #include "lib/util/samba_util.h" /* get_myname */
28 #include "ctdb_logging.h"
30 /* Linux and FreeBSD define this appropriately - try good old /dev/log
31 * for anything that doesn't... */
33 #define _PATH_LOG "/dev/log"
36 #define CTDB_LOG_SYSLOG_PREFIX "syslog"
37 #define CTDB_SYSLOG_FACILITY LOG_USER
39 struct ctdb_syslog_sock_state
{
43 int (*format
)(int dbglevel
, struct ctdb_syslog_sock_state
*state
,
44 const char *str
, char *buf
, int bsize
);
47 /**********************************************************************/
49 static int ctdb_debug_to_syslog_level(int dbglevel
)
74 /**********************************************************************/
76 /* Format messages as per RFC3164. */
78 /* It appears that some syslog daemon implementations do not allow a
79 * hostname when messages are sent via a Unix domain socket, so omit
80 * it. Similarly, syslogd on FreeBSD does not understand the hostname
81 * part of the header, even when logging via UDP. Note that most
82 * implementations will log messages against "localhost" when logging
83 * via UDP. A timestamp could be sent but rsyslogd on Linux limits
84 * the timestamp logged to the precision that was received on
85 * /dev/log. It seems sane to send degenerate RFC3164 messages
86 * without a header at all, so that the daemon will generate high
87 * resolution timestamps if configured. */
88 static int format_rfc3164(int dbglevel
, struct ctdb_syslog_sock_state
*state
,
89 const char *str
, char *buf
, int bsize
)
94 pri
= CTDB_SYSLOG_FACILITY
| ctdb_debug_to_syslog_level(dbglevel
);
95 len
= snprintf(buf
, bsize
, "<%d>%s[%u]: %s%s",
96 pri
, state
->app_name
, getpid(), debug_extra
, str
);
97 len
= MIN(len
, bsize
- 1);
102 /* Format messages as per RFC5424
104 * <165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1
105 * myproc 8710 - - %% It's time to make the do-nuts.
107 static int format_rfc5424(int dbglevel
, struct ctdb_syslog_sock_state
*state
,
108 const char *str
, char *buf
, int bsize
)
112 struct timeval_buf tvbuf
;
116 pri
= CTDB_SYSLOG_FACILITY
| ctdb_debug_to_syslog_level(dbglevel
);
118 len
= snprintf(buf
, bsize
,
119 "<%d>1 %s %s %s %u - - ",
120 pri
, timeval_str_buf(&tv
, true, true, &tvbuf
),
121 state
->hostname
, state
->app_name
, getpid());
122 /* A truncated header is not useful... */
128 s
= snprintf(&buf
[len
], bsize
- len
, "%s %s", debug_extra
, str
);
129 len
= MIN(len
+ s
, bsize
- 1);
134 /**********************************************************************/
136 /* Non-blocking logging */
138 static void ctdb_log_to_syslog_sock(void *private_ptr
,
139 int dbglevel
, const char *str
)
141 struct ctdb_syslog_sock_state
*state
= talloc_get_type(
142 private_ptr
, struct ctdb_syslog_sock_state
);
144 /* RFC3164 says: The total length of the packet MUST be 1024
149 n
= state
->format(dbglevel
, state
, str
, buf
, sizeof(buf
));
151 fprintf(stderr
, "Failed to format syslog message %s\n", str
);
155 /* Could extend this to count failures, which probably
156 * indicate dropped messages due to EAGAIN or EWOULDBLOCK */
157 (void)send(state
->fd
, buf
, n
, 0);
161 ctdb_syslog_sock_state_destructor(struct ctdb_syslog_sock_state
*state
)
163 if (state
->fd
!= -1) {
170 static struct ctdb_syslog_sock_state
*
171 ctdb_log_setup_syslog_common(TALLOC_CTX
*mem_ctx
,
172 const char *app_name
)
174 struct ctdb_syslog_sock_state
*state
;
176 state
= talloc_zero(mem_ctx
, struct ctdb_syslog_sock_state
);
181 state
->app_name
= app_name
;
182 talloc_set_destructor(state
, ctdb_syslog_sock_state_destructor
);
187 static int ctdb_log_setup_syslog_un(TALLOC_CTX
*mem_ctx
,
188 const char *app_name
)
190 struct ctdb_syslog_sock_state
*state
;
191 struct sockaddr_un dest
;
194 state
= ctdb_log_setup_syslog_common(mem_ctx
, app_name
);
199 state
->fd
= socket(AF_UNIX
, SOCK_DGRAM
, 0);
200 if (state
->fd
== -1) {
201 int save_errno
= errno
;
206 dest
.sun_family
= AF_UNIX
;
207 strncpy(dest
.sun_path
, _PATH_LOG
, sizeof(dest
.sun_path
)-1);
208 ret
= connect(state
->fd
,
209 (struct sockaddr
*)&dest
, sizeof(dest
));
211 int save_errno
= errno
;
215 set_blocking(state
->fd
, false);
217 state
->hostname
= NULL
; /* Make this explicit */
218 state
->format
= format_rfc3164
;
220 debug_set_callback(state
, ctdb_log_to_syslog_sock
);
225 static int ctdb_log_setup_syslog_udp(TALLOC_CTX
*mem_ctx
,
226 const char *app_name
,
229 struct ctdb_syslog_sock_state
*state
;
230 struct sockaddr_in dest
;
233 state
= ctdb_log_setup_syslog_common(mem_ctx
, app_name
);
238 state
->fd
= socket(AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
);
239 if (state
->fd
== -1) {
240 int save_errno
= errno
;
245 dest
.sin_family
= AF_INET
;
246 dest
.sin_port
= htons(514);
247 dest
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
248 ret
= connect(state
->fd
,
249 (struct sockaddr
*)&dest
, sizeof(dest
));
251 int save_errno
= errno
;
256 state
->hostname
= get_myname(state
);
257 if (state
->hostname
== NULL
) {
258 /* Use a fallback instead of failing initialisation */
259 state
->hostname
= "localhost";
262 state
->format
= format_rfc5424
;
264 state
->format
= format_rfc3164
;
267 debug_set_callback(state
, ctdb_log_to_syslog_sock
);
272 /**********************************************************************/
274 static void ctdb_log_to_syslog(void *private_ptr
, int dbglevel
, const char *s
)
276 syslog(ctdb_debug_to_syslog_level(dbglevel
),
277 "%s%s", debug_extra
, s
);
280 static int ctdb_log_setup_syslog(TALLOC_CTX
*mem_ctx
,
282 const char *app_name
)
284 size_t l
= strlen(CTDB_LOG_SYSLOG_PREFIX
);
286 if (logging
[l
] != '\0') {
287 /* Handle non-blocking extensions here */
290 if (logging
[l
] != ':') {
293 method
= &logging
[0] + l
+ 1;
294 if (strcmp(method
, "nonblocking") == 0) {
295 ctdb_log_setup_syslog_un(mem_ctx
, app_name
);
298 if (strcmp(method
, "udp") == 0) {
299 ctdb_log_setup_syslog_udp(mem_ctx
, app_name
, false);
302 if (strcmp(method
, "udp-rfc5424") == 0) {
303 ctdb_log_setup_syslog_udp(mem_ctx
, app_name
, true);
310 debug_set_callback(NULL
, ctdb_log_to_syslog
);
314 void ctdb_log_init_syslog(void)
316 ctdb_log_register_backend(CTDB_LOG_SYSLOG_PREFIX
,
317 ctdb_log_setup_syslog
);