virlog.c 38.4 KB
Newer Older
1
/*
2
 * virlog.c: internal logging and debugging
3
 *
4
 * Copyright (C) 2008, 2010-2014 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library.  If not, see
O
Osier Yang 已提交
18
 * <http://www.gnu.org/licenses/>.
19 20 21 22 23
 *
 */

#include <config.h>

D
Daniel Veillard 已提交
24 25 26 27 28 29 30 31
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
32
#include <unistd.h>
33
#include <execinfo.h>
34
#include <regex.h>
D
Daniel Veillard 已提交
35
#if HAVE_SYSLOG_H
36
# include <syslog.h>
D
Daniel Veillard 已提交
37
#endif
D
Daniel P. Berrange 已提交
38 39 40 41
#include <sys/socket.h>
#if HAVE_SYS_UN_H
# include <sys/un.h>
#endif
D
Daniel Veillard 已提交
42

43
#include "virerror.h"
44
#include "virlog.h"
45
#include "viralloc.h"
46
#include "virutil.h"
47
#include "virbuffer.h"
48
#include "virthread.h"
E
Eric Blake 已提交
49
#include "virfile.h"
50
#include "virtime.h"
D
Daniel P. Berrange 已提交
51
#include "intprops.h"
52
#include "virstring.h"
53

E
Eric Blake 已提交
54 55 56 57 58 59
/* Journald output is only supported on Linux new enough to expose
 * htole64.  */
#if HAVE_SYSLOG_H && defined(__linux__) && HAVE_DECL_HTOLE64
# define USE_JOURNALD 1
#endif

60 61
#define VIR_FROM_THIS VIR_FROM_NONE

62 63
VIR_LOG_INIT("util.log");

64
static regex_t *virLogRegex;
65 66


67 68
#define VIR_LOG_DATE_REGEX "[0-9]{4}-[0-9]{2}-[0-9]{2}"
#define VIR_LOG_TIME_REGEX "[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}\\+[0-9]{4}"
69
#define VIR_LOG_PID_REGEX "[0-9]+"
70
#define VIR_LOG_LEVEL_REGEX "(debug|info|warning|error)"
71 72 73 74

#define VIR_LOG_REGEX \
    VIR_LOG_DATE_REGEX " " VIR_LOG_TIME_REGEX ": " \
    VIR_LOG_PID_REGEX ": " VIR_LOG_LEVEL_REGEX " : "
D
Daniel Veillard 已提交
75

76 77 78 79
VIR_ENUM_DECL(virLogDestination);
VIR_ENUM_IMPL(virLogDestination, VIR_LOG_TO_OUTPUT_LAST,
              "stderr", "syslog", "file", "journald");

D
Daniel Veillard 已提交
80 81 82 83 84
/*
 * Filters are used to refine the rules on what to keep or drop
 * based on a matching pattern (currently a substring)
 */
struct _virLogFilter {
85
    char *match;
86
    virLogPriority priority;
87
    unsigned int flags;
D
Daniel Veillard 已提交
88 89 90 91
};
typedef struct _virLogFilter virLogFilter;
typedef virLogFilter *virLogFilterPtr;

92
static int virLogFiltersSerial = 1;
93 94
static virLogFilterPtr virLogFilters;
static int virLogNbFilters;
D
Daniel Veillard 已提交
95 96 97 98 99 100

/*
 * Outputs are used to emit the messages retained
 * after filtering, multiple output can be used simultaneously
 */
struct _virLogOutput {
101
    bool logInitMessage;
D
Daniel Veillard 已提交
102 103 104
    void *data;
    virLogOutputFunc f;
    virLogCloseFunc c;
105
    virLogPriority priority;
106
    virLogDestination dest;
107
    char *name;
D
Daniel Veillard 已提交
108 109 110 111
};
typedef struct _virLogOutput virLogOutput;
typedef virLogOutput *virLogOutputPtr;

112 113
static virLogOutputPtr virLogOutputs;
static int virLogNbOutputs;
D
Daniel Veillard 已提交
114 115 116 117

/*
 * Default priorities
 */
118
static virLogPriority virLogDefaultPriority = VIR_LOG_DEFAULT;
D
Daniel Veillard 已提交
119

120 121
static void virLogResetFilters(void);
static void virLogResetOutputs(void);
122
static void virLogOutputToFd(virLogSourcePtr src,
123
                             virLogPriority priority,
124
                             const char *filename,
125
                             int linenr,
126
                             const char *funcname,
127
                             const char *timestamp,
M
Miloslav Trmač 已提交
128
                             virLogMetadataPtr metadata,
129
                             unsigned int flags,
130 131
                             const char *rawstr,
                             const char *str,
132
                             void *data);
D
Daniel Veillard 已提交
133

134

D
Daniel Veillard 已提交
135 136 137
/*
 * Logs accesses must be serialized though a mutex
 */
138
virMutex virLogMutex;
D
Daniel Veillard 已提交
139

140 141
void
virLogLock(void)
D
Daniel Veillard 已提交
142
{
143
    virMutexLock(&virLogMutex);
D
Daniel Veillard 已提交
144
}
145 146 147 148


void
virLogUnlock(void)
D
Daniel Veillard 已提交
149
{
150
    virMutexUnlock(&virLogMutex);
D
Daniel Veillard 已提交
151 152
}

153 154 155 156

static const char *
virLogPriorityString(virLogPriority lvl)
{
D
Daniel Veillard 已提交
157
    switch (lvl) {
158 159 160 161 162 163 164 165
    case VIR_LOG_DEBUG:
        return "debug";
    case VIR_LOG_INFO:
        return "info";
    case VIR_LOG_WARN:
        return "warning";
    case VIR_LOG_ERROR:
        return "error";
D
Daniel Veillard 已提交
166
    }
167
    return "unknown";
D
Daniel Veillard 已提交
168 169 170
}


171 172
static int
virLogOnceInit(void)
173
{
174 175 176
    if (virMutexInit(&virLogMutex) < 0)
        return -1;

D
Daniel Veillard 已提交
177
    virLogLock();
178
    virLogDefaultPriority = VIR_LOG_DEFAULT;
179

180
    if (VIR_ALLOC_QUIET(virLogRegex) >= 0) {
181 182 183 184
        if (regcomp(virLogRegex, VIR_LOG_REGEX, REG_EXTENDED) != 0)
            VIR_FREE(virLogRegex);
    }

D
Daniel Veillard 已提交
185
    virLogUnlock();
186
    return 0;
D
Daniel Veillard 已提交
187 188
}

189 190
VIR_ONCE_GLOBAL_INIT(virLog)

191

