autorid: introduce idmap_autorid_domsid_is_for_alloc()
[Samba.git] / ctdb / common / ctdb_logging.c
blobba3e8610c5dddcd5c4e6f80dcae384ba76a9ad1a
1 /*
2 ctdb logging code
4 Copyright (C) Ronnie Sahlberg 2009
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "tdb.h"
22 #include "system/time.h"
23 #include "../include/ctdb_private.h"
24 #include "../include/ctdb_client.h"
26 int log_ringbuf_size;
28 #define MAX_LOG_SIZE 128
30 static int first_entry = 0;
31 static int ringbuf_count = 0;
33 struct ctdb_log_entry {
34 int32_t level;
35 struct timeval t;
36 char message[MAX_LOG_SIZE];
40 static struct ctdb_log_entry *log_entries;
43 * this function logs all messages for all levels to a ringbuffer
45 static void log_ringbuffer_v(const char *format, va_list ap)
47 int ret;
48 int next_entry;
50 if (log_entries == NULL && log_ringbuf_size != 0) {
51 /* Hope this works. We cant log anything if it doesnt anyway */
52 log_entries = malloc(sizeof(struct ctdb_log_entry) * log_ringbuf_size);
54 if (log_entries == NULL) {
55 return;
58 next_entry = (first_entry + ringbuf_count) % log_ringbuf_size;
60 if (ringbuf_count > 0 && first_entry == next_entry) {
61 first_entry = (first_entry + 1) % log_ringbuf_size;
64 log_entries[next_entry].message[0] = '\0';
66 ret = vsnprintf(&log_entries[next_entry].message[0], MAX_LOG_SIZE, format, ap);
67 if (ret == -1) {
68 return;
70 /* Log messages longer than MAX_LOG_SIZE are truncated to MAX_LOG_SIZE-1
71 * bytes. In that case, add a newline.
73 if (ret >= MAX_LOG_SIZE) {
74 log_entries[next_entry].message[MAX_LOG_SIZE-2] = '\n';
77 log_entries[next_entry].level = this_log_level;
78 log_entries[next_entry].t = timeval_current();
80 if (ringbuf_count < log_ringbuf_size) {
81 ringbuf_count++;
85 void log_ringbuffer(const char *format, ...)
87 va_list ap;
89 va_start(ap, format);
90 log_ringbuffer_v(format, ap);
91 va_end(ap);
94 void ctdb_log_ringbuffer_free(void)
96 if (log_entries != NULL) {
97 free(log_entries);
98 log_entries = NULL;
100 log_ringbuf_size = 0;
103 void ctdb_collect_log(struct ctdb_context *ctdb, struct ctdb_get_log_addr *log_addr)
105 TDB_DATA data;
106 FILE *f;
107 long fsize;
108 int tmp_entry;
109 struct tm *tm;
110 char tbuf[100];
111 int i;
113 DEBUG(DEBUG_ERR,("Marshalling %d log entries\n", ringbuf_count));
115 /* dump to a file, then send the file as a blob */
116 f = tmpfile();
117 if (f == NULL) {
118 DEBUG(DEBUG_ERR,(__location__ " Unable to open tmpfile - %s\n", strerror(errno)));
119 return;
122 for (i=0; i<ringbuf_count; i++) {
123 tmp_entry = (first_entry + i) % log_ringbuf_size;
125 if (log_entries[tmp_entry].level > log_addr->level) {
126 continue;
129 tm = localtime(&log_entries[tmp_entry].t.tv_sec);
130 strftime(tbuf, sizeof(tbuf)-1,"%Y/%m/%d %H:%M:%S", tm);
132 if (log_entries[tmp_entry].message[0] != '\0') {
133 fprintf(f, "%s:%s %s", tbuf,
134 get_debug_by_level(log_entries[tmp_entry].level),
135 log_entries[tmp_entry].message);
139 fsize = ftell(f);
140 if (fsize < 0) {
141 fclose(f);
142 DEBUG(DEBUG_ERR, ("Cannot get file size for log entries\n"));
143 return;
145 rewind(f);
146 data.dptr = talloc_size(NULL, fsize);
147 if (data.dptr == NULL) {
148 fclose(f);
149 CTDB_NO_MEMORY_VOID(ctdb, data.dptr);
151 data.dsize = fread(data.dptr, 1, fsize, f);
152 fclose(f);
154 DEBUG(DEBUG_ERR,("Marshalling log entries into a blob of %d bytes\n", (int)data.dsize));
156 DEBUG(DEBUG_ERR,("Send log to %d:%d\n", (int)log_addr->pnn, (int)log_addr->srvid));
157 ctdb_client_send_message(ctdb, log_addr->pnn, log_addr->srvid, data);
159 talloc_free(data.dptr);
162 int32_t ctdb_control_get_log(struct ctdb_context *ctdb, TDB_DATA addr)
164 struct ctdb_get_log_addr *log_addr = (struct ctdb_get_log_addr *)addr.dptr;
165 pid_t child;
167 /* spawn a child process to marshall the huge log blob and send it back
168 to the ctdb tool using a MESSAGE
170 child = ctdb_fork_no_free_ringbuffer(ctdb);
171 if (child == (pid_t)-1) {
172 DEBUG(DEBUG_ERR,("Failed to fork a log collector child\n"));
173 return -1;
176 if (child == 0) {
177 ctdb_set_process_name("ctdb_log_collector");
178 if (switch_from_server_to_client(ctdb, "log-collector") != 0) {
179 DEBUG(DEBUG_CRIT, (__location__ "ERROR: failed to switch log collector child into client mode.\n"));
180 _exit(1);
182 ctdb_collect_log(ctdb, log_addr);
183 _exit(0);
186 return 0;
189 void ctdb_clear_log(struct ctdb_context *ctdb)
191 first_entry = 0;
192 ringbuf_count = 0;
195 int32_t ctdb_control_clear_log(struct ctdb_context *ctdb)
197 ctdb_clear_log(ctdb);
199 return 0;