virlog.c 41.0 KB
Newer Older
1
/*
2
 * virlog.c: internal logging and debugging
3
 *
4
 * Copyright (C) 2008, 2010-2012 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 <signal.h>
34
#include <execinfo.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 "virterror_internal.h"
44
#include "virlog.h"
45
#include "viralloc.h"
D
Daniel Veillard 已提交
46
#include "util.h"
47
#include "virbuffer.h"
48
#include "threads.h"
E
Eric Blake 已提交
49
#include "virfile.h"
50
#include "virtime.h"
D
Daniel P. Berrange 已提交
51
#include "intprops.h"
52

E
Eric Blake 已提交
53 54 55 56 57 58
/* 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

59 60
#define VIR_FROM_THIS VIR_FROM_NONE

61 62 63 64 65 66 67 68
VIR_ENUM_DECL(virLogSource)
VIR_ENUM_IMPL(virLogSource, VIR_LOG_FROM_LAST,
              "file",
              "error",
              "audit",
              "trace",
              "library");

D
Daniel Veillard 已提交
69 70 71 72
/*
 * A logging buffer to keep some history over logs
 */

73 74
static int virLogSize = 64 * 1024;
static char *virLogBuffer = NULL;
D
Daniel Veillard 已提交
75 76 77 78 79 80 81 82 83 84
static int virLogLen = 0;
static int virLogStart = 0;
static int virLogEnd = 0;

/*
 * Filters are used to refine the rules on what to keep or drop
 * based on a matching pattern (currently a substring)
 */
struct _virLogFilter {
    const char *match;
85
    virLogPriority priority;
86
    unsigned int flags;
D
Daniel Veillard 已提交
87 88 89 90 91 92 93 94 95 96 97 98
};
typedef struct _virLogFilter virLogFilter;
typedef virLogFilter *virLogFilterPtr;

static virLogFilterPtr virLogFilters = NULL;
static int virLogNbFilters = 0;

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

static virLogOutputPtr virLogOutputs = NULL;
static int virLogNbOutputs = 0;

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

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

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

137 138
void
virLogLock(void)
D
Daniel Veillard 已提交
139
{
140
    virMutexLock(&virLogMutex);
D
Daniel Veillard 已提交
141
}
142 143 144 145


void
virLogUnlock(void)
D
Daniel Veillard 已提交
146
{
147
    virMutexUnlock(&virLogMutex);
D
Daniel Veillard 已提交
148 149
}

150 151 152 153

static const char *
virLogOutputString(virLogDestination ldest)
{
154
    switch (ldest) {
155 156 157 158 159 160
    case VIR_LOG_TO_STDERR:
        return "stderr";
    case VIR_LOG_TO_SYSLOG:
        return "syslog";
    case VIR_LOG_TO_FILE:
        return "file";
D
Daniel P. Berrange 已提交
161 162
    case VIR_LOG_TO_JOURNALD:
        return "journald";
163
    }
164
    return "unknown";
165
}
D
Daniel Veillard 已提交
166

167 168 169 170

static const char *
virLogPriorityString(virLogPriority lvl)
{
D
Daniel Veillard 已提交
171
    switch (lvl) {
172 173 174 175 176 177 178 179
    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 已提交
180
    }
181
    return "unknown";
D
Daniel Veillard 已提交
182 183 184
}


185 186
static int
virLogOnceInit(void)
187
{
188 189
    const char *pbm = NULL;

190 191 192
    if (virMutexInit(&virLogMutex) < 0)
        return -1;

D
Daniel Veillard 已提交
193
    virLogLock();
194
    if (VIR_ALLOC_N(virLogBuffer, virLogSize + 1) < 0) {
195 196 197 198 199 200
        /*
         * The debug buffer is not a critical component, allow startup
         * even in case of failure to allocate it in case of a
         * configuration mistake.
         */
        virLogSize = 64 * 1024;
201
        if (VIR_ALLOC_N(virLogBuffer, virLogSize + 1) < 0) {
202 203 204 205 206 207
            pbm = "Failed to allocate debug buffer: deactivating debug log\n";
            virLogSize = 0;
        } else {
            pbm = "Failed to allocate debug buffer: reduced to 64 kB\n";
        }
    }
D
Daniel Veillard 已提交
208 209 210
    virLogLen = 0;
    virLogStart = 0;
    virLogEnd = 0;
211
    virLogDefaultPriority = VIR_LOG_DEFAULT;
D
Daniel Veillard 已提交
212
    virLogUnlock();
213
    if (pbm)
214
        VIR_WARN("%s", pbm);
215
    return 0;
D
Daniel Veillard 已提交
216 217
}

218 219
VIR_ONCE_GLOBAL_INIT(virLog)

220

221 222 223 224 225 226 227 228 229 230
/**
 * virLogSetBufferSize:
 * @size: size of the buffer in kilobytes or <= 0 to deactivate
 *
 * Dynamically set the size or deactivate the logging buffer used to keep
 * a trace of all recent debug output. Note that the content of the buffer
 * is lost if it gets reallocated.
 *
 * Return -1 in case of failure or 0 in case of success
 */
231 232 233
int
virLogSetBufferSize(int size)
{
234 235 236 237 238 239 240 241
    int ret = 0;
    int oldsize;
    char *oldLogBuffer;
    const char *pbm = NULL;

    if (size < 0)
        size = 0;

242 243 244 245
    if (virLogInitialize() < 0)
        return -1;

    if (size * 1024 == virLogSize)
246 247 248 249 250 251 252
        return ret;

    virLogLock();

    oldsize = virLogSize;
    oldLogBuffer = virLogBuffer;

253
    if (INT_MAX / 1024 <= size) {
254 255 256 257 258 259
        pbm = "Requested log size of %d kB too large\n";
        ret = -1;
        goto error;
    }

    virLogSize = size * 1024;
260
    if (VIR_ALLOC_N(virLogBuffer, virLogSize + 1) < 0) {
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
        pbm = "Failed to allocate debug buffer of %d kB\n";
        virLogBuffer = oldLogBuffer;
        virLogSize = oldsize;
        ret = -1;
        goto error;
    }
    VIR_FREE(oldLogBuffer);
    virLogLen = 0;
    virLogStart = 0;
    virLogEnd = 0;

error:
    virLogUnlock();
    if (pbm)
        VIR_ERROR(pbm, size);
    return ret;
}

