Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

gdp / gdplogd / logd_admin.c @ master

History | View | Annotate | Download (7.75 KB)

1 a0469464 Eric Allman
/* vim: set ai sw=4 sts=4 ts=4 :*/
2
3
/*
4
**        ----- BEGIN LICENSE BLOCK -----
5 897accec Eric Allman
**        GDPLOGD: Log Daemon for the Global Data Plane
6 a0469464 Eric Allman
**        From the Ubiquitous Swarm Lab, 490 Cory Hall, U.C. Berkeley.
7
**
8 c87dd166 Eric Allman
**        Copyright (c) 2015-2019, Regents of the University of California.
9 a0469464 Eric Allman
**        All rights reserved.
10
**
11
**        Permission is hereby granted, without written agreement and without
12
**        license or royalty fees, to use, copy, modify, and distribute this
13
**        software and its documentation for any purpose, provided that the above
14
**        copyright notice and the following two paragraphs appear in all copies
15
**        of this software.
16
**
17
**        IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
18
**        SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
19
**        PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
20
**        EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21
**
22
**        REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
23
**        LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24
**        FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION,
25
**        IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO
26
**        OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
27
**        OR MODIFICATIONS.
28
**        ----- END LICENSE BLOCK -----
29
*/
30
31
32
/*
33
**  This file has support for GDP log server administration
34
*/
35
36
#include "logd_admin.h"
37 92243bf4 Eric Allman
#include "logd_sqlite.h"
38 a0469464 Eric Allman
39
#include <gdp/gdp.h>
40
#include <gdp/gdp_priv.h>
41
42 11029b9c Eric Allman
#include <ep/ep_dbg.h>
43 a0469464 Eric Allman
#include <ep/ep_xlate.h>
44
45
#include <stdarg.h>
46
#include <string.h>
47
#include <syslog.h>
48
49 5da0351b Eric Allman
#include <sys/errno.h>
50
#include <sys/stat.h>
51
52 11029b9c Eric Allman
static EP_DBG        Dbg = EP_DBG_INIT("gdplogd.admin", "GDP administrative logging");
53
54 a0469464 Eric Allman
/*
55
**        ADMIN_POST --- post statistics for system visualization
56
**
57
**                This always produces parsable output.
58
*/
59
60
61 5da0351b Eric Allman
static const char        *AdminStatsFileName = NULL;
62
static ino_t                AdminStatsIno = -1;
63 a0469464 Eric Allman
static FILE                        *AdminStatsFp;
64
static uint32_t                AdminRunMask = 0xffffffff;
65 58292089 Eric Allman
static const char        *AdminPrefix = "";
66 d1ba7cd7 Eric Allman
static bool                        AdminInitialized = false;
67 11029b9c Eric Allman
static EP_THR_MUTEX        AdminProbeMutex                EP_THR_MUTEX_INITIALIZER;
68 d9924104 Eric Allman
69
// a prefix to indicate that this is an admin message (stdout & stderr only)
70
#define INDICATOR                ">#<"
71 a0469464 Eric Allman
72
73
/*
74 5da0351b Eric Allman
**  (Re-)Open an output file
75
*/
76
77
static void
78
reopen(const char *fname, FILE **fpp, ino_t *inop)
79
{
80
        FILE *fp;
81
        struct stat st;
82
83
        // open the new version of the file
84
        fp = fopen(fname, "a");
85
        if (fp == NULL)
86
        {
87
                fprintf(stderr, "Cannot open output file \"%s\": %s\n",
88
                                fname, strerror(errno));
89
                return;
90
        }
91
        setlinebuf(fp);
92
93
        // close the old file
94
        if (*fpp != NULL)
95
                fclose(*fpp);
96
97
        // save info for new version of the file
98
        *inop = -1;
99
        if (fstat(fileno(fp), &st) == 0)
100
                *inop = st.st_ino;
101
        *fpp = fp;
102
}
103
104
105
/*
106 a0469464 Eric Allman
**  ADMIN_INIT
107
*/
108
109
extern void                        admin_probe(int, short, void *);
110
111
static void
112
admin_init(void)
113
{
114
        // figure out where to put the output
115
        const char *logdest =
116
                        ep_adm_getstrparam("swarm.gdplogd.admin.output", NULL);
117
        int fd;
118
        char *endp;
119
120 d1ba7cd7 Eric Allman
        // first, avoid calling this multiple times
121
        AdminInitialized = true;
122
123 a0469464 Eric Allman
        if (logdest == NULL || logdest[0] == '\0' ||
124
                        strcasecmp(logdest, "none") == 0)
125
        {
126
                AdminRunMask = 0;
127
                return;
128
        }
129
130
        fd = strtol(logdest, &endp, 10);
131
        if (fd > 0 && *endp == '\0')
132
        {
133
                // pure integer; use as fd
134
                AdminStatsFp = fdopen(fd, "a");
135
        }
136
        else if (strcmp(logdest, "stdout") == 0)
137
        {
138
                AdminStatsFp = stdout;
139 d9924104 Eric Allman
                AdminPrefix = INDICATOR;
140 a0469464 Eric Allman
        }
141
        else if (strcmp(logdest, "stderr") == 0)
142
        {
143
                AdminStatsFp = stderr;
144 d9924104 Eric Allman
                AdminPrefix = INDICATOR;
145 a0469464 Eric Allman
        }
146
        else if (strcmp(logdest, "syslog") == 0)
147
        {
148
                AdminStatsFp = ep_fopen_syslog(LOG_INFO);
149
        }
150
        else
151
        {
152 5da0351b Eric Allman
                reopen(logdest, &AdminStatsFp, &AdminStatsIno);
153
                AdminStatsFileName = logdest;
154 a0469464 Eric Allman
        }
155
156
        // if we couldn't open the file, skip this output
157
        if (AdminStatsFp == NULL)
158
        {
159
                AdminRunMask = 0;
160
                AdminStatsFp = stderr;                        // anything non-NULL
161
                return;
162
        }
163
164
        // arrange to probe logs periodically
165
        long stats_intvl = ep_adm_getlongparam("swarm.gdplogd.admin.probeintvl", 0);
166
167
        if (stats_intvl > 0)
168
        {
169
                struct timeval tv = { stats_intvl, 0 };
170 5a73c6ad Eric Allman
                struct event *evtimer = event_new(_GdpIoEventBase, -1,
171 a0469464 Eric Allman
                                                                        EV_PERSIST, &admin_probe, NULL);
172
                event_add(evtimer, &tv);
173
        }
174
}
175
176
177
/*
178
**  _ADMIN_POST_STATS, _ADMIN_POST_STATSV --- post statistics
179
**
180
**                Parameters:
181
**                        mask --- to allow classification
182
**                        msgid --- to label the statistic
183
**                        ..., av --- a list of name, value pairs.  The name may
184
**                                be NULL to output an unnamed (positional) value.
185
**                                A value of NULL terminates the list.
186
*/
187
188
void
189
admin_post_stats(
190
                uint32_t mask,
191
                const char *msgid,
192
                ...)