D
Daniel Veillard 已提交
192 193 194 195 196 197 198
/**
 * virLogReset:
 *
 * Reset the logging module to its default initial state
 *
 * Returns 0 if successful, and -1 in case or error
 */
199 200 201
int
virLogReset(void)
{
202 203
    if (virLogInitialize() < 0)
        return -1;
D
Daniel Veillard 已提交
204 205 206 207

    virLogLock();
    virLogResetFilters();
    virLogResetOutputs();
208
    virLogDefaultPriority = VIR_LOG_DEFAULT;
D
Daniel Veillard 已提交
209
    virLogUnlock();
210
    return 0;
D
Daniel Veillard 已提交
211 212 213 214 215 216 217 218 219 220 221 222
}

/**
 * virLogSetDefaultPriority:
 * @priority: the default priority level
 *
 * Set the default priority level, i.e. any logged data of a priority
 * equal or superior to this level will be logged, unless a specific rule
 * was defined for the log category of the message.
 *
 * Returns 0 if successful, -1 in case of error.
 */
223 224 225
int
virLogSetDefaultPriority(virLogPriority priority)
{
226
    if ((priority < VIR_LOG_DEBUG) || (priority > VIR_LOG_ERROR)) {
227
        VIR_WARN("Ignoring invalid log level setting.");
228
        return -1;
229
    }
230 231 232
    if (virLogInitialize() < 0)
        return -1;

D
Daniel Veillard 已提交
233
    virLogDefaultPriority = priority;
234
    return 0;
D
Daniel Veillard 已提交
235 236
}

237

D
Daniel Veillard 已提交
238 239 240 241 242
/**
 * virLogResetFilters:
 *
 * Removes the set of logging filters defined.
 */
243
static void
244 245
virLogResetFilters(void)
{
246
    size_t i;
D
Daniel Veillard 已提交
247

248
    for (i = 0; i < virLogNbFilters; i++)
D
Daniel Veillard 已提交
249 250 251
        VIR_FREE(virLogFilters[i].match);
    VIR_FREE(virLogFilters);
    virLogNbFilters = 0;
252
    virLogFiltersSerial++;
D
Daniel Veillard 已提交
253 254
}

255

D
Daniel Veillard 已提交
256 257 258 259
/**
 * virLogDefineFilter:
 * @match: the pattern to match
 * @priority: the priority to give to messages matching the pattern
260
 * @flags: extra flags, see virLogFilterFlags enum
D
Daniel Veillard 已提交
261 262 263 264 265 266 267 268
 *
 * Defines a pattern used for log filtering, it allow to select or
 * reject messages independently of the default priority.
 * The filter defines a rules that will apply only to messages matching
 * the pattern (currently if @match is a substring of the message category)
 *
 * Returns -1 in case of failure or the filter number if successful
 */
269 270 271 272
int
virLogDefineFilter(const char *match,
                   virLogPriority priority,
                   unsigned int flags)
273
{
274 275
    size_t i;
    int ret = -1;
D
Daniel Veillard 已提交
276 277
    char *mdup = NULL;

278
    virCheckFlags(VIR_LOG_STACK_TRACE, -1);
279

280 281 282
    if (virLogInitialize() < 0)
        return -1;

D
Daniel Veillard 已提交
283 284
    if ((match == NULL) || (priority < VIR_LOG_DEBUG) ||
        (priority > VIR_LOG_ERROR))
285
        return -1;
D
Daniel Veillard 已提交
286 287

    virLogLock();
288
    for (i = 0; i < virLogNbFilters; i++) {
D
Daniel Veillard 已提交
289 290
        if (STREQ(virLogFilters[i].match, match)) {
            virLogFilters[i].priority = priority;
291
            ret = i;
D
Daniel Veillard 已提交
292 293 294 295
            goto cleanup;
        }
    }

296
    if (VIR_STRDUP_QUIET(mdup, match) < 0)
D
Daniel Veillard 已提交
297
        goto cleanup;
298
    if (VIR_REALLOC_N_QUIET(virLogFilters, virLogNbFilters + 1)) {
D
Daniel Veillard 已提交
299 300 301
        VIR_FREE(mdup);
        goto cleanup;
    }
302
    ret = virLogNbFilters;
D
Daniel Veillard 已提交
303 304
    virLogFilters[i].match = mdup;
    virLogFilters[i].priority = priority;
305
    virLogFilters[i].flags = flags;
D
Daniel Veillard 已提交
306
    virLogNbFilters++;
307
    virLogFiltersSerial++;
308
 cleanup:
D
Daniel Veillard 已提交
309
    virLogUnlock();
310
    if (ret < 0)
311
        virReportOOMError();
312
    return ret;
D
Daniel Veillard 已提交
313 314 315 316 317 318 319
}

/**
 * virLogResetOutputs:
 *
 * Removes the set of logging output defined.
 */
320
static void
321 322
virLogResetOutputs(void)
{
323
    size_t i;
D
Daniel Veillard 已提交
324

325
    for (i = 0; i < virLogNbOutputs; i++) {
D
Daniel Veillard 已提交
326 327
        if (virLogOutputs[i].c != NULL)
            virLogOutputs[i].c(virLogOutputs[i].data);
328
        VIR_FREE(virLogOutputs[i].name);
D
Daniel Veillard 已提交
329 330 331 332 333
    }
    VIR_FREE(virLogOutputs);
    virLogNbOutputs = 0;
}

334

D
Daniel Veillard 已提交
335 336 337
/**
 * virLogDefineOutput:
 * @f: the function to call to output a message
338
 * @c: the function to call to close the output (or NULL)
D
Daniel Veillard 已提交
339 340
 * @data: extra data passed as first arg to the function
 * @priority: minimal priority for this filter, use 0 for none
341 342
 * @dest: where to send output of this priority
 * @name: optional name data associated with an output
D
Daniel Veillard 已提交
343 344 345 346 347 348 349
 * @flags: extra flag, currently unused
 *
 * Defines an output function for log messages. Each message once
 * gone though filtering is emitted through each registered output.
 *
 * Returns -1 in case of failure or the output number if successful
 */
350 351 352 353 354 355 356 357
int
virLogDefineOutput(virLogOutputFunc f,
                   virLogCloseFunc c,
                   void *data,
                   virLogPriority priority,
                   virLogDestination dest,
                   const char *name,
                   unsigned int flags)