279

D
Daniel Veillard 已提交
280 281 282 283 284 285 286
/**
 * virLogReset:
 *
 * Reset the logging module to its default initial state
 *
 * Returns 0 if successful, and -1 in case or error
 */
287 288 289
int
virLogReset(void)
{
290 291
    if (virLogInitialize() < 0)
        return -1;
D
Daniel Veillard 已提交
292 293 294 295 296 297 298

    virLogLock();
    virLogResetFilters();
    virLogResetOutputs();
    virLogLen = 0;
    virLogStart = 0;
    virLogEnd = 0;
299
    virLogDefaultPriority = VIR_LOG_DEFAULT;
D
Daniel Veillard 已提交
300
    virLogUnlock();
301
    return 0;
D
Daniel Veillard 已提交
302 303
}

304

D
Daniel Veillard 已提交
305 306 307
/*
 * Store a string in the ring buffer
 */
308 309
static void
virLogStr(const char *str)
310
{
D
Daniel Veillard 已提交
311
    int tmp;
312
    int len;
D
Daniel Veillard 已提交
313

314
    if ((str == NULL) || (virLogBuffer == NULL) || (virLogSize <= 0))
D
Daniel Veillard 已提交
315
        return;
316
    len = strlen(str);
E
Eric Blake 已提交
317
    if (len >= virLogSize)
D
Daniel Veillard 已提交
318 319 320 321 322
        return;

    /*
     * copy the data and reset the end, we cycle over the end of the buffer
     */
323 324
    if (virLogEnd + len >= virLogSize) {
        tmp = virLogSize - virLogEnd;
D
Daniel Veillard 已提交
325
        memcpy(&virLogBuffer[virLogEnd], str, tmp);
326
        memcpy(&virLogBuffer[0], &str[tmp], len - tmp);
D
Daniel Veillard 已提交
327 328 329 330 331
        virLogEnd = len - tmp;
    } else {
        memcpy(&virLogBuffer[virLogEnd], str, len);
        virLogEnd += len;
    }
E
Eric Blake 已提交
332
    virLogBuffer[virLogEnd] = 0;
D
Daniel Veillard 已提交
333 334 335 336
    /*
     * Update the log length, and if full move the start index
     */
    virLogLen += len;
337 338 339
    if (virLogLen > virLogSize) {
        tmp = virLogLen - virLogSize;
        virLogLen = virLogSize;
D
Daniel Veillard 已提交
340
        virLogStart += tmp;
341 342
        if (virLogStart >= virLogSize)
            virLogStart -= virLogSize;
D
Daniel Veillard 已提交
343 344 345
    }
}

346 347 348 349

static void
virLogDumpAllFD(const char *msg, int len)
{
350 351
    int i, found = 0;

352 353 354
    if (len <= 0)
        len = strlen(msg);

355 356
    for (i = 0; i < virLogNbOutputs;i++) {
        if (virLogOutputs[i].f == virLogOutputToFd) {
357
            int fd = (intptr_t) virLogOutputs[i].data;
358 359

            if (fd >= 0) {
360
                ignore_value(safewrite(fd, msg, len));
361 362 363 364 365
                found = 1;
            }
        }
    }
    if (!found)
366
        ignore_value(safewrite(STDERR_FILENO, msg, len));
367 368
}

369

370 371 372 373 374 375 376 377
/**
 * virLogEmergencyDumpAll:
 * @signum: the signal number
 *
 * Emergency function called, possibly from a signal handler.
 * It need to output the debug ring buffer through the log
 * output which are safe to use from a signal handler.
 * In case none is found it is emitted to standard error.
D
Daniel Veillard 已提交
378
 */
379
void
380 381
virLogEmergencyDumpAll(int signum)
{
382
    int len;
C
Christophe Fergeau 已提交
383
    int oldLogStart, oldLogLen;
D
Daniel Veillard 已提交
384

385
    switch (signum) {
D
Daniel Veillard 已提交
386
#ifdef SIGFPE
387
        case SIGFPE:
388
            virLogDumpAllFD("Caught signal Floating-point exception", -1);
389
            break;
D
Daniel Veillard 已提交
390 391
#endif
#ifdef SIGSEGV
392
        case SIGSEGV:
393
            virLogDumpAllFD("Caught Segmentation violation", -1);
394
            break;
D
Daniel Veillard 已提交
395 396
#endif
#ifdef SIGILL
397
        case SIGILL:
398
            virLogDumpAllFD("Caught illegal instruction", -1);
399
            break;
D
Daniel Veillard 已提交
400 401
#endif
#ifdef SIGABRT
402
        case SIGABRT:
403
            virLogDumpAllFD("Caught abort signal", -1);
404
            break;
D
Daniel Veillard 已提交
405 406
#endif
#ifdef SIGBUS
407
        case SIGBUS:
408
            virLogDumpAllFD("Caught bus error", -1);
409
            break;
D
Daniel Veillard 已提交
410 411
#endif
#ifdef SIGUSR2
412
        case SIGUSR2:
413
            virLogDumpAllFD("Caught User-defined signal 2", -1);
414
            break;
D
Daniel Veillard 已提交
415
#endif
416
        default:
417
            virLogDumpAllFD("Caught unexpected signal", -1);
418 419
            break;
    }
420 421
    if ((virLogBuffer == NULL) || (virLogSize <= 0)) {
        virLogDumpAllFD(" internal log buffer deactivated\n", -1);
422
        return;
423
    }
424

425 426
    virLogDumpAllFD(" dumping internal log buffer:\n", -1);
    virLogDumpAllFD("\n\n    ====== start of log =====\n\n", -1);
427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448

    /*
     * Since we can't lock the buffer safely from a signal handler
     * we mark it as empty in case of concurrent access, and proceed
     * with the data, at worse we will output something a bit weird
     * if another thread start logging messages at the same time.
     * Note that virLogStr() uses virLogEnd for the computations and
     * writes to the buffer and only then updates virLogLen and virLogStart
     * so it's best to reset it first.
     */
    oldLogStart = virLogStart;
    oldLogLen = virLogLen;
    virLogEnd = 0;
    virLogLen = 0;
    virLogStart = 0;

    while (oldLogLen > 0) {
        if (oldLogStart + oldLogLen < virLogSize) {
            virLogBuffer[oldLogStart + oldLogLen] = 0;
            virLogDumpAllFD(&virLogBuffer[oldLogStart], oldLogLen);
            oldLogStart += oldLogLen;
            oldLogLen = 0;
D
Daniel Veillard 已提交
449
        } else {
450
            len = virLogSize - oldLogStart;
451
            virLogBuffer[virLogSize] = 0;
452 453 454
            virLogDumpAllFD(&virLogBuffer[oldLogStart], len);
            oldLogLen -= len;
            oldLogStart = 0;
D
Daniel Veillard 已提交
455 456
        }
    }
457
    virLogDumpAllFD("\n\n     ====== end of log =====\n\n", -1);
D
Daniel Veillard 已提交
458
}
459

460

D
Daniel Veillard 已提交
461 462 463 464 465 466 467 468 469 470
/**
 * 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.
 */
471 472 473
int
virLogSetDefaultPriority(virLogPriority priority)
{
474
    if ((priority < VIR_LOG_DEBUG) || (priority > VIR_LOG_ERROR)) {
475
        VIR_WARN("Ignoring invalid log level setting.");
476
        return -1;
477
    }
478 479 480
    if (virLogInitialize() < 0)
        return -1;

D
Daniel Veillard 已提交
481
    virLogDefaultPriority = priority;
482
    return 0;
D
Daniel Veillard 已提交
483 484
}

485

D
Daniel Veillard 已提交
486 487 488 489 490 491 492
/**
 * virLogResetFilters:
 *
 * Removes the set of logging filters defined.
 *
 * Returns the number of filters removed
 */
493 494 495
static int
virLogResetFilters(void)
{
D
Daniel Veillard 已提交
496 497 498 499 500 501
    int i;

    for (i = 0; i < virLogNbFilters;i++)
        VIR_FREE(virLogFilters[i].match);
    VIR_FREE(virLogFilters);
    virLogNbFilters = 0;
502
    return i;
D
Daniel Veillard 已提交
503 504
}

505

D
Daniel Veillard 已提交
506 507 508 509
/**
 * virLogDefineFilter:
 * @match: the pattern to match
 * @priority: the priority to give to messages matching the pattern
510
 * @flags: extra flags, see virLogFilterFlags enum
D
Daniel Veillard 已提交
511 512 513 514 515 516 517 518
 *
 * 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
 */
519 520 521 522
int
virLogDefineFilter(const char *match,
                   virLogPriority priority,
                   unsigned int flags)
523
{
D
Daniel Veillard 已提交
524 525 526
    int i;
    char *mdup = NULL;

527
    virCheckFlags(VIR_LOG_STACK_TRACE, -1);
528

D
Daniel Veillard 已提交
529 530
    if ((match == NULL) || (priority < VIR_LOG_DEBUG) ||
        (priority > VIR_LOG_ERROR))
531
        return -1;
D
Daniel Veillard 已提交
532 533 534 535 536 537 538 539 540 541

    virLogLock();
    for (i = 0;i < virLogNbFilters;i++) {
        if (STREQ(virLogFilters[i].match, match)) {
            virLogFilters[i].priority = priority;
            goto cleanup;
        }
    }

    mdup = strdup(match);
542
    if (mdup == NULL) {
D
Daniel Veillard 已提交
543 544 545 546 547 548 549 550 551 552 553
        i = -1;
        goto cleanup;
    }
    i = virLogNbFilters;
    if (VIR_REALLOC_N(virLogFilters, virLogNbFilters + 1)) {
        i = -1;
        VIR_FREE(mdup);
        goto cleanup;
    }
    virLogFilters[i].match = mdup;
    virLogFilters[i].priority = priority;
554
    virLogFilters[i].flags = flags;
D
Daniel Veillard 已提交
555 556 557
    virLogNbFilters++;
cleanup:
    virLogUnlock();
558
    return i;
D
Daniel Veillard 已提交
559 560
}

561

D
Daniel Veillard 已提交
562 563 564 565 566 567 568 569 570 571
/**
 * virLogFiltersCheck:
 * @input: the input string
 *
 * Check the input of the message against the existing filters. Currently
 * the match is just a substring check of the category used as the input
 * string, a more subtle approach could be used instead
 *
 * Returns 0 if not matched or the new priority if found.
 */
572 573 574 575
static int
virLogFiltersCheck(const char *input,
                   unsigned int *flags)
{
D
Daniel Veillard 已提交
576 577 578 579 580 581 582
    int ret = 0;
    int i;

    virLogLock();
    for (i = 0;i < virLogNbFilters;i++) {
        if (strstr(input, virLogFilters[i].match)) {
            ret = virLogFilters[i].priority;
583
            *flags = virLogFilters[i].flags;
D
Daniel Veillard 已提交
584 585 586 587
            break;
        }
    }
    virLogUnlock();
588
    return ret;
D
Daniel Veillard 已提交
589 590
}

591

D
Daniel Veillard 已提交
592 593 594 595 596 597 598
/**
 * virLogResetOutputs:
 *
 * Removes the set of logging output defined.
 *
 * Returns the number of output removed
 */
599 600 601
static int
virLogResetOutputs(void)
{
D
Daniel Veillard 已提交
602 603 604 605 606
    int i;

    for (i = 0;i < virLogNbOutputs;i++) {
        if (virLogOutputs[i].c != NULL)
            virLogOutputs[i].c(virLogOutputs[i].data);
607
        VIR_FREE(virLogOutputs[i].name);
D
Daniel Veillard 已提交
608 609 610 611
    }
    VIR_FREE(virLogOutputs);
    i = virLogNbOutputs;
    virLogNbOutputs = 0;
612
    return i;
D
Daniel Veillard 已提交
613 614
}

615

D
Daniel Veillard 已提交
616 617 618
/**
 * virLogDefineOutput:
 * @f: the function to call to output a message
619
 * @c: the function to call to close the output (or NULL)
D
Daniel Veillard 已提交
620 621
 * @data: extra data passed as first arg to the function
 * @priority: minimal priority for this filter, use 0 for none
622 623
 * @dest: where to send output of this priority
 * @name: optional name data associated with an output
D
Daniel Veillard 已提交
624 625 626 627 628 629 630
 * @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
 */
631 632 633 634 635 636 637 638
int
virLogDefineOutput(virLogOutputFunc f,
                   virLogCloseFunc c,
                   void *data,
                   virLogPriority priority,
                   virLogDestination dest,
                   const char *name,
                   unsigned int flags)
639
{
D
Daniel Veillard 已提交
640
    int ret = -1;
641
    char *ndup = NULL;
D
Daniel Veillard 已提交
642

643 644
    virCheckFlags(0, -1);

D
Daniel Veillard 已提交
645
    if (f == NULL)
646
        return -1;
D
Daniel Veillard 已提交
647

648 649
    if (dest == VIR_LOG_TO_SYSLOG || dest == VIR_LOG_TO_FILE) {
        if (name == NULL)
650
            return -1;
651 652
        ndup = strdup(name);
        if (ndup == NULL)
653
            return -1;
654 655
    }

D
Daniel Veillard 已提交
656 657
    virLogLock();
    if (VIR_REALLOC_N(virLogOutputs, virLogNbOutputs + 1)) {
658
        VIR_FREE(ndup);
D
Daniel Veillard 已提交
659 660 661
        goto cleanup;
    }
    ret = virLogNbOutputs++;
662
    virLogOutputs[ret].logVersion = true;
D
Daniel Veillard 已提交
663 664 665 666
    virLogOutputs[ret].f = f;
    virLogOutputs[ret].c = c;
    virLogOutputs[ret].data = data;
    virLogOutputs[ret].priority = priority;
667 668
    virLogOutputs[ret].dest = dest;
    virLogOutputs[ret].name = ndup;
D
Daniel Veillard 已提交
669 670
cleanup:
    virLogUnlock();
671
    return ret;
D
Daniel Veillard 已提交
672 673
}

674

675 676
static int
virLogFormatString(char **msg,
677
                   int linenr,
678
                   const char *funcname,
679
                   virLogPriority priority,
680 681 682
                   const char *str)
{
    int ret;
683 684 685 686 687 688 689 690

    /*
     * 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.
     */
691
    if ((funcname != NULL)) {
692
        ret = virAsprintf(msg, "%d: %s : %s:%d : %s\n",
693 694
                          virThreadSelfID(), virLogPriorityString(priority),
                          funcname, linenr, str);
695
    } else {
696 697 698
        ret = virAsprintf(msg, "%d: %s : %s\n",
                          virThreadSelfID(), virLogPriorityString(priority),
                          str);
699 700 701 702
    }
    return ret;
}

703

704
static int
705 706
virLogVersionString(const char **rawmsg,
                    char **msg)
707 708 709 710 711 712 713 714 715 716 717 718 719 720
{
#ifdef PACKAGER_VERSION
# ifdef PACKAGER
#  define LOG_VERSION_STRING \
    "libvirt version: " VERSION ", package: " PACKAGER_VERSION " (" PACKAGER ")"
# else
#  define LOG_VERSION_STRING \
    "libvirt version: " VERSION ", package: " PACKAGER_VERSION
# endif
#else
# define LOG_VERSION_STRING  \
    "libvirt version: " VERSION
#endif

721
    *rawmsg = LOG_VERSION_STRING;
722
    return virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, LOG_VERSION_STRING);
723 724
}

725

D
Daniel Veillard 已提交
726 727
/**
 * virLogMessage:
728
 * @source: where is that message coming from
D
Daniel Veillard 已提交
729
 * @priority: the priority level
730
 * @filename: file where the message was emitted
731
 * @linenr: line where the message was emitted
732
 * @funcname: the function emitting the (debug) message
733
 * @metadata: NULL or metadata array, terminated by an item with NULL key
D
Daniel Veillard 已提交
734 735 736
 * @fmt: the string format
 * @...: the arguments
 *
E
Eric Blake 已提交
737
 * Call the libvirt logger with some information. Based on the configuration
D
Daniel Veillard 已提交
738 739
 * the message may be stored, sent to output or just discarded
 */
740
void
741
virLogMessage(virLogSource source,
742
              virLogPriority priority,
743
              const char *filename,
744
              int linenr,
745
              const char *funcname,
746
              virLogMetadataPtr metadata,
747
              const char *fmt, ...)
748 749 750
{
    va_list ap;
    va_start(ap, fmt);
751
    virLogVMessage(source, priority,
752
                   filename, linenr, funcname,
753
                   metadata, fmt, ap);
754 755 756
    va_end(ap);
}

757

758 759
/**
 * virLogVMessage:
760
 * @source: where is that message coming from
761
 * @priority: the priority level
762
 * @filename: file where the message was emitted
763
 * @linenr: line where the message was emitted
764
 * @funcname: the function emitting the (debug) message
765
 * @metadata: NULL or metadata array, terminated by an item with NULL key
766 767 768 769 770 771
 * @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
 */
772
void
773
virLogVMessage(virLogSource source,
774
               virLogPriority priority,
775
               const char *filename,
776
               int linenr,
777
               const char *funcname,
M
Miloslav Trmač 已提交
778
               virLogMetadataPtr metadata,
779 780
               const char *fmt,
               va_list vargs)
781
{
782
    static bool logVersionStderr = true;
D
Daniel Veillard 已提交
783
    char *str = NULL;
784
    char *msg = NULL;
785
    char timestamp[VIR_TIME_STRING_BUFLEN];
786
    int fprio, i, ret;
787
    int saved_errno = errno;
788
    int emit = 1;
789
    unsigned int filterflags = 0;
D
Daniel Veillard 已提交
790

791 792
    if (virLogInitialize() < 0)
        return;
D
Daniel Veillard 已提交
793 794

    if (fmt == NULL)
795
        goto cleanup;
D
Daniel Veillard 已提交
796 797 798 799

    /*
     * check against list of specific logging patterns
     */
800
    fprio = virLogFiltersCheck(filename, &filterflags);
D
Daniel Veillard 已提交
801 802
    if (fprio == 0) {
        if (priority < virLogDefaultPriority)
803
            emit = 0;
804
    } else if (priority < fprio) {
805
        emit = 0;
806
    }
D
Daniel Veillard 已提交
807

808 809 810
    if ((emit == 0) && ((virLogBuffer == NULL) || (virLogSize <= 0)))
        goto cleanup;

D
Daniel Veillard 已提交
811 812 813
    /*
     * serialize the error message, add level and timestamp
     */
814
    if (virVasprintf(&str, fmt, vargs) < 0) {
815
        goto cleanup;
E
Eric Blake 已提交
816
    }
D
Daniel Veillard 已提交
817

818
    ret = virLogFormatString(&msg, linenr, funcname, priority, str);
819 820
    if (ret < 0)
        goto cleanup;
D
Daniel Veillard 已提交
821

822 823
    if (virTimeStringNowRaw(timestamp) < 0)
        timestamp[0] = '\0';
824

D
Daniel Veillard 已提交
825
    /*
826 827
     * Log based on defaults, first store in the history buffer,
     * then if emit push the message on the outputs defined, if none
D
Daniel Veillard 已提交
828 829 830 831 832
     * use stderr.
     * NOTE: the locking is a single point of contention for multiple
     *       threads, but avoid intermixing. Maybe set up locks per output
     *       to improve paralellism.
     */
833 834 835 836
    virLogLock();
    virLogStr(timestamp);
    virLogStr(msg);
    virLogUnlock();
837 838 839
    if (emit == 0)
        goto cleanup;

D
Daniel Veillard 已提交
840
    virLogLock();
841
    for (i = 0; i < virLogNbOutputs; i++) {
842 843
        if (priority >= virLogOutputs[i].priority) {
            if (virLogOutputs[i].logVersion) {
844
                const char *rawver;
845
                char *ver = NULL;
846
                if (virLogVersionString(&rawver, &ver) >= 0)
847
                    virLogOutputs[i].f(VIR_LOG_FROM_FILE, VIR_LOG_INFO,
848
                                       __FILE__, __LINE__, __func__,
M
Miloslav Trmač 已提交
849
                                       timestamp, NULL, 0, rawver, ver,
850 851 852 853
                                       virLogOutputs[i].data);
                VIR_FREE(ver);
                virLogOutputs[i].logVersion = false;
            }
854
            virLogOutputs[i].f(source, priority,
855
                               filename, linenr, funcname,
M
Miloslav Trmač 已提交
856
                               timestamp, metadata, filterflags,
857
                               str, msg, virLogOutputs[i].data);
858
        }
D
Daniel Veillard 已提交
859
    }
860
    if ((virLogNbOutputs == 0) && (source != VIR_LOG_FROM_ERROR)) {
861
        if (logVersionStderr) {
862
            const char *rawver;
863
            char *ver = NULL;
864
            if (virLogVersionString(&rawver, &ver) >= 0)
865
                virLogOutputToFd(VIR_LOG_FROM_FILE, VIR_LOG_INFO,
866
                                 __FILE__, __LINE__, __func__,
M
Miloslav Trmač 已提交
867
                                 timestamp, NULL, 0, rawver, ver,
868
                                 (void *) STDERR_FILENO);
869 870 871
            VIR_FREE(ver);
            logVersionStderr = false;
        }
872
        virLogOutputToFd(source, priority,
873
                         filename, linenr, funcname,
M
Miloslav Trmač 已提交
874
                         timestamp, metadata, filterflags,
875
                         str, msg, (void *) STDERR_FILENO);
876
    }
D
Daniel Veillard 已提交
877 878
    virLogUnlock();

879
cleanup:
880
    VIR_FREE(str);
881
    VIR_FREE(msg);
882
    errno = saved_errno;
D
Daniel Veillard 已提交
883 884
}

885

886 887
static void
virLogStackTraceToFd(int fd)
888 889 890 891 892
{
    void *array[100];
    int size;
    static bool doneWarning = false;
    const char *msg = "Stack trace not available on this platform\n";
893 894 895 896 897 898 899

#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) {
900 901 902
        ignore_value(safewrite(fd, msg, strlen(msg)));
        doneWarning = true;
    }
903
#undef STRIP_DEPTH
904 905
}

906
static void
907
virLogOutputToFd(virLogSource source ATTRIBUTE_UNUSED,
908
                 virLogPriority priority ATTRIBUTE_UNUSED,
909
                 const char *filename ATTRIBUTE_UNUSED,
910
                 int linenr ATTRIBUTE_UNUSED,
911
                 const char *funcname ATTRIBUTE_UNUSED,
912
                 const char *timestamp,
M
Miloslav Trmač 已提交
913
                 virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
914 915 916 917
                 unsigned int flags,
                 const char *rawstr ATTRIBUTE_UNUSED,
                 const char *str,
                 void *data)
918
{
919
    int fd = (intptr_t) data;
920
    char *msg;
D
Daniel Veillard 已提交
921 922

    if (fd < 0)
923
        return;
924 925

    if (virAsprintf(&msg, "%s: %s", timestamp, str) < 0)
926
        return;
927

928
    ignore_value(safewrite(fd, msg, strlen(msg)));
929 930
    VIR_FREE(msg);

931 932
    if (flags & VIR_LOG_STACK_TRACE)
        virLogStackTraceToFd(fd);
D
Daniel Veillard 已提交
933 934
}

935 936 937

static void
virLogCloseFd(void *data)
938
{
939
    int fd = (intptr_t) data;
D
Daniel Veillard 已提交
940

941
    VIR_LOG_CLOSE(fd);
D
Daniel Veillard 已提交
942 943
}

944 945 946 947

static int
virLogAddOutputToStderr(virLogPriority priority)
{
948 949
    if (virLogDefineOutput(virLogOutputToFd, NULL, (void *)2L, priority,
                           VIR_LOG_TO_STDERR, NULL, 0) < 0)
950 951
        return -1;
    return 0;
D
Daniel Veillard 已提交
952 953
}

954 955 956 957 958

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

961
    fd = open(file, O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR);
D
Daniel Veillard 已提交
962
    if (fd < 0)
963
        return -1;
964 965
    if (virLogDefineOutput(virLogOutputToFd, virLogCloseFd,
                           (void *)(intptr_t)fd,
966
                           priority, VIR_LOG_TO_FILE, file, 0) < 0) {
967
        VIR_FORCE_CLOSE(fd);
968
        return -1;
D
Daniel Veillard 已提交
969
    }
970
    return 0;
D
Daniel Veillard 已提交
971 972
}

973

D
Daniel Veillard 已提交
974
#if HAVE_SYSLOG_H
975 976
static int
virLogPrioritySyslog(virLogPriority priority)
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991
{
    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;
    }
}

992 993

static void
994
virLogOutputToSyslog(virLogSource source ATTRIBUTE_UNUSED,
995
                     virLogPriority priority,
996
                     const char *filename ATTRIBUTE_UNUSED,
997
                     int linenr ATTRIBUTE_UNUSED,
998
                     const char *funcname ATTRIBUTE_UNUSED,
999
                     const char *timestamp ATTRIBUTE_UNUSED,
M
Miloslav Trmač 已提交
1000
                     virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
1001 1002 1003 1004
                     unsigned int flags,
                     const char *rawstr ATTRIBUTE_UNUSED,
                     const char *str,
                     void *data ATTRIBUTE_UNUSED)
1005
{
1006
    virCheckFlags(VIR_LOG_STACK_TRACE,);
1007

1008
    syslog(virLogPrioritySyslog(priority), "%s", str);
D
Daniel Veillard 已提交
1009 1010
}

1011 1012
static char *current_ident = NULL;

1013 1014 1015 1016

static void
virLogCloseSyslog(void *data ATTRIBUTE_UNUSED)
{
D
Daniel Veillard 已提交
1017
    closelog();
1018
    VIR_FREE(current_ident);
D
Daniel Veillard 已提交
1019 1020
}

1021 1022 1023 1024 1025

static int
virLogAddOutputToSyslog(virLogPriority priority,
                        const char *ident)
{
1026 1027 1028 1029 1030 1031
    /*
     * ident needs to be kept around on Solaris
     */
    VIR_FREE(current_ident);
    current_ident = strdup(ident);
    if (current_ident == NULL)
1032
        return -1;
1033 1034

    openlog(current_ident, 0, 0);
D
Daniel Veillard 已提交
1035
    if (virLogDefineOutput(virLogOutputToSyslog, virLogCloseSyslog, NULL,
1036
                           priority, VIR_LOG_TO_SYSLOG, ident, 0) < 0) {
D
Daniel Veillard 已提交
1037
        closelog();
1038
        VIR_FREE(current_ident);
1039
        return -1;
D
Daniel Veillard 已提交
1040
    }
1041
    return 0;
D
Daniel Veillard 已提交
1042
}
D
Daniel P. Berrange 已提交
1043 1044


E
Eric Blake 已提交
1045
# if USE_JOURNALD
1046 1047 1048 1049 1050
#  define IOVEC_SET(iov, data, size)            \
    do {                                        \
        struct iovec *_i = &(iov);              \
        _i->iov_base = (void*)(data);           \
        _i->iov_len = (size);                   \
D
Daniel P. Berrange 已提交
1051 1052
    } while (0)

1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 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
#  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 已提交
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127

static int journalfd = -1;

static void
virLogOutputToJournald(virLogSource source,
                       virLogPriority priority,
                       const char *filename,
                       int linenr,
                       const char *funcname,
                       const char *timestamp ATTRIBUTE_UNUSED,
M
Miloslav Trmač 已提交
1128
                       virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
D
Daniel P. Berrange 已提交
1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
                       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";

1148 1149 1150 1151
#  define NUM_FIELDS 6
    struct iovec iov[NUM_FIELDS * 5];
    char iov_bufs[NUM_FIELDS][JOURNAL_BUF_SIZE];
    struct journalState state;
D
Daniel P. Berrange 已提交
1152

1153 1154 1155 1156
    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 已提交
1157

1158 1159 1160 1161 1162 1163 1164
    journalAddString(&state ,"MESSAGE", rawstr);
    journalAddInt(&state, "PRIORITY", priority);
    journalAddString(&state, "LIBVIRT_SOURCE",
                     virLogSourceTypeToString(source));
    journalAddString(&state, "CODE_FILE", filename);
    journalAddInt(&state, "CODE_LINE", linenr);
    journalAddString(&state, "CODE_FUNC", funcname);
D
Daniel P. Berrange 已提交
1165 1166 1167 1168 1169 1170 1171 1172 1173 1174

    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;
1175
    mh.msg_iovlen = state.iov - iov;
D
Daniel P. Berrange 已提交
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198

    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;

1199
    if (writev(buffd, iov, state.iov - iov) < 0)
D
Daniel P. Berrange 已提交
1200 1201 1202 1203 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
        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;

    sendmsg(journalfd, &mh, MSG_NOSIGNAL);

cleanup:
    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 已提交
1244
# endif /* USE_JOURNALD */
D
Daniel Veillard 已提交
1245 1246 1247 1248 1249 1250
#endif /* HAVE_SYSLOG_H */

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

1251

D
Daniel Veillard 已提交
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274
/**
 * 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
 *    0: everything
 *    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.
 *
 * Returns the number of output parsed and installed or -1 in case of error
 */
1275 1276 1277
int
virLogParseOutputs(const char *outputs)
{
D
Daniel Veillard 已提交
1278 1279
    const char *cur = outputs, *str;
    char *name;
1280
    char *abspath;
1281
    virLogPriority prio;
1282 1283
    int ret = -1;
    int count = 0;
D
Daniel Veillard 已提交
1284 1285

    if (cur == NULL)
1286
        return -1;
D
Daniel Veillard 已提交
1287

1288 1289
    VIR_DEBUG("outputs=%s", outputs);

D
Daniel Veillard 已提交
1290 1291 1292
    virSkipSpaces(&cur);
    while (*cur != 0) {
        prio= virParseNumber(&cur);
1293
        if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
1294
            goto cleanup;
D
Daniel Veillard 已提交
1295
        if (*cur != ':')
1296
            goto cleanup;
D
Daniel Veillard 已提交
1297 1298 1299 1300
        cur++;
        if (STREQLEN(cur, "stderr", 6)) {
            cur += 6;
            if (virLogAddOutputToStderr(prio) == 0)
1301
                count++;
D
Daniel Veillard 已提交
1302 1303 1304
        } else if (STREQLEN(cur, "syslog", 6)) {
            cur += 6;
            if (*cur != ':')
1305
                goto cleanup;
D
Daniel Veillard 已提交
1306 1307 1308 1309 1310
            cur++;
            str = cur;
            while ((*cur != 0) && (!IS_SPACE(cur)))
                cur++;
            if (str == cur)
1311
                goto cleanup;
D
Daniel Veillard 已提交
1312 1313 1314
#if HAVE_SYSLOG_H
            name = strndup(str, cur - str);
            if (name == NULL)
1315
                goto cleanup;
D
Daniel Veillard 已提交
1316
            if (virLogAddOutputToSyslog(prio, name) == 0)
1317
                count++;
D
Daniel Veillard 已提交
1318 1319 1320 1321 1322
            VIR_FREE(name);
#endif /* HAVE_SYSLOG_H */
        } else if (STREQLEN(cur, "file", 4)) {
            cur += 4;
            if (*cur != ':')
1323
                goto cleanup;
D
Daniel Veillard 已提交
1324 1325 1326 1327 1328
            cur++;
            str = cur;
            while ((*cur != 0) && (!IS_SPACE(cur)))
                cur++;
            if (str == cur)
1329
                goto cleanup;
D
Daniel Veillard 已提交
1330 1331
            name = strndup(str, cur - str);
            if (name == NULL)
1332
                goto cleanup;
1333 1334 1335 1336 1337
            if (virFileAbsPath(name, &abspath) < 0) {
                VIR_FREE(name);
                return -1; /* skip warning here because setting was fine */
            }
            if (virLogAddOutputToFile(prio, abspath) == 0)
1338
                count++;
D
Daniel Veillard 已提交
1339
            VIR_FREE(name);
1340
            VIR_FREE(abspath);
D
Daniel P. Berrange 已提交
1341 1342
        } else if (STREQLEN(cur, "journald", 8)) {
            cur += 8;
E
Eric Blake 已提交
1343
#if USE_JOURNALD
D
Daniel P. Berrange 已提交
1344 1345
            if (virLogAddOutputToJournald(prio) == 0)
                count++;
E
Eric Blake 已提交
1346
#endif /* USE_JOURNALD */
D
Daniel Veillard 已提交
1347
        } else {
1348
            goto cleanup;
D
Daniel Veillard 已提交
1349 1350 1351
        }
        virSkipSpaces(&cur);
    }
1352 1353 1354
    ret = count;
cleanup:
    if (ret == -1)
1355
        VIR_WARN("Ignoring invalid log output setting.");
1356
    return ret;
D
Daniel Veillard 已提交
1357 1358
}

1359

D
Daniel Veillard 已提交
1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377
/**
 * 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.
 *
 * Returns the number of filter parsed and installed or -1 in case of error
 */
1378 1379 1380
int
virLogParseFilters(const char *filters)
{
D
Daniel Veillard 已提交
1381 1382
    const char *cur = filters, *str;
    char *name;
1383
    virLogPriority prio;
1384 1385
    int ret = -1;
    int count = 0;
D
Daniel Veillard 已提交
1386 1387

    if (cur == NULL)
1388
        return -1;
D
Daniel Veillard 已提交
1389 1390 1391

    virSkipSpaces(&cur);
    while (*cur != 0) {
1392
        unsigned int flags = 0;
D
Daniel Veillard 已提交
1393
        prio= virParseNumber(&cur);
1394
        if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
1395
            goto cleanup;
D
Daniel Veillard 已提交
1396
        if (*cur != ':')
1397
            goto cleanup;
D
Daniel Veillard 已提交
1398
        cur++;
1399 1400 1401 1402
        if (*cur == '+') {
            flags |= VIR_LOG_STACK_TRACE;
            cur++;
        }
D
Daniel Veillard 已提交
1403 1404 1405 1406
        str = cur;
        while ((*cur != 0) && (!IS_SPACE(cur)))
            cur++;
        if (str == cur)
1407
            goto cleanup;
D
Daniel Veillard 已提交
1408 1409
        name = strndup(str, cur - str);
        if (name == NULL)
1410
            goto cleanup;
1411
        if (virLogDefineFilter(name, prio, flags) >= 0)
1412
            count++;
D
Daniel Veillard 已提交
1413 1414 1415
        VIR_FREE(name);
        virSkipSpaces(&cur);
    }
1416 1417 1418
    ret = count;
cleanup:
    if (ret == -1)
1419
        VIR_WARN("Ignoring invalid log filter setting.");
1420
    return ret;
D
Daniel Veillard 已提交
1421
}
1422

1423

1424 1425 1426 1427 1428
/**
 * virLogGetDefaultPriority:
 *
 * Returns the current logging priority level.
 */
1429 1430 1431
virLogPriority
virLogGetDefaultPriority(void)
{
1432
    return virLogDefaultPriority;
1433 1434
}

1435

1436 1437 1438 1439 1440 1441 1442
/**
 * virLogGetFilters:
 *
 * Returns a string listing the current filters, in the format originally
 * specified in the config file or environment. Caller must free the
 * result.
 */
1443 1444 1445
char *
virLogGetFilters(void)
{
1446 1447 1448 1449 1450
    int i;
    virBuffer filterbuf = VIR_BUFFER_INITIALIZER;

    virLogLock();
    for (i = 0; i < virLogNbFilters; i++) {
1451 1452 1453 1454 1455 1456
        const char *sep = ":";
        if (virLogFilters[i].flags & VIR_LOG_STACK_TRACE)
            sep = ":+";
        virBufferAsprintf(&filterbuf, "%d%s%s ",
                          virLogFilters[i].priority,
                          sep,
1457 1458 1459 1460
                          virLogFilters[i].match);
    }
    virLogUnlock();

1461 1462
    if (virBufferError(&filterbuf)) {
        virBufferFreeAndReset(&filterbuf);
1463
        return NULL;
1464
    }
1465 1466 1467 1468

    return virBufferContentAndReset(&filterbuf);
}

1469

1470 1471 1472 1473 1474 1475 1476
/**
 * virLogGetOutputs:
 *
 * Returns a string listing the current outputs, in the format originally
 * specified in the config file or environment. Caller must free the
 * result.
 */
1477 1478 1479
char *
virLogGetOutputs(void)
{
1480 1481 1482 1483 1484
    int i;
    virBuffer outputbuf = VIR_BUFFER_INITIALIZER;

    virLogLock();
    for (i = 0; i < virLogNbOutputs; i++) {
1485
        virLogDestination dest = virLogOutputs[i].dest;
1486
        if (i)
1487
            virBufferAsprintf(&outputbuf, " ");
1488 1489 1490
        switch (dest) {
            case VIR_LOG_TO_SYSLOG:
            case VIR_LOG_TO_FILE:
1491
                virBufferAsprintf(&outputbuf, "%d:%s:%s",
1492 1493 1494 1495 1496
                                  virLogOutputs[i].priority,
                                  virLogOutputString(dest),
                                  virLogOutputs[i].name);
                break;
            default:
1497
                virBufferAsprintf(&outputbuf, "%d:%s",
1498 1499 1500 1501 1502 1503
                                  virLogOutputs[i].priority,
                                  virLogOutputString(dest));
        }
    }
    virLogUnlock();

1504 1505
    if (virBufferError(&outputbuf)) {
        virBufferFreeAndReset(&outputbuf);
1506
        return NULL;
1507
    }
1508 1509 1510 1511

    return virBufferContentAndReset(&outputbuf);
}

1512

1513 1514 1515 1516 1517
/**
 * virLogGetNbFilters:
 *
 * Returns the current number of defined log filters.
 */
1518 1519 1520
int
virLogGetNbFilters(void)
{
1521
    return virLogNbFilters;
1522 1523
}

1524

1525 1526 1527 1528 1529
/**
 * virLogGetNbOutputs:
 *
 * Returns the current number of defined log outputs.
 */
1530 1531 1532
int
virLogGetNbOutputs(void)
{
1533
    return virLogNbOutputs;
1534
}
1535

1536

1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549
/**
 * 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
 *
 * Returns the parsed log level or -1 on error.
 */
1550 1551 1552
int
virLogParseDefaultPriority(const char *priority)
{
1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563
    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
1564
        VIR_WARN("Ignoring invalid log level setting");
1565 1566 1567 1568

    return ret;
}

1569

1570 1571 1572 1573 1574 1575
/**
 * virLogSetFromEnv:
 *
 * Sets virLogDefaultPriority, virLogFilters and virLogOutputs based on
 * environment variables.
 */
1576 1577 1578
void
virLogSetFromEnv(void)
{
1579 1580 1581 1582 1583 1584 1585
    char *debugEnv;

    debugEnv = getenv("LIBVIRT_DEBUG");
    if (debugEnv && *debugEnv)
        virLogParseDefaultPriority(debugEnv);
    debugEnv = getenv("LIBVIRT_LOG_FILTERS");
    if (debugEnv && *debugEnv)
1586
        virLogParseFilters(debugEnv);
1587 1588
    debugEnv = getenv("LIBVIRT_LOG_OUTPUTS");
    if (debugEnv && *debugEnv)
1589
        virLogParseOutputs(debugEnv);
1590
}