193
{
194
        va_list av;
195
196
        va_start(av, msgid);
197
        admin_post_statsv(mask, msgid, av);
198
        va_end(av);
199
}
200
201
void
202
admin_post_statsv(
203
                uint32_t mask,
204
                const char *msgid,
205
                va_list av)
206
{
207
        int argno = 0;
208
        bool firstparam = true;
209
        int xlatemode = EP_XLATE_PLUS | EP_XLATE_NPRINT;
210
        static const char *forbidchars = NULL;
211
        FILE *fp;
212
213 d1ba7cd7 Eric Allman
        if (!AdminInitialized)
214 a0469464 Eric Allman
                admin_init();
215
        if ((mask & AdminRunMask) == 0)
216
                return;
217
        if (forbidchars == NULL)
218
                forbidchars = ep_adm_getstrparam("gdplogd.admin.forbidchars", "=;");
219
220 5da0351b Eric Allman
        // check to see if we need to re-open the output
221
        if (AdminStatsFileName != NULL)
222
        {
223
                struct stat st;
224
225 1b12a638 Eric Allman
                if (stat(AdminStatsFileName, &st) != 0 || st.st_ino != AdminStatsIno)
226 5da0351b Eric Allman
                {
227
                        reopen(AdminStatsFileName, &AdminStatsFp, &AdminStatsIno);
228
                }
229
        }
230
        fp = AdminStatsFp;
231
232 1241e33a Eric Allman
        // make sure this message is atomic
233
        flockfile(fp);
234
235 d9924104 Eric Allman
        // output an initial indicator to make this easy to find
236
        fprintf(fp, "%s", AdminPrefix);
237
238 a0469464 Eric Allman
        // add a timestamp and the message id
239
        {
240
                EP_TIME_SPEC now;
241
                char tbuf[60];
242
243
                ep_time_now(&now);
244
                ep_time_format(&now, tbuf, sizeof tbuf, EP_TIME_FMT_NOFUZZ);
245
                fprintf(fp, "%s ", tbuf);
246
        }
247
248
        (void) ep_xlate_out(msgid,
249
                        strlen(msgid),
250
                        fp,
251
                        forbidchars,
252
                        xlatemode);
253
254
        // scan the arguments
255
        for (;;)
256
        {
257
                const char *apn;
258
                const char *apv;
259
260
                argno++;
261
                apn = va_arg(av, const char *);
262
                if ((apv = va_arg(av, const char *)) == NULL)
263
                        break;
264
265
                if (!firstparam)
266
                        putc(';', fp);
267
                putc(' ', fp);
268
                firstparam = false;
269
270
                if (apn != NULL)
271
                {
272
                        (void) ep_xlate_out(apn,
273
                                        strlen(apn),
274
                                        fp,
275
                                        forbidchars,
276
                                        xlatemode);
277
278
                        putc('=', fp);
279
                }
280
281
                (void) ep_xlate_out(apv,
282
                                strlen(apv),
283
                                fp,
284
                                forbidchars,
285
                                xlatemode);
286
        }
287
        putc('\n', fp);
288 1241e33a Eric Allman
        fflush(fp);
289
        funlockfile(fp);
290 a0469464 Eric Allman
}
291
292
293
/*
294
**  Periodic probe of system status (should probably be in thread)
295
*/
296
297 833b2d3d Eric Allman
static EP_STAT
298 a0469464 Eric Allman
post_one_log(gdp_name_t gdpname, void *ctx)
299
{
300 fec93aac Eric Allman
        gdp_gob_t *gob;
301 a0469464 Eric Allman
        gdp_pname_t gdppname;
302 11029b9c Eric Allman
        EP_STAT estat;
303 a0469464 Eric Allman
304
        gdp_printable_name(gdpname, gdppname);
305 1d6925ca Eric Allman
306 fec93aac Eric Allman
        estat = _gdp_gob_cache_get(gdpname, GGCF_NOCREATE | GGCF_PEEK, &gob);
307 11029b9c Eric Allman
        if (!EP_STAT_ISOK(estat))
308
        {
309
                char ebuf[100];
310
311 fec93aac Eric Allman
                ep_dbg_cprintf(Dbg, 1, "post_one_log: _gdp_gob_cache_get: %s\n",
312 11029b9c Eric Allman
                                ep_stat_tostr(estat, ebuf, sizeof ebuf));
313 cc4a7f8a Eric Allman
                return estat;
314 11029b9c Eric Allman
        }
315 fec93aac Eric Allman
        if (gob != NULL)
316 a0469464 Eric Allman
        {
317 fec93aac Eric Allman
                if (gob->x->physimpl->getstats != NULL)
318 a0469464 Eric Allman
                {
319
                        char nrecsbuf[40];
320
                        char logsizebuf[40];
321 fec93aac Eric Allman
                        struct gob_phys_stats stats;
322 a0469464 Eric Allman
323 fec93aac Eric Allman
                        gob->x->physimpl->getstats(gob, &stats);
324 a0469464 Eric Allman
                        snprintf(nrecsbuf, sizeof nrecsbuf, "%" PRIgdp_recno, stats.nrecs);
325
                        snprintf(logsizebuf, sizeof logsizebuf, "%" PRId64, stats.size);
326
                        admin_post_stats(ADMIN_LOG_SNAPSHOT, "log-snapshot",
327
                                        "name", gdppname,
328
                                        "in-cache", "true",
329
                                        "nrecs", nrecsbuf,
330
                                        "size", logsizebuf,
331
                                        NULL, NULL);
332
                }
333
                else
334
                {
335
                        admin_post_stats(ADMIN_LOG_SNAPSHOT, "log-snapshot",
336
                                        "name", gdppname,
337
                                        "in-cache", "true",
338
                                        NULL, NULL);
339
                }
340 b890d0d9 Eric Allman
341 fec93aac Eric Allman
                _gdp_gob_unlock(gob);
342 a0469464 Eric Allman
        }
343
        else
344
        {
345
                admin_post_stats(ADMIN_LOG_SNAPSHOT, "log-snapshot",
346
                                "name", gdppname,
347
                                "in-cache", "false",
348
                                NULL, NULL);
349
        }
350 833b2d3d Eric Allman
        return EP_STAT_OK;
351 a0469464 Eric Allman
}
352
353
354
static void
355
admin_probe_thread(void *ctx)
356
{
357 11029b9c Eric Allman
        if (ep_thr_mutex_trylock(&AdminProbeMutex) != 0)
358
        {
359
                ep_dbg_cprintf(Dbg, 7, "admin_probe_thread: locked\n");
360
                return;
361
        }
362 92243bf4 Eric Allman
        GdpSqliteImpl.foreach(post_one_log, ctx);
363 11029b9c Eric Allman
        ep_thr_mutex_unlock(&AdminProbeMutex);
364 a0469464 Eric Allman
}
365
366
void
367
admin_probe(int fd, short what, void *ctx)
368
{
369
        ep_thr_pool_run(admin_probe_thread, ctx);
370
}