358
{
D
Daniel Veillard 已提交
359
    int ret = -1;
360
    char *ndup = NULL;
D
Daniel Veillard 已提交
361

362 363
    virCheckFlags(0, -1);

364 365 366
    if (virLogInitialize() < 0)
        return -1;

D
Daniel Veillard 已提交
367
    if (f == NULL)
368
        return -1;
D
Daniel Veillard 已提交
369

370
    if (dest == VIR_LOG_TO_SYSLOG || dest == VIR_LOG_TO_FILE) {
371 372
        if (!name) {
            virReportOOMError();
373
            return -1;
374 375
        }
        if (VIR_STRDUP(ndup, name) < 0)
376
            return -1;
377 378
    }

D
Daniel Veillard 已提交
379
    virLogLock();
380
    if (VIR_REALLOC_N_QUIET(virLogOutputs, virLogNbOutputs + 1)) {
381
        VIR_FREE(ndup);
D
Daniel Veillard 已提交
382 383 384
        goto cleanup;
    }
    ret = virLogNbOutputs++;
385
    virLogOutputs[ret].logInitMessage = true;
D
Daniel Veillard 已提交
386 387 388 389
    virLogOutputs[ret].f = f;
    virLogOutputs[ret].c = c;
    virLogOutputs[ret].data = data;
    virLogOutputs[ret].priority = priority;
390 391
    virLogOutputs[ret].dest = dest;
    virLogOutputs[ret].name = ndup;
392
 cleanup:
D
Daniel Veillard 已提交
393
    virLogUnlock();
394
    return ret;
D
Daniel Veillard 已提交
395 396
}

397

398 399
static int
virLogFormatString(char **msg,
400
                   int linenr,
401
                   const char *funcname,
402
                   virLogPriority priority,
403 404 405
                   const char *str)
{
    int ret;
406 407 408 409 410 411 412 413

    /*
     * Be careful when changing the following log message formatting, we rely
     * on it when stripping libvirt debug messages from qemu log files. So when
     * changing this, you might also need to change the code there.
     * virLogFormatString() function name is mentioned there so it's sufficient
     * to just grep for it to find the right place.
     */
414
    if ((funcname != NULL)) {
415 416 417
        ret = virAsprintfQuiet(msg, "%llu: %s : %s:%d : %s\n",
                               virThreadSelfID(), virLogPriorityString(priority),
                               funcname, linenr, str);
418
    } else {
419 420 421
        ret = virAsprintfQuiet(msg, "%llu: %s : %s\n",
                               virThreadSelfID(), virLogPriorityString(priority),
                               str);
422 423 424 425
    }
    return ret;
}

426

427
static int
428 429
virLogVersionString(const char **rawmsg,
                    char **msg)
430
{
431 432
    *rawmsg = VIR_LOG_VERSION_STRING;
    return virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, VIR_LOG_VERSION_STRING);
433 434
}

435 436 437 438
/* Similar to virGetHostname() but avoids use of error
 * reporting APIs or logging APIs, to prevent recursion
 */
static int
439
virLogHostnameString(char **rawmsg,
440 441 442 443 444 445 446 447 448 449 450 451
                     char **msg)
{
    char *hostname = virGetHostnameQuiet();
    char *hoststr;

    if (!hostname)
        return -1;

    if (virAsprintfQuiet(&hoststr, "hostname: %s", hostname) < 0) {
        VIR_FREE(hostname);
        return -1;
    }
452
    VIR_FREE(hostname);
453 454 455 456 457 458 459 460 461

    if (virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, hoststr) < 0) {
        VIR_FREE(hoststr);
        return -1;
    }
    *rawmsg = hoststr;
    return 0;
}

462

463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
static void
virLogSourceUpdate(virLogSourcePtr source)
{
    virLogLock();
    if (source->serial < virLogFiltersSerial) {
        unsigned int priority = virLogDefaultPriority;
        unsigned int flags = 0;
        size_t i;

        for (i = 0; i < virLogNbFilters; i++) {
            if (strstr(source->name, virLogFilters[i].match)) {
                priority = virLogFilters[i].priority;
                flags = virLogFilters[i].flags;
                break;
            }
        }

        source->priority = priority;
        source->flags = flags;
        source->serial = virLogFiltersSerial;
    }
    virLogUnlock();
}

D
Daniel Veillard 已提交
487 488
/**
 * virLogMessage:
489
 * @source: where is that message coming from
D
Daniel Veillard 已提交
490
 * @priority: the priority level
491
 * @filename: file where the message was emitted
492
 * @linenr: line where the message was emitted
493
 * @funcname: the function emitting the (debug) message
494
 * @metadata: NULL or metadata array, terminated by an item with NULL key
D
Daniel Veillard 已提交
495 496 497
 * @fmt: the string format
 * @...: the arguments
 *
E
Eric Blake 已提交
498
 * Call the libvirt logger with some information. Based on the configuration
D
Daniel Veillard 已提交
499 500
 * the message may be stored, sent to output or just discarded
 */
501
void
502
virLogMessage(virLogSourcePtr source,
503
              virLogPriority priority,
504
              const char *filename,
505
              int linenr,
506
              const char *funcname,
507
              virLogMetadataPtr metadata,
508
              const char *fmt, ...)
509 510 511
{
    va_list ap;
    va_start(ap, fmt);
512
    virLogVMessage(source, priority,
513
                   filename, linenr, funcname,
514
                   metadata, fmt, ap);
515 516 517
    va_end(ap);
}

518

519 520
/**
 * virLogVMessage:
521
 * @source: where is that message coming from
522
 * @priority: the priority level
523
 * @filename: file where the message was emitted
524
 * @linenr: line where the message was emitted
525
 * @funcname: the function emitting the (debug) message
526
 * @metadata: NULL or metadata array, terminated by an item with NULL key
527 528 529 530 531 532
 * @fmt: the string format
 * @vargs: format args
 *
 * Call the libvirt logger with some information. Based on the configuration
 * the message may be stored, sent to output or just discarded
 */
533
void
534
virLogVMessage(virLogSourcePtr source,
535
               virLogPriority priority,
536
               const char *filename,
537
               int linenr,
538
               const char *funcname,
M
Miloslav Trmač 已提交
539
               virLogMetadataPtr metadata,
540 541
               const char *fmt,
               va_list vargs)
542
{
543
    static bool logInitMessageStderr = true;
D
Daniel Veillard 已提交
544
    char *str = NULL;
545
    char *msg = NULL;
546
    char timestamp[VIR_TIME_STRING_BUFLEN];
547
    int ret;
548
    size_t i;
549
    int saved_errno = errno;
550
    unsigned int filterflags = 0;
D
Daniel Veillard 已提交
551

552 553
    if (virLogInitialize() < 0)
        return;
D
Daniel Veillard 已提交
554 555

    if (fmt == NULL)
556
        return;
D
Daniel Veillard 已提交
557 558

    /*
559 560 561 562 563 564
     * 3 intentionally non-thread safe variable reads.
     * Since writes to the variable are serialized on
     * virLogLock, worst case result is a log message
     * is accidentally dropped or emitted, if another
     * thread is updating log filter list concurrently
     * with a log message emission.
D
Daniel Veillard 已提交
565
     */
566 567 568
    if (source->serial < virLogFiltersSerial)
        virLogSourceUpdate(source);
    if (priority < source->priority)
569
        goto cleanup;
570
    filterflags = source->flags;
571

D
Daniel Veillard 已提交
572 573 574
    /*
     * serialize the error message, add level and timestamp
     */
575
    if (virVasprintfQuiet(&str, fmt, vargs) < 0)
576
        goto cleanup;
D
Daniel Veillard 已提交
577

578
    ret = virLogFormatString(&msg, linenr, funcname, priority, str);
579 580
    if (ret < 0)
        goto cleanup;
D
Daniel Veillard 已提交
581

582 583
    if (virTimeStringNowRaw(timestamp) < 0)
        timestamp[0] = '\0';
584

585 586
    virLogLock();

D
Daniel Veillard 已提交
587
    /*
588
     * Push the message to the outputs defined, if none exist then
D
Daniel Veillard 已提交
589 590
     * use stderr.
     */
591
    for (i = 0; i < virLogNbOutputs; i++) {
592
        if (priority >= virLogOutputs[i].priority) {
593 594
            if (virLogOutputs[i].logInitMessage) {
                const char *rawinitmsg;
595
                char *hoststr = NULL;
596 597 598 599 600 601 602
                char *initmsg = NULL;
                if (virLogVersionString(&rawinitmsg, &initmsg) >= 0)
                    virLogOutputs[i].f(&virLogSelf, VIR_LOG_INFO,
                                       __FILE__, __LINE__, __func__,
                                       timestamp, NULL, 0, rawinitmsg, initmsg,
                                       virLogOutputs[i].data);
                VIR_FREE(initmsg);
603
                if (virLogHostnameString(&hoststr, &initmsg) >= 0)
604
                    virLogOutputs[i].f(&virLogSelf, VIR_LOG_INFO,
605
                                       __FILE__, __LINE__, __func__,
606
                                       timestamp, NULL, 0, hoststr, initmsg,
607
                                       virLogOutputs[i].data);
608
                VIR_FREE(hoststr);
609 610
                VIR_FREE(initmsg);
                virLogOutputs[i].logInitMessage = false;
611
            }
612
            virLogOutputs[i].f(source, priority,
613
                               filename, linenr, funcname,
M
Miloslav Trmač 已提交
614
                               timestamp, metadata, filterflags,
615
                               str, msg, virLogOutputs[i].data);
616
        }
D
Daniel Veillard 已提交
617
    }
618
    if (virLogNbOutputs == 0) {
619 620
        if (logInitMessageStderr) {
            const char *rawinitmsg;
621
            char *hoststr = NULL;
622 623 624 625 626 627 628
            char *initmsg = NULL;
            if (virLogVersionString(&rawinitmsg, &initmsg) >= 0)
                virLogOutputToFd(&virLogSelf, VIR_LOG_INFO,
                                 __FILE__, __LINE__, __func__,
                                 timestamp, NULL, 0, rawinitmsg, initmsg,
                                 (void *) STDERR_FILENO);
            VIR_FREE(initmsg);
629
            if (virLogHostnameString(&hoststr, &initmsg) >= 0)
630
                virLogOutputToFd(&virLogSelf, VIR_LOG_INFO,
631
                                 __FILE__, __LINE__, __func__,
632
                                 timestamp, NULL, 0, hoststr, initmsg,
633
                                 (void *) STDERR_FILENO);
634
            VIR_FREE(hoststr);
635 636
            VIR_FREE(initmsg);
            logInitMessageStderr = false;
637
        }
638
        virLogOutputToFd(source, priority,
639
                         filename, linenr, funcname,
M
Miloslav Trmač 已提交
640
                         timestamp, metadata, filterflags,
641
                         str, msg, (void *) STDERR_FILENO);
642
    }
D
Daniel Veillard 已提交
643 644
    virLogUnlock();

645
 cleanup:
646
    VIR_FREE(str);
647
    VIR_FREE(msg);
648
    errno = saved_errno;
D
Daniel Veillard 已提交
649 650
}

651

652 653
static void
virLogStackTraceToFd(int fd)
654 655 656
{
    void *array[100];
    int size;
657
    static bool doneWarning;
658
    const char *msg = "Stack trace not available on this platform\n";
659 660 661 662 663 664 665

#define STRIP_DEPTH 3
    size = backtrace(array, ARRAY_CARDINALITY(array));
    if (size) {
        backtrace_symbols_fd(array +  STRIP_DEPTH, size - STRIP_DEPTH, fd);
        ignore_value(safewrite(fd, "\n", 1));
    } else if (!doneWarning) {
666 667 668
        ignore_value(safewrite(fd, msg, strlen(msg)));
        doneWarning = true;
    }
669
#undef STRIP_DEPTH
670 671
}

672
static void
673
virLogOutputToFd(virLogSourcePtr source ATTRIBUTE_UNUSED,
674
                 virLogPriority priority ATTRIBUTE_UNUSED,
675
                 const char *filename ATTRIBUTE_UNUSED,
676
                 int linenr ATTRIBUTE_UNUSED,
677
                 const char *funcname ATTRIBUTE_UNUSED,
678
                 const char *timestamp,
M
Miloslav Trmač 已提交
679
                 virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
680 681 682 683
                 unsigned int flags,
                 const char *rawstr ATTRIBUTE_UNUSED,
                 const char *str,
                 void *data)
684
{
685
    int fd = (intptr_t) data;
686
    char *msg;
D
Daniel Veillard 已提交
687 688

    if (fd < 0)
689
        return;
690

691
    if (virAsprintfQuiet(&msg, "%s: %s", timestamp, str) < 0)
692
        return;
693

694
    ignore_value(safewrite(fd, msg, strlen(msg)));
695 696
    VIR_FREE(msg);

697 698
    if (flags & VIR_LOG_STACK_TRACE)
        virLogStackTraceToFd(fd);
D
Daniel Veillard 已提交
699 700
}

701 702 703

static void
virLogCloseFd(void *data)
704
{
705
    int fd = (intptr_t) data;
D
Daniel Veillard 已提交
706

707
    VIR_LOG_CLOSE(fd);
D
Daniel Veillard 已提交
708 709
}

710 711 712 713

static int
virLogAddOutputToStderr(virLogPriority priority)
{
714 715
    if (virLogDefineOutput(virLogOutputToFd, NULL, (void *)2L, priority,
                           VIR_LOG_TO_STDERR, NULL, 0) < 0)
716 717
        return -1;
    return 0;
D
Daniel Veillard 已提交
718 719
}

720 721 722 723 724

static int
virLogAddOutputToFile(virLogPriority priority,
                      const char *file)
{
D
Daniel Veillard 已提交
725 726
    int fd;

727
    fd = open(file, O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR);
D
Daniel Veillard 已提交
728
    if (fd < 0)
729
        return -1;
730 731
    if (virLogDefineOutput(virLogOutputToFd, virLogCloseFd,
                           (void *)(intptr_t)fd,
732
                           priority, VIR_LOG_TO_FILE, file, 0) < 0) {
733
        VIR_FORCE_CLOSE(fd);
734
        return -1;
D
Daniel Veillard 已提交
735
    }
736
    return 0;
D
Daniel Veillard 已提交
737 738
}

739

740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
#if HAVE_SYSLOG_H || USE_JOURNALD

/* Compat in case we build with journald, but no syslog */
# ifndef LOG_DEBUG
#  define LOG_DEBUG 7
# endif
# ifndef LOG_INFO
#  define LOG_INFO 6
# endif
# ifndef LOG_WARNING
#  define LOG_WARNING 4
# endif
# ifndef LOG_ERR
#  define LOG_ERR 3
# endif

756 757
static int
virLogPrioritySyslog(virLogPriority priority)
758 759 760 761 762 763 764 765 766 767 768 769 770 771
{
    switch (priority) {
    case VIR_LOG_DEBUG:
        return LOG_DEBUG;
    case VIR_LOG_INFO:
        return LOG_INFO;
    case VIR_LOG_WARN:
        return LOG_WARNING;
    case VIR_LOG_ERROR:
        return LOG_ERR;
    default:
        return LOG_ERR;
    }
}
772
#endif /* HAVE_SYSLOG_H || USE_JOURNALD */
773

774

775
#if HAVE_SYSLOG_H
776
static void
777
virLogOutputToSyslog(virLogSourcePtr source ATTRIBUTE_UNUSED,
778
                     virLogPriority priority,
779
                     const char *filename ATTRIBUTE_UNUSED,
780
                     int linenr ATTRIBUTE_UNUSED,
781
                     const char *funcname ATTRIBUTE_UNUSED,
782
                     const char *timestamp ATTRIBUTE_UNUSED,
M
Miloslav Trmač 已提交
783
                     virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
784 785 786 787
                     unsigned int flags,
                     const char *rawstr ATTRIBUTE_UNUSED,
                     const char *str,
                     void *data ATTRIBUTE_UNUSED)
788
{
789
    virCheckFlags(VIR_LOG_STACK_TRACE,);
790

791
    syslog(virLogPrioritySyslog(priority), "%s", str);
D
Daniel Veillard 已提交
792 793
}

794
static char *current_ident;
795

796 797 798 799

static void
virLogCloseSyslog(void *data ATTRIBUTE_UNUSED)
{
D
Daniel Veillard 已提交
800
    closelog();
801
    VIR_FREE(current_ident);
D
Daniel Veillard 已提交
802 803
}

804 805 806 807 808

static int
virLogAddOutputToSyslog(virLogPriority priority,
                        const char *ident)
{
809 810 811 812
    /*
     * ident needs to be kept around on Solaris
     */
    VIR_FREE(current_ident);
813
    if (VIR_STRDUP(current_ident, ident) < 0)
814
        return -1;
815 816

    openlog(current_ident, 0, 0);
D
Daniel Veillard 已提交
817
    if (virLogDefineOutput(virLogOutputToSyslog, virLogCloseSyslog, NULL,
818
                           priority, VIR_LOG_TO_SYSLOG, ident, 0) < 0) {
D
Daniel Veillard 已提交
819
        closelog();
820
        VIR_FREE(current_ident);
821
        return -1;
D
Daniel Veillard 已提交
822
    }
823
    return 0;
D
Daniel Veillard 已提交
824
}
D
Daniel P. Berrange 已提交
825 826


E
Eric Blake 已提交
827
# if USE_JOURNALD
828 829 830 831 832
#  define IOVEC_SET(iov, data, size)            \
    do {                                        \
        struct iovec *_i = &(iov);              \
        _i->iov_base = (void*)(data);           \
        _i->iov_len = (size);                   \
D
Daniel P. Berrange 已提交
833 834
    } while (0)

835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
#  define IOVEC_SET_STRING(iov, str) IOVEC_SET(iov, str, strlen(str))

/* Used for conversion of numbers to strings, and for length of binary data */
#  define JOURNAL_BUF_SIZE (MAX(INT_BUFSIZE_BOUND(int), sizeof(uint64_t)))

struct journalState
{
    struct iovec *iov, *iov_end;
    char (*bufs)[JOURNAL_BUF_SIZE], (*bufs_end)[JOURNAL_BUF_SIZE];
};

static void
journalAddString(struct journalState *state, const char *field,
                 const char *value)
{
    static const char newline = '\n', equals = '=';

    if (strchr(value, '\n') != NULL) {
        uint64_t nstr;

        /* If 'str' contains a newline, then we must
         * encode the string length, since we can't
         * rely on the newline for the field separator
         */
        if (state->iov_end - state->iov < 5 || state->bufs == state->bufs_end)
            return; /* Silently drop */
        nstr = htole64(strlen(value));
        memcpy(state->bufs[0], &nstr, sizeof(nstr));

        IOVEC_SET_STRING(state->iov[0], field);
        IOVEC_SET(state->iov[1], &newline, sizeof(newline));
        IOVEC_SET(state->iov[2], state->bufs[0], sizeof(nstr));
        state->bufs++;
        state->iov += 3;
    } else {
        if (state->iov_end - state->iov < 4)
            return; /* Silently drop */
        IOVEC_SET_STRING(state->iov[0], field);
        IOVEC_SET(state->iov[1], (void *)&equals, sizeof(equals));
        state->iov += 2;
    }
    IOVEC_SET_STRING(state->iov[0], value);
    IOVEC_SET(state->iov[1], (void *)&newline, sizeof(newline));
    state->iov += 2;
}

static void
journalAddInt(struct journalState *state, const char *field, int value)
{
    static const char newline = '\n', equals = '=';

    char *num;

    if (state->iov_end - state->iov < 4 || state->bufs == state->bufs_end)
        return; /* Silently drop */

    num = virFormatIntDecimal(state->bufs[0], sizeof(state->bufs[0]), value);

    IOVEC_SET_STRING(state->iov[0], field);
    IOVEC_SET(state->iov[1], (void *)&equals, sizeof(equals));
    IOVEC_SET_STRING(state->iov[2], num);
    IOVEC_SET(state->iov[3], (void *)&newline, sizeof(newline));
    state->bufs++;
    state->iov += 4;
}
D
Daniel P. Berrange 已提交
900 901 902 903

static int journalfd = -1;

static void
904
virLogOutputToJournald(virLogSourcePtr source,
D
Daniel P. Berrange 已提交
905 906 907 908 909
                       virLogPriority priority,
                       const char *filename,
                       int linenr,
                       const char *funcname,
                       const char *timestamp ATTRIBUTE_UNUSED,
910
                       virLogMetadataPtr metadata,
D
Daniel P. Berrange 已提交
911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
                       unsigned int flags,
                       const char *rawstr,
                       const char *str ATTRIBUTE_UNUSED,
                       void *data ATTRIBUTE_UNUSED)
{
    virCheckFlags(VIR_LOG_STACK_TRACE,);
    int buffd = -1;
    struct msghdr mh;
    struct sockaddr_un sa;
    union {
        struct cmsghdr cmsghdr;
        uint8_t buf[CMSG_SPACE(sizeof(int))];
    } control;
    struct cmsghdr *cmsg;
    /* We use /dev/shm instead of /tmp here, since we want this to
     * be a tmpfs, and one that is available from early boot on
     * and where unprivileged users can create files. */
    char path[] = "/dev/shm/journal.XXXXXX";
929
    size_t nmetadata = 0;
D
Daniel P. Berrange 已提交
930

931 932 933
#  define NUM_FIELDS_CORE 6
#  define NUM_FIELDS_META 5
#  define NUM_FIELDS (NUM_FIELDS_CORE + NUM_FIELDS_META)
934 935 936
    struct iovec iov[NUM_FIELDS * 5];
    char iov_bufs[NUM_FIELDS][JOURNAL_BUF_SIZE];
    struct journalState state;
D
Daniel P. Berrange 已提交
937

938 939 940 941
    state.iov = iov;
    state.iov_end = iov + ARRAY_CARDINALITY(iov);
    state.bufs = iov_bufs;
    state.bufs_end = iov_bufs + ARRAY_CARDINALITY(iov_bufs);
D
Daniel P. Berrange 已提交
942

E
Eric Blake 已提交
943
    journalAddString(&state, "MESSAGE", rawstr);
944 945
    journalAddInt(&state, "PRIORITY",
                  virLogPrioritySyslog(priority));
946
    journalAddInt(&state, "SYSLOG_FACILITY", LOG_DAEMON);
947
    journalAddString(&state, "LIBVIRT_SOURCE", source->name);
948 949
    if (filename)
        journalAddString(&state, "CODE_FILE", filename);
950
    journalAddInt(&state, "CODE_LINE", linenr);
951 952
    if (funcname)
        journalAddString(&state, "CODE_FUNC", funcname);
953 954 955 956 957 958 959 960 961 962 963
    if (metadata != NULL) {
        while (metadata->key != NULL &&
               nmetadata < NUM_FIELDS_META) {
            if (metadata->s != NULL)
                journalAddString(&state, metadata->key, metadata->s);
            else
                journalAddInt(&state, metadata->key, metadata->iv);
            metadata++;
            nmetadata++;
        }
    }
D
Daniel P. Berrange 已提交
964 965 966 967 968 969 970 971 972 973

    memset(&sa, 0, sizeof(sa));
    sa.sun_family = AF_UNIX;
    if (!virStrcpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path)))
        return;

    memset(&mh, 0, sizeof(mh));
    mh.msg_name = &sa;
    mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
    mh.msg_iov = iov;
974
    mh.msg_iovlen = state.iov - iov;
D
Daniel P. Berrange 已提交
975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997

    if (sendmsg(journalfd, &mh, MSG_NOSIGNAL) >= 0)
        return;

    if (errno != EMSGSIZE && errno != ENOBUFS)
        return;

    /* Message was too large, so dump to temporary file
     * and pass an FD to the journal
     */

    /* NB: mkostemp is not declared async signal safe by
     * POSIX, but this is Linux only code and the GLibc
     * impl is safe enough, only using open() and inline
     * asm to read a timestamp (falling back to gettimeofday
     * on some arches
     */
    if ((buffd = mkostemp(path, O_CLOEXEC|O_RDWR)) < 0)
        return;

    if (unlink(path) < 0)
        goto cleanup;

998
    if (writev(buffd, iov, state.iov - iov) < 0)
D
Daniel P. Berrange 已提交
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
        goto cleanup;

    mh.msg_iov = NULL;
    mh.msg_iovlen = 0;

    memset(&control, 0, sizeof(control));
    mh.msg_control = &control;
    mh.msg_controllen = sizeof(control);

    cmsg = CMSG_FIRSTHDR(&mh);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_RIGHTS;
    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
    memcpy(CMSG_DATA(cmsg), &buffd, sizeof(int));

    mh.msg_controllen = cmsg->cmsg_len;

1016
    ignore_value(sendmsg(journalfd, &mh, MSG_NOSIGNAL));
D
Daniel P. Berrange 已提交
1017

1018
 cleanup:
D
Daniel P. Berrange 已提交
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
    VIR_LOG_CLOSE(buffd);
}


static void virLogCloseJournald(void *data ATTRIBUTE_UNUSED)
{
    VIR_LOG_CLOSE(journalfd);
}


static int virLogAddOutputToJournald(int priority)
{
    if ((journalfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
        return -1;
    if (virSetInherit(journalfd, false) < 0) {
        VIR_LOG_CLOSE(journalfd);
        return -1;
    }
    if (virLogDefineOutput(virLogOutputToJournald, virLogCloseJournald, NULL,
                           priority, VIR_LOG_TO_JOURNALD, NULL, 0) < 0) {
        return -1;
    }
    return 0;
}
E
Eric Blake 已提交
1043
# endif /* USE_JOURNALD */
J
Ján Tomko 已提交
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068

int virLogPriorityFromSyslog(int priority)
{
    switch (priority) {
    case LOG_EMERG:
    case LOG_ALERT:
    case LOG_CRIT:
    case LOG_ERR:
        return VIR_LOG_ERROR;
    case LOG_WARNING:
    case LOG_NOTICE:
        return VIR_LOG_WARN;
    case LOG_INFO:
        return VIR_LOG_INFO;
    case LOG_DEBUG:
        return VIR_LOG_DEBUG;
    }
    return VIR_LOG_ERROR;
}

#else /* HAVE_SYSLOG_H */
int virLogPriorityFromSyslog(int priority ATTRIBUTE_UNUSED)
{
    return VIR_LOG_ERROR;
}
D
Daniel Veillard 已提交
1069 1070 1071 1072 1073 1074
#endif /* HAVE_SYSLOG_H */

#define IS_SPACE(cur)                                                   \
    ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') ||               \
     (*cur == '\r') || (*cur == '\\'))

1075

1076 1077 1078 1079 1080 1081 1082 1083
static int
virLogParseOutput(const char *src)
{
    int ret = -1;
    char **tokens = NULL;
    char *abspath = NULL;
    size_t count = 0;
    virLogPriority prio;
1084
    int dest;
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
    bool isSUID = virIsSUID();

    if (!src)
        return -1;

    VIR_DEBUG("output=%s", src);

    /* split our format prio:destination:additional_data to tokens and parse
     * them individually
     */
    if (!(tokens = virStringSplitCount(src, ":", 0, &count)))
        return -1;

    if (virStrToLong_uip(tokens[0], NULL, 10, &prio) < 0 ||
        (prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
        goto cleanup;

    if ((dest = virLogDestinationTypeFromString(tokens[1])) < 0)
        goto cleanup;

    if (((dest == VIR_LOG_TO_STDERR ||
          dest == VIR_LOG_TO_JOURNALD) && count != 2) ||
        ((dest == VIR_LOG_TO_FILE ||
          dest == VIR_LOG_TO_SYSLOG) && count != 3))
        goto cleanup;

    /* if running with setuid, only 'stderr' is allowed */
    if (isSUID && dest != VIR_LOG_TO_STDERR)
        goto cleanup;

    switch ((virLogDestination) dest) {
    case VIR_LOG_TO_STDERR:
        ret = virLogAddOutputToStderr(prio);
        break;
    case VIR_LOG_TO_SYSLOG:
#if HAVE_SYSLOG_H
        ret = virLogAddOutputToSyslog(prio, tokens[2]);
#endif
        break;
    case VIR_LOG_TO_FILE:
        if (virFileAbsPath(tokens[2], &abspath) < 0)
            goto cleanup;
        ret = virLogAddOutputToFile(prio, abspath);
        VIR_FREE(abspath);
        break;
    case VIR_LOG_TO_JOURNALD:
#if USE_JOURNALD
        ret = virLogAddOutputToJournald(prio);
#endif
        break;
    case VIR_LOG_TO_OUTPUT_LAST:
        break;
    }

 cleanup:
    if (ret < 0)
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to parse and define log output %s"), src);
    virStringFreeList(tokens);
    return ret;
}


D
Daniel Veillard 已提交
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
/**
 * virLogParseOutputs:
 * @outputs: string defining a (set of) output(s)
 *
 * The format for an output can be:
 *    x:stderr
 *       output goes to stderr
 *    x:syslog:name
 *       use syslog for the output and use the given name as the ident
 *    x:file:file_path
 *       output to a file, with the given filepath
 * In all case the x prefix is the minimal level, acting as a filter
 *    1: DEBUG
 *    2: INFO
 *    3: WARNING
 *    4: ERROR
 *
 * Multiple output can be defined in a single @output, they just need to be
 * separated by spaces.
 *
1168 1169 1170
 * If running in setuid mode, then only the 'stderr' output will
 * be allowed
 *
1171
 * Returns the number of output parsed or -1 in case of error.
D
Daniel Veillard 已提交
1172
 */
1173
int
1174
virLogParseOutputs(const char *src)
1175
{
1176 1177
    int ret = -1;
    int count = 0;
1178 1179
    size_t i;
    char **strings = NULL;
D
Daniel Veillard 已提交
1180

1181
    if (!src)
1182
        return -1;
D
Daniel Veillard 已提交
1183

1184
    VIR_DEBUG("outputs=%s", src);
1185

1186 1187 1188 1189 1190 1191 1192 1193 1194
    if (!(strings = virStringSplit(src, " ", 0)))
        goto cleanup;

    for (i = 0; strings[i]; i++) {
        /* virStringSplit may return empty strings */
        if (STREQ(strings[i], ""))
            continue;

        if (virLogParseOutput(strings[i]) < 0)
1195
            goto cleanup;
1196 1197

        count++;
D
Daniel Veillard 已提交
1198
    }
1199

1200
    ret = count;
1201
 cleanup:
1202
    virStringFreeList(strings);
1203
    return ret;
D
Daniel Veillard 已提交
1204 1205
}

1206

1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252
static int
virLogParseFilter(const char *filter)
{
    int ret = -1;
    size_t count = 0;
    virLogPriority prio;
    char **tokens = NULL;
    unsigned int flags = 0;
    char *ref = NULL;

    if (!filter)
        return -1;

    VIR_DEBUG("filter=%s", filter);

    if (!(tokens = virStringSplitCount(filter, ":", 0, &count)))
        return -1;

    if (count != 2)
        goto cleanup;

    if (virStrToLong_uip(tokens[0], NULL, 10, &prio) < 0 ||
        (prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
        goto cleanup;

    ref = tokens[1];
    if (ref[0] == '+') {
        flags |= VIR_LOG_STACK_TRACE;
        ref++;
    }

    if (!*ref)
        goto cleanup;

    if (virLogDefineFilter(ref, prio, flags) < 0)
        goto cleanup;

    ret = 0;
 cleanup:
    if (ret < 0)
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to parse and define log filter %s"), filter);
    virStringFreeList(tokens);
    return ret;
}

D
Daniel Veillard 已提交
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
/**
 * virLogParseFilters:
 * @filters: string defining a (set of) filter(s)
 *
 * The format for a filter is:
 *    x:name
 *       where name is a match string
 * the x prefix is the minimal level where the messages should be logged
 *    1: DEBUG
 *    2: INFO
 *    3: WARNING
 *    4: ERROR
 *
 * Multiple filter can be defined in a single @filters, they just need to be
 * separated by spaces.
 *
1269
 * Returns the number of filter parsed or -1 in case of error.
D
Daniel Veillard 已提交
1270
 */
1271 1272 1273
int
virLogParseFilters(const char *filters)
{
1274 1275
    int ret = -1;
    int count = 0;
1276 1277
    size_t i;
    char **strings = NULL;
D
Daniel Veillard 已提交
1278

1279
    if (!filters)
1280
        return -1;
D
Daniel Veillard 已提交
1281

1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292
    VIR_DEBUG("filters=%s", filters);

    if (!(strings = virStringSplit(filters, " ", 0)))
        goto cleanup;

    for (i = 0; strings[i]; i++) {
        /* virStringSplit may return empty strings */
        if (STREQ(strings[i], ""))
            continue;

        if (virLogParseFilter(strings[i]) < 0)
1293
            goto cleanup;
1294 1295

        count++;
D
Daniel Veillard 已提交
1296
    }
1297

1298
    ret = count;
1299
 cleanup:
1300
    virStringFreeList(strings);
1301
    return ret;
D
Daniel Veillard 已提交
1302
}
1303

1304

1305 1306 1307 1308 1309
/**
 * virLogGetDefaultPriority:
 *
 * Returns the current logging priority level.
 */
1310 1311 1312
virLogPriority
virLogGetDefaultPriority(void)
{
1313
    return virLogDefaultPriority;
1314 1315
}

1316

1317 1318 1319 1320 1321 1322 1323
/**
 * virLogGetFilters:
 *
 * Returns a string listing the current filters, in the format originally
 * specified in the config file or environment. Caller must free the
 * result.
 */
1324 1325 1326
char *
virLogGetFilters(void)
{
1327
    size_t i;
1328 1329 1330 1331
    virBuffer filterbuf = VIR_BUFFER_INITIALIZER;

    virLogLock();
    for (i = 0; i < virLogNbFilters; i++) {
1332 1333 1334 1335 1336 1337
        const char *sep = ":";
        if (virLogFilters[i].flags & VIR_LOG_STACK_TRACE)
            sep = ":+";
        virBufferAsprintf(&filterbuf, "%d%s%s ",
                          virLogFilters[i].priority,
                          sep,
1338 1339 1340 1341
                          virLogFilters[i].match);
    }
    virLogUnlock();

1342 1343
    if (virBufferError(&filterbuf)) {
        virBufferFreeAndReset(&filterbuf);
1344
        return NULL;
1345
    }
1346 1347 1348 1349

    return virBufferContentAndReset(&filterbuf);
}

1350

1351 1352 1353 1354 1355 1356 1357
/**
 * virLogGetOutputs:
 *
 * Returns a string listing the current outputs, in the format originally
 * specified in the config file or environment. Caller must free the
 * result.
 */
1358 1359 1360
char *
virLogGetOutputs(void)
{
1361
    size_t i;
1362 1363 1364 1365
    virBuffer outputbuf = VIR_BUFFER_INITIALIZER;

    virLogLock();
    for (i = 0; i < virLogNbOutputs; i++) {
1366
        virLogDestination dest = virLogOutputs[i].dest;
1367
        if (i)
1368
            virBufferAddChar(&outputbuf, ' ');
1369 1370 1371
        switch (dest) {
            case VIR_LOG_TO_SYSLOG:
            case VIR_LOG_TO_FILE:
1372
                virBufferAsprintf(&outputbuf, "%d:%s:%s",
1373
                                  virLogOutputs[i].priority,
1374
                                  virLogDestinationTypeToString(dest),
1375 1376 1377
                                  virLogOutputs[i].name);
                break;
            default:
1378
                virBufferAsprintf(&outputbuf, "%d:%s",
1379
                                  virLogOutputs[i].priority,
1380
                                  virLogDestinationTypeToString(dest));
1381 1382 1383 1384
        }
    }
    virLogUnlock();

1385 1386
    if (virBufferError(&outputbuf)) {
        virBufferFreeAndReset(&outputbuf);
1387
        return NULL;
1388
    }
1389 1390 1391 1392

    return virBufferContentAndReset(&outputbuf);
}

1393

1394 1395 1396 1397 1398
/**
 * virLogGetNbFilters:
 *
 * Returns the current number of defined log filters.
 */
1399 1400 1401
int
virLogGetNbFilters(void)
{
1402
    return virLogNbFilters;
1403 1404
}

1405

1406 1407 1408 1409 1410
/**
 * virLogGetNbOutputs:
 *
 * Returns the current number of defined log outputs.
 */
1411 1412 1413
int
virLogGetNbOutputs(void)
{
1414
    return virLogNbOutputs;
1415
}
1416

1417

1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428
/**
 * virLogParseDefaultPriority:
 * @priority: string defining the desired logging level
 *
 * Parses and sets the default log priority level. It can take a string or
 * number corresponding to the following levels:
 *    1: DEBUG
 *    2: INFO
 *    3: WARNING
 *    4: ERROR
 *
1429
 * Returns 0 if successful, -1 in case of error.
1430
 */
1431 1432 1433
int
virLogParseDefaultPriority(const char *priority)
{
1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444
    int ret = -1;

    if (STREQ(priority, "1") || STREQ(priority, "debug"))
        ret = virLogSetDefaultPriority(VIR_LOG_DEBUG);
    else if (STREQ(priority, "2") || STREQ(priority, "info"))
        ret = virLogSetDefaultPriority(VIR_LOG_INFO);
    else if (STREQ(priority, "3") || STREQ(priority, "warning"))
        ret = virLogSetDefaultPriority(VIR_LOG_WARN);
    else if (STREQ(priority, "4") || STREQ(priority, "error"))
        ret = virLogSetDefaultPriority(VIR_LOG_ERROR);
    else
1445
        VIR_WARN("Ignoring invalid log level setting");
1446 1447 1448 1449

    return ret;
}

1450

1451 1452 1453 1454 1455 1456
/**
 * virLogSetFromEnv:
 *
 * Sets virLogDefaultPriority, virLogFilters and virLogOutputs based on
 * environment variables.
 */
1457 1458 1459
void
virLogSetFromEnv(void)
{
1460
    const char *debugEnv;
1461

1462 1463 1464
    if (virLogInitialize() < 0)
        return;

1465
    debugEnv = virGetEnvAllowSUID("LIBVIRT_DEBUG");
1466 1467
    if (debugEnv && *debugEnv)
        virLogParseDefaultPriority(debugEnv);
1468
    debugEnv = virGetEnvAllowSUID("LIBVIRT_LOG_FILTERS");
1469
    if (debugEnv && *debugEnv)
1470
        virLogParseFilters(debugEnv);
1471
    debugEnv = virGetEnvAllowSUID("LIBVIRT_LOG_OUTPUTS");
1472
    if (debugEnv && *debugEnv)
1473
        virLogParseOutputs(debugEnv);
1474
}
1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490


/*
 * Returns a true value if the first line in @str is
 * probably a log message generated by the libvirt
 * logging layer
 */
bool virLogProbablyLogMessage(const char *str)
{
    bool ret = false;
    if (!virLogRegex)
        return false;
    if (regexec(virLogRegex, str, 0, NULL, 0) == 0)
        ret = true;
    return ret;
}