a4a9be62b859f4e700e16de348711f94d20443aa
[sahlberg/ctdb.git] / libctdb / test / log.c
1 /*
2
3 This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
4
5 Copyright (c) 2003,2004 Jeremy Kerr & Rusty Russell
6
7 This file is part of nfsim.
8
9 nfsim is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 nfsim is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with nfsim; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 */
23 #include "log.h"
24 #include "tui.h"
25 #include "utils.h"
26 #include "expect.h"
27 #include <string.h>
28 #include <talloc.h>
29
30 static struct {
31         enum log_type   type;
32         char *          name;
33 } log_names[] = {
34         { LOG_WRITE,    "write" },
35         { LOG_READ,     "read" },
36         { LOG_LIB,      "lib" },
37         { LOG_VERBOSE,  "verbose" },
38 };
39
40 static FILE *logstream;
41 static int typemask = ~LOG_VERBOSE;
42
43 bool log_line(enum log_type type, const char *format, ...)
44 {
45         va_list ap;
46         char *line;
47         bool ret;
48
49         va_start(ap, format);
50         line = talloc_vasprintf(NULL, format, ap);
51         va_end(ap);
52
53         if (!type || (type & typemask))
54                 fprintf(logstream ?: stderr, "%s\n", line);
55
56         ret = expect_log_hook(line);
57         talloc_free(line);
58         return ret;
59 }
60
61 static void log_partial_v(enum log_type type,
62                           char *buf,
63                           unsigned bufsize,
64                           const char *format,
65                           va_list ap)
66 {
67         char *ptr;
68         int len = strlen(buf);
69
70         /* write to the end of buffer */
71         if (vsnprintf(buf + len, bufsize - len - 1, format, ap)
72                         > bufsize - len - 1)
73                 log_line(LOG_ALWAYS, "log_line_partial buffer is full!");
74
75         ptr = buf;
76
77         /* print each bit that ends in a newline */
78         for (len = strcspn(ptr, "\n"); *(ptr + len);
79                         ptr += len, len = strcspn(ptr, "\n")) {
80                 log_line(type, "%.*s", len++, ptr);
81         }
82
83         /* if we've printed, copy any remaining (non-newlined)
84            parts (including the \0) to the front of buf */
85         memmove(buf, ptr, strlen(ptr) + 1);
86 }
87
88 void log_partial(enum log_type type, char *buf, unsigned bufsize,
89                  const char *format, ...)
90 {
91         va_list ap;
92
93         va_start(ap, format);
94         log_partial_v(type, buf, bufsize, format, ap);
95         va_end(ap);
96 }
97
98 static inline int parsetype(const char *type)
99 {
100         int i;
101
102         for (i = 0; i < ARRAY_SIZE(log_names); i++)
103                 if (streq(log_names[i].name, type))
104                         return log_names[i].type;
105
106         return 0;
107 }
108
109 static bool log_admin(int argc, char **argv)
110 {
111         int i;
112         int newtypemask = 0;
113
114         if (argc == 1) {
115                 log_line(LOG_UI, "current log types:", typemask);
116
117                 for (i = 0; i < ARRAY_SIZE(log_names); i++) {
118                         if (typemask & log_names[i].type)
119                                 log_line(LOG_UI, "\t%s", log_names[i].name);
120                 }
121                 return true;
122         }
123
124         if (argc == 2) {
125                 log_line(LOG_ALWAYS, "Expected =, + or - then args");
126                 return false;
127         }
128
129         for (i = 2; i < argc; i++) {
130                 int type;
131
132                 if (!(type = parsetype(argv[i]))) {
133                         log_line(LOG_ALWAYS, "no such type %s", argv[i]);
134                         return false;
135                 }
136                 newtypemask |= type;
137         }
138
139         switch (*argv[1]) {
140         case '=':
141                 typemask = newtypemask;
142                 break;
143         case '-':
144                 typemask &= ~newtypemask;
145                 break;
146         case '+':
147                 typemask |= newtypemask;
148                 break;
149         default:
150                 log_line(LOG_ALWAYS, "unknown modifer: %c", *argv[1]);
151                 return false;
152         }
153
154         return true;
155 }
156
157 static void log_admin_help(int agc, char **argv)
158 {
159 #include "generated-log-help:log"
160 /*** XML Help:
161     <section id="c:log">
162      <title><command>log</command></title>
163      <para>Manage logging settings</para>
164      <cmdsynopsis>
165       <command>log</command>
166       <group choice="opt">
167        <arg choice="plain">=</arg>
168        <arg choice="plain">+</arg>
169        <arg choice="plain">-</arg>
170       </group>
171       <arg choice="req"><replaceable>type, ...</replaceable></arg>
172      </cmdsynopsis>
173      <para>Each log message is classified into one of the following
174      types:</para>
175       <varlistentry>
176        <term>UI</term>
177        <listitem>
178         <para>Normal response from command lines.</para>
179        </listitem>
180       </varlistentry>
181       <varlistentry>
182        <term>LIB</term>
183        <listitem>
184         <para>Logging output from libctdb</para>
185        </listitem>
186       </varlistentry>
187      <variablelist>
188       <varlistentry>
189        <term>READ</term>
190        <listitem>
191         <para>Messages from ctdbd</para>
192        </listitem>
193       </varlistentry>
194       <varlistentry>
195        <term>WRITE</term>
196        <listitem>
197         <para>Messages to ctdbd</para>
198        </listitem>
199       </varlistentry>
200       <varlistentry>
201        <term>VERBOSE</term>
202        <listitem>
203         <para>Verbose debug output</para>
204        </listitem>
205       </varlistentry>
206      </variablelist>
207
208      <para>The <command>log</command> command allows you to select
209       which messages are displayed. By default, all messages except
210       debug will be shown.</para>
211
212      <para>Without any arguments, the current logged types are listed.</para>
213
214      <para>With +, - or = character, those types will be added,
215       removed or set as the current types of messages to be logged
216       (repectively).</para>
217
218       <para>Messages generated as a result of user input are always
219       logged.  </para> </section>
220 */
221 }
222
223 static void log_init(void)
224 {
225         logstream = stdout;
226         if (tui_quiet)
227                 typemask = 0;
228         tui_register_command("log", log_admin, log_admin_help);
229 }
230
231 init_call(log_init);