uwrap: Add mutex in uwrap_destructor().
[Samba.git] / ctdb / common / ctdb_logging.c
blob6dd1a385daabab5d8f4a4ad8ce393607636a705c
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 LogLevel = DEBUG_NOTICE;
27 int this_log_level = 0;
29 int log_ringbuf_size;
31 #define MAX_LOG_SIZE 128
33 static int first_entry = 0;
34 static int ringbuf_count = 0;
36 struct ctdb_log_entry {
37 int32_t level;
38 struct timeval t;
39 char message[MAX_LOG_SIZE];
43 static struct ctdb_log_entry *log_entries;
46 * this function logs all messages for all levels to a ringbuffer
48 static void log_ringbuffer_v(const char *format, va_list ap)
50 int ret;
51 int next_entry;
53 if (log_entries == NULL && log_ringbuf_size != 0) {
54 /* Hope this works. We cant log anything if it doesnt anyway */
55 log_entries = malloc(sizeof(struct ctdb_log_entry) * log_ringbuf_size);
57 if (log_entries == NULL) {
58 return;
61 next_entry = (first_entry + ringbuf_count) % log_ringbuf_size;
63 if (ringbuf_count > 0 && first_entry == next_entry) {
64 first_entry = (first_entry + 1) % log_ringbuf_size;
67 log_entries[next_entry].message[0] = '\0';
69 ret = vsnprintf(&log_entries[next_entry].message[0], MAX_LOG_SIZE, format, ap);
70 if (ret == -1) {
71 return;
73 /* Log messages longer than MAX_LOG_SIZE are truncated to MAX_LOG_SIZE-1
74 * bytes. In that case, add a newline.
76 if (ret >= MAX_LOG_SIZE) {
77 log_entries[next_entry].message[MAX_LOG_SIZE-2] = '\n';
80 log_entries[next_entry].level = this_log_level;
81 log_entries[next_entry].t = timeval_current();
83 if (ringbuf_count < log_ringbuf_size) {
84 ringbuf_count++;
88 void log_ringbuffer(const char *format, ...)
90 va_list ap;
92 va_start(ap, format);
93 log_ringbuffer_v(format, ap);
94 va_end(ap);
97 void ctdb_log_ringbuffer_free(void)
99 if (log_entries != NULL) {
100 free(log_entries);
101 log_entries = NULL;
103 log_ringbuf_size = 0;
106 TDB_DATA ctdb_log_ringbuffer_collect_log(TALLOC_CTX *mem_ctx,
107 enum debug_level max_level)
109 TDB_DATA data;
110 FILE *f;
111 long fsize;
112 int tmp_entry;
113 struct tm *tm;
114 char tbuf[100];
115 int i;
117 DEBUG(DEBUG_ERR,("Marshalling %d log entries\n", ringbuf_count));
119 /* dump to a file, then send the file as a blob */
120 f = tmpfile();
121 if (f == NULL) {
122 DEBUG(DEBUG_ERR,(__location__ " Unable to open tmpfile - %s\n",
123 strerror(errno)));
124 return tdb_null;
127 for (i=0; i<ringbuf_count; i++) {
128 tmp_entry = (first_entry + i) % log_ringbuf_size;
130 if (log_entries[tmp_entry].level > max_level) {
131 continue;
134 tm = localtime(&log_entries[tmp_entry].t.tv_sec);
135 strftime(tbuf, sizeof(tbuf)-1,"%Y/%m/%d %H:%M:%S", tm);
137 if (log_entries[tmp_entry].message[0] != '\0') {
138 fprintf(f, "%s:%s %s", tbuf,
139 get_debug_by_level(log_entries[tmp_entry].level),
140 log_entries[tmp_entry].message);
144 fsize = ftell(f);
145 if (fsize < 0) {
146 fclose(f);
147 DEBUG(DEBUG_ERR, ("Cannot get file size for log entries\n"));
148 return tdb_null;
150 rewind(f);
151 data.dptr = talloc_size(NULL, fsize);
152 if (data.dptr == NULL) {
153 fclose(f);
154 DEBUG(DEBUG_ERR, (__location__ " Memory allocation error\n"));
155 return tdb_null;
157 data.dsize = fread(data.dptr, 1, fsize, f);
158 fclose(f);
160 DEBUG(DEBUG_ERR,("Marshalling log entries into a blob of %d bytes\n", (int)data.dsize));
162 return data;
165 void ctdb_clear_log(struct ctdb_context *ctdb)
167 first_entry = 0;
168 ringbuf_count = 0;
171 int32_t ctdb_control_clear_log(struct ctdb_context *ctdb)
173 ctdb_clear_log(ctdb);
175 return 0;
178 struct debug_levels debug_levels[] = {
179 {DEBUG_EMERG, "EMERG"},
180 {DEBUG_ALERT, "ALERT"},
181 {DEBUG_CRIT, "CRIT"},
182 {DEBUG_ERR, "ERR"},
183 {DEBUG_WARNING, "WARNING"},
184 {DEBUG_NOTICE, "NOTICE"},
185 {DEBUG_INFO, "INFO"},
186 {DEBUG_DEBUG, "DEBUG"},
187 {0, NULL}
190 const char *get_debug_by_level(int32_t level)
192 int i;
194 for (i=0; debug_levels[i].description != NULL; i++) {
195 if (debug_levels[i].level == level) {
196 return debug_levels[i].description;
199 return "Unknown";
202 int32_t get_debug_by_desc(const char *desc)
204 int i;
206 for (i=0; debug_levels[i].description != NULL; i++) {
207 if (!strcasecmp(debug_levels[i].description, desc)) {
208 return debug_levels[i].level;
212 return DEBUG_ERR;