You need to sign in or sign up before continuing.
logging.c 29.0 KB
Newer Older
1 2 3
/*
 * logging.c: internal logging and debugging
 *
4
 * Copyright (C) 2008, 2010-2011 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * 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
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 */

#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>
D
Daniel Veillard 已提交
33
#if HAVE_SYSLOG_H
34
# include <syslog.h>
D
Daniel Veillard 已提交
35 36
#endif

37
#include "ignore-value.h"
38
#include "logging.h"
D
Daniel Veillard 已提交
39 40
#include "memory.h"
#include "util.h"
41
#include "buf.h"
42
#include "threads.h"
43
#include "files.h"
44

D
Daniel Veillard 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
/*
 * Macro used to format the message as a string in virLogMessage
 * and borrowed from libxml2 (also used in virRaiseError)
 */
#define VIR_GET_VAR_STR(msg, str) {				\
    int       size, prev_size = -1;				\
    int       chars;						\
    char      *larger;						\
    va_list   ap;						\
                                                                \
    str = (char *) malloc(150);					\
    if (str != NULL) {						\
                                                                \
    size = 150;							\
                                                                \
    while (1) {							\
        va_start(ap, msg);					\
        chars = vsnprintf(str, size, msg, ap);			\
        va_end(ap);						\
        if ((chars > -1) && (chars < size)) {			\
            if (prev_size == chars) {				\
                break;						\
            } else {						\
                prev_size = chars;				\
            }							\
        }							\
        if (chars > -1)						\
            size += chars + 1;					\
        else							\
            size += 100;					\
        if ((larger = (char *) realloc(str, size)) == NULL) {	\
            break;						\
        }							\
        str = larger;						\
    }}								\
}

/*
 * A logging buffer to keep some history over logs
 */
#define LOG_BUFFER_SIZE 64000

static char virLogBuffer[LOG_BUFFER_SIZE + 1];
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;
    int priority;
};
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 {
111
    bool logVersion;
D
Daniel Veillard 已提交
112 113 114 115
    void *data;
    virLogOutputFunc f;
    virLogCloseFunc c;
    int priority;
116 117
    virLogDestination dest;
    const char *name;
D
Daniel Veillard 已提交
118 119 120 121 122 123 124 125 126 127
};
typedef struct _virLogOutput virLogOutput;
typedef virLogOutput *virLogOutputPtr;

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

/*
 * Default priorities
 */
128
static virLogPriority virLogDefaultPriority = VIR_LOG_DEFAULT;
D
Daniel Veillard 已提交
129 130 131

static int virLogResetFilters(void);
static int virLogResetOutputs(void);
132 133 134
static int virLogOutputToFd(const char *category, int priority,
                            const char *funcname, long long linenr,
                            const char *str, int len, void *data);
D
Daniel Veillard 已提交
135 136 137 138

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

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

150 151
static const char *virLogOutputString(virLogDestination ldest) {
    switch (ldest) {
152 153 154 155 156 157
    case VIR_LOG_TO_STDERR:
        return "stderr";
    case VIR_LOG_TO_SYSLOG:
        return "syslog";
    case VIR_LOG_TO_FILE:
        return "file";
158
    }
159
    return "unknown";
160
}
D
Daniel Veillard 已提交
161 162 163

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

static int virLogInitialized = 0;

/**
 * virLogStartup:
 *
 * Initialize the logging module
 *
 * Returns 0 if successful, and -1 in case or error
 */
int virLogStartup(void) {
    if (virLogInitialized)
187
        return -1;
188 189 190 191

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

D
Daniel Veillard 已提交
192 193 194 195 196
    virLogInitialized = 1;
    virLogLock();
    virLogLen = 0;
    virLogStart = 0;
    virLogEnd = 0;
197
    virLogDefaultPriority = VIR_LOG_DEFAULT;
D
Daniel Veillard 已提交
198
    virLogUnlock();
199
    return 0;
D
Daniel Veillard 已提交
200 201 202 203 204 205 206 207 208 209 210
}

/**
 * virLogReset:
 *
 * Reset the logging module to its default initial state
 *
 * Returns 0 if successful, and -1 in case or error
 */
int virLogReset(void) {
    if (!virLogInitialized)
211
        return virLogStartup();
D
Daniel Veillard 已提交
212 213 214 215 216 217 218

    virLogLock();
    virLogResetFilters();
    virLogResetOutputs();
    virLogLen = 0;
    virLogStart = 0;
    virLogEnd = 0;
219
    virLogDefaultPriority = VIR_LOG_DEFAULT;
D
Daniel Veillard 已提交
220
    virLogUnlock();
221
    return 0;
D
Daniel Veillard 已提交
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
}
/**
 * virLogShutdown:
 *
 * Shutdown the logging module
 */
void virLogShutdown(void) {
    if (!virLogInitialized)
        return;
    virLogLock();
    virLogResetFilters();
    virLogResetOutputs();
    virLogLen = 0;
    virLogStart = 0;
    virLogEnd = 0;
    virLogUnlock();
238
    virMutexDestroy(&virLogMutex);
D
Daniel Veillard 已提交
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
    virLogInitialized = 0;
}

/*
 * Store a string in the ring buffer
 */
static void virLogStr(const char *str, int len) {
    int tmp;

    if (str == NULL)
        return;
    if (len <= 0)
        len = strlen(str);
    if (len > LOG_BUFFER_SIZE)
        return;
    virLogLock();

    /*
     * copy the data and reset the end, we cycle over the end of the buffer
     */
    if (virLogEnd + len >= LOG_BUFFER_SIZE) {
        tmp = LOG_BUFFER_SIZE - virLogEnd;
        memcpy(&virLogBuffer[virLogEnd], str, tmp);
        virLogBuffer[LOG_BUFFER_SIZE] = 0;
263
        memcpy(&virLogBuffer[0], &str[tmp], len - tmp);
D
Daniel Veillard 已提交
264 265 266 267 268 269 270 271 272 273 274 275 276
        virLogEnd = len - tmp;
    } else {
        memcpy(&virLogBuffer[virLogEnd], str, len);
        virLogEnd += len;
    }
    /*
     * Update the log length, and if full move the start index
     */
    virLogLen += len;
    if (virLogLen > LOG_BUFFER_SIZE) {
        tmp = virLogLen - LOG_BUFFER_SIZE;
        virLogLen = LOG_BUFFER_SIZE;
        virLogStart += tmp;
277 278
        if (virLogStart >= LOG_BUFFER_SIZE)
            virLogStart -= LOG_BUFFER_SIZE;
D
Daniel Veillard 已提交
279 280 281 282
    }
    virLogUnlock();
}

283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
static void virLogDumpAllFD(const char *msg, int len) {
    int i, found = 0;

    for (i = 0; i < virLogNbOutputs;i++) {
        if (virLogOutputs[i].f == virLogOutputToFd) {
            int fd = (long) virLogOutputs[i].data;

            if (fd >= 0) {
                ignore_value (safewrite(fd, msg, len));
                found = 1;
            }
        }
    }
    if (!found)
        ignore_value (safewrite(STDERR_FILENO, msg, len));
}

/**
 * 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 已提交
308
 */
309 310 311 312 313 314 315
void
virLogEmergencyDumpAll(int signum) {
    int ret = 0, len;
    char buf[100];

    if (virLogLen == 0)
        return;
D
Daniel Veillard 已提交
316 317

    virLogLock();
318 319 320 321 322 323 324 325 326 327 328 329 330
    snprintf(buf, sizeof(buf) - 1,
             "Caught signal %d, dumping internal log buffer:\n", signum);
    buf[sizeof(buf) - 1] = 0;
    virLogDumpAllFD(buf, strlen(buf));
    snprintf(buf, sizeof(buf) - 1, "\n\n    ====== start of log =====\n\n");
    virLogDumpAllFD(buf, strlen(buf));
    while (virLogLen > 0) {
        if (virLogStart + virLogLen < LOG_BUFFER_SIZE) {
            virLogBuffer[virLogStart + virLogLen] = 0;
            virLogDumpAllFD(&virLogBuffer[virLogStart], virLogLen);
            ret += virLogLen;
            virLogStart += virLogLen;
            virLogLen = 0;
D
Daniel Veillard 已提交
331
        } else {
332 333 334 335
            len = LOG_BUFFER_SIZE - virLogStart;
            virLogBuffer[LOG_BUFFER_SIZE] = 0;
            virLogDumpAllFD(&virLogBuffer[virLogStart], len);
            virLogLen -= len;
D
Daniel Veillard 已提交
336 337 338
            virLogStart = 0;
        }
    }
339 340
    snprintf(buf, sizeof(buf) - 1, "\n\n     ====== end of log =====\n\n");
    virLogDumpAllFD(buf, strlen(buf));
D
Daniel Veillard 已提交
341 342
    virLogUnlock();
}
343

D
Daniel Veillard 已提交
344 345 346 347 348 349 350 351 352 353 354
/**
 * 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.
 */
int virLogSetDefaultPriority(int priority) {
355
    if ((priority < VIR_LOG_DEBUG) || (priority > VIR_LOG_ERROR)) {
356
        VIR_WARN0("Ignoring invalid log level setting.");
357
        return -1;
358
    }
D
Daniel Veillard 已提交
359 360 361
    if (!virLogInitialized)
        virLogStartup();
    virLogDefaultPriority = priority;
362
    return 0;
D
Daniel Veillard 已提交
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
}

/**
 * virLogResetFilters:
 *
 * Removes the set of logging filters defined.
 *
 * Returns the number of filters removed
 */
static int virLogResetFilters(void) {
    int i;

    for (i = 0; i < virLogNbFilters;i++)
        VIR_FREE(virLogFilters[i].match);
    VIR_FREE(virLogFilters);
    virLogNbFilters = 0;
379
    return i;
D
Daniel Veillard 已提交
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
}

/**
 * virLogDefineFilter:
 * @match: the pattern to match
 * @priority: the priority to give to messages matching the pattern
 * @flags: extra flag, currently unused
 *
 * 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
 */
int virLogDefineFilter(const char *match, int priority,
                       int flags ATTRIBUTE_UNUSED) {
    int i;
    char *mdup = NULL;

    if ((match == NULL) || (priority < VIR_LOG_DEBUG) ||
        (priority > VIR_LOG_ERROR))
402
        return -1;
D
Daniel Veillard 已提交
403 404 405 406 407 408 409 410 411 412

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

    mdup = strdup(match);
413
    if (mdup == NULL) {
D
Daniel Veillard 已提交
414 415 416 417 418 419 420 421 422 423 424 425 426 427
        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;
    virLogNbFilters++;
cleanup:
    virLogUnlock();
428
    return i;
D
Daniel Veillard 已提交
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
}

/**
 * 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.
 */
static int virLogFiltersCheck(const char *input) {
    int ret = 0;
    int i;

    virLogLock();
    for (i = 0;i < virLogNbFilters;i++) {
        if (strstr(input, virLogFilters[i].match)) {
            ret = virLogFilters[i].priority;
            break;
        }
    }
    virLogUnlock();
453
    return ret;
D
Daniel Veillard 已提交
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
}

/**
 * virLogResetOutputs:
 *
 * Removes the set of logging output defined.
 *
 * Returns the number of output removed
 */
static int virLogResetOutputs(void) {
    int i;

    for (i = 0;i < virLogNbOutputs;i++) {
        if (virLogOutputs[i].c != NULL)
            virLogOutputs[i].c(virLogOutputs[i].data);
469
        VIR_FREE(virLogOutputs[i].name);
D
Daniel Veillard 已提交
470 471 472 473
    }
    VIR_FREE(virLogOutputs);
    i = virLogNbOutputs;
    virLogNbOutputs = 0;
474
    return i;
D
Daniel Veillard 已提交
475 476 477 478 479
}

/**
 * virLogDefineOutput:
 * @f: the function to call to output a message
480
 * @c: the function to call to close the output (or NULL)
D
Daniel Veillard 已提交
481 482
 * @data: extra data passed as first arg to the function
 * @priority: minimal priority for this filter, use 0 for none
483 484
 * @dest: where to send output of this priority
 * @name: optional name data associated with an output
D
Daniel Veillard 已提交
485 486 487 488 489 490 491 492
 * @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
 */
int virLogDefineOutput(virLogOutputFunc f, virLogCloseFunc c, void *data,
493 494
                       int priority, int dest, const char *name,
                       int flags ATTRIBUTE_UNUSED) {
D
Daniel Veillard 已提交
495
    int ret = -1;
496
    char *ndup = NULL;
D
Daniel Veillard 已提交
497 498

    if (f == NULL)
499
        return -1;
D
Daniel Veillard 已提交
500

501 502
    if (dest == VIR_LOG_TO_SYSLOG || dest == VIR_LOG_TO_FILE) {
        if (name == NULL)
503
            return -1;
504 505
        ndup = strdup(name);
        if (ndup == NULL)
506
            return -1;
507 508
    }

D
Daniel Veillard 已提交
509 510
    virLogLock();
    if (VIR_REALLOC_N(virLogOutputs, virLogNbOutputs + 1)) {
511
        VIR_FREE(ndup);
D
Daniel Veillard 已提交
512 513 514
        goto cleanup;
    }
    ret = virLogNbOutputs++;
515
    virLogOutputs[ret].logVersion = true;
D
Daniel Veillard 已提交
516 517 518 519
    virLogOutputs[ret].f = f;
    virLogOutputs[ret].c = c;
    virLogOutputs[ret].data = data;
    virLogOutputs[ret].priority = priority;
520 521
    virLogOutputs[ret].dest = dest;
    virLogOutputs[ret].name = ndup;
D
Daniel Veillard 已提交
522 523
cleanup:
    virLogUnlock();
524
    return ret;
D
Daniel Veillard 已提交
525 526
}

527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
static int
virLogFormatString(char **msg,
                   const char *funcname,
                   long long linenr,
                   struct tm *time_info,
                   struct timeval *cur_time,
                   int priority,
                   const char *str)
{
    int ret;
    if ((funcname != NULL)) {
        ret = virAsprintf(msg, "%02d:%02d:%02d.%03d: %d: %s : %s:%lld : %s\n",
                          time_info->tm_hour, time_info->tm_min,
                          time_info->tm_sec, (int) cur_time->tv_usec / 1000,
                          virThreadSelfID(),
                          virLogPriorityString(priority), funcname, linenr, str);
    } else {
        ret = virAsprintf(msg, "%02d:%02d:%02d.%03d: %d: %s : %s\n",
                          time_info->tm_hour, time_info->tm_min,
                          time_info->tm_sec, (int) cur_time->tv_usec / 1000,
                          virThreadSelfID(),
                          virLogPriorityString(priority), str);
    }
    return ret;
}

static int
virLogVersionString(char **msg,
                    struct tm *time_info,
                    struct timeval *cur_time)
{
#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

    return virLogFormatString(msg, NULL, 0,
                              time_info, cur_time,
                              VIR_LOG_INFO, LOG_VERSION_STRING);
}

D
Daniel Veillard 已提交
576 577 578 579
/**
 * virLogMessage:
 * @category: where is that message coming from
 * @priority: the priority level
580 581
 * @funcname: the function emitting the (debug) message
 * @linenr: line where the message was emitted
D
Daniel Veillard 已提交
582 583 584 585 586 587 588
 * @flags: extra flags, 1 if coming from the error handler
 * @fmt: the string format
 * @...: the arguments
 *
 * Call the libvirt logger with some informations. Based on the configuration
 * the message may be stored, sent to output or just discarded
 */
589 590
void virLogMessage(const char *category, int priority, const char *funcname,
                   long long linenr, int flags, const char *fmt, ...) {
591
    static bool logVersionStderr = true;
D
Daniel Veillard 已提交
592
    char *str = NULL;
593
    char *msg = NULL;
D
Daniel Veillard 已提交
594 595
    struct timeval cur_time;
    struct tm time_info;
596
    int len, fprio, i, ret;
597
    int saved_errno = errno;
598
    int emit = 1;
D
Daniel Veillard 已提交
599 600 601 602 603

    if (!virLogInitialized)
        virLogStartup();

    if (fmt == NULL)
604
        goto cleanup;
D
Daniel Veillard 已提交
605 606 607 608 609 610 611

    /*
     * check against list of specific logging patterns
     */
    fprio = virLogFiltersCheck(category);
    if (fprio == 0) {
        if (priority < virLogDefaultPriority)
612
            emit = 0;
613
    } else if (priority < fprio) {
614
        emit = 0;
615
    }
D
Daniel Veillard 已提交
616 617 618 619 620 621

    /*
     * serialize the error message, add level and timestamp
     */
    VIR_GET_VAR_STR(fmt, str);
    if (str == NULL)
622
        goto cleanup;
D
Daniel Veillard 已提交
623 624 625
    gettimeofday(&cur_time, NULL);
    localtime_r(&cur_time.tv_sec, &time_info);

626 627 628
    ret = virLogFormatString(&msg, funcname, linenr,
                             &time_info, &cur_time,
                             priority, str);
629
    VIR_FREE(str);
630 631
    if (ret < 0)
        goto cleanup;
D
Daniel Veillard 已提交
632 633

    /*
634 635
     * 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 已提交
636 637 638 639 640 641 642
     * 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.
     */
    len = strlen(msg);
    virLogStr(msg, len);
643 644 645
    if (emit == 0)
        goto cleanup;

D
Daniel Veillard 已提交
646 647
    virLogLock();
    for (i = 0; i < virLogNbOutputs;i++) {
648 649 650 651 652 653 654 655 656 657
        if (priority >= virLogOutputs[i].priority) {
            if (virLogOutputs[i].logVersion) {
                char *ver = NULL;
                if (virLogVersionString(&ver, &time_info, &cur_time) >= 0)
                    virLogOutputs[i].f(category, VIR_LOG_INFO, __func__, __LINE__,
                                       ver, strlen(ver),
                                       virLogOutputs[i].data);
                VIR_FREE(ver);
                virLogOutputs[i].logVersion = false;
            }
658 659
            virLogOutputs[i].f(category, priority, funcname, linenr,
                               msg, len, virLogOutputs[i].data);
660
        }
D
Daniel Veillard 已提交
661
    }
662 663 664 665 666 667 668 669 670
    if ((virLogNbOutputs == 0) && (flags != 1)) {
        if (logVersionStderr) {
            char *ver = NULL;
            if (virLogVersionString(&ver, &time_info, &cur_time) >= 0)
                ignore_value (safewrite(STDERR_FILENO,
                                        ver, strlen(ver)));
            VIR_FREE(ver);
            logVersionStderr = false;
        }
671
        ignore_value (safewrite(STDERR_FILENO, msg, len));
672
    }
D
Daniel Veillard 已提交
673 674
    virLogUnlock();

675
cleanup:
676
    VIR_FREE(msg);
677
    errno = saved_errno;
D
Daniel Veillard 已提交
678 679
}

680
static int virLogOutputToFd(const char *category ATTRIBUTE_UNUSED,
D
Daniel Veillard 已提交
681
                            int priority ATTRIBUTE_UNUSED,
682 683 684
                            const char *funcname ATTRIBUTE_UNUSED,
                            long long linenr ATTRIBUTE_UNUSED,
                            const char *str, int len, void *data) {
D
Daniel Veillard 已提交
685 686 687 688
    int fd = (long) data;
    int ret;

    if (fd < 0)
689
        return -1;
D
Daniel Veillard 已提交
690
    ret = safewrite(fd, str, len);
691
    return ret;
D
Daniel Veillard 已提交
692 693 694 695 696
}

static void virLogCloseFd(void *data) {
    int fd = (long) data;

697
    VIR_FORCE_CLOSE(fd);
D
Daniel Veillard 已提交
698 699 700
}

static int virLogAddOutputToStderr(int priority) {
701 702
    if (virLogDefineOutput(virLogOutputToFd, NULL, (void *)2L, priority,
                           VIR_LOG_TO_STDERR, NULL, 0) < 0)
703 704
        return -1;
    return 0;
D
Daniel Veillard 已提交
705 706 707 708 709
}

static int virLogAddOutputToFile(int priority, const char *file) {
    int fd;

710
    fd = open(file, O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR);
D
Daniel Veillard 已提交
711
    if (fd < 0)
712
        return -1;
D
Daniel Veillard 已提交
713
    if (virLogDefineOutput(virLogOutputToFd, virLogCloseFd, (void *)(long)fd,
714
                           priority, VIR_LOG_TO_FILE, file, 0) < 0) {
715
        VIR_FORCE_CLOSE(fd);
716
        return -1;
D
Daniel Veillard 已提交
717
    }
718
    return 0;
D
Daniel Veillard 已提交
719 720 721
}

#if HAVE_SYSLOG_H
722 723 724 725 726 727
static int virLogOutputToSyslog(const char *category ATTRIBUTE_UNUSED,
                                int priority,
                                const char *funcname ATTRIBUTE_UNUSED,
                                long long linenr ATTRIBUTE_UNUSED,
                                const char *str, int len ATTRIBUTE_UNUSED,
                                void *data ATTRIBUTE_UNUSED) {
D
Daniel Veillard 已提交
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
    int prio;

    switch (priority) {
        case VIR_LOG_DEBUG:
            prio = LOG_DEBUG;
            break;
        case VIR_LOG_INFO:
            prio = LOG_INFO;
            break;
        case VIR_LOG_WARN:
            prio = LOG_WARNING;
            break;
        case VIR_LOG_ERROR:
            prio = LOG_ERR;
            break;
        default:
            prio = LOG_ERR;
    }
    syslog(prio, "%s", str);
747
    return len;
D
Daniel Veillard 已提交
748 749
}

750 751
static char *current_ident = NULL;

D
Daniel Veillard 已提交
752 753
static void virLogCloseSyslog(void *data ATTRIBUTE_UNUSED) {
    closelog();
754
    VIR_FREE(current_ident);
D
Daniel Veillard 已提交
755 756 757
}

static int virLogAddOutputToSyslog(int priority, const char *ident) {
758 759 760 761 762 763
    /*
     * ident needs to be kept around on Solaris
     */
    VIR_FREE(current_ident);
    current_ident = strdup(ident);
    if (current_ident == NULL)
764
        return -1;
765 766

    openlog(current_ident, 0, 0);
D
Daniel Veillard 已提交
767
    if (virLogDefineOutput(virLogOutputToSyslog, virLogCloseSyslog, NULL,
768
                           priority, VIR_LOG_TO_SYSLOG, ident, 0) < 0) {
D
Daniel Veillard 已提交
769
        closelog();
770
        VIR_FREE(current_ident);
771
        return -1;
D
Daniel Veillard 已提交
772
    }
773
    return 0;
D
Daniel Veillard 已提交
774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
}
#endif /* HAVE_SYSLOG_H */

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

/**
 * 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
 */
int virLogParseOutputs(const char *outputs) {
    const char *cur = outputs, *str;
    char *name;
807
    char *abspath;
D
Daniel Veillard 已提交
808
    int prio;
809 810
    int ret = -1;
    int count = 0;
D
Daniel Veillard 已提交
811 812

    if (cur == NULL)
813
        return -1;
D
Daniel Veillard 已提交
814 815 816 817

    virSkipSpaces(&cur);
    while (*cur != 0) {
        prio= virParseNumber(&cur);
818
        if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
819
            goto cleanup;
D
Daniel Veillard 已提交
820
        if (*cur != ':')
821
            goto cleanup;
D
Daniel Veillard 已提交
822 823 824 825
        cur++;
        if (STREQLEN(cur, "stderr", 6)) {
            cur += 6;
            if (virLogAddOutputToStderr(prio) == 0)
826
                count++;
D
Daniel Veillard 已提交
827 828 829
        } else if (STREQLEN(cur, "syslog", 6)) {
            cur += 6;
            if (*cur != ':')
830
                goto cleanup;
D
Daniel Veillard 已提交
831 832 833 834 835
            cur++;
            str = cur;
            while ((*cur != 0) && (!IS_SPACE(cur)))
                cur++;
            if (str == cur)
836
                goto cleanup;
D
Daniel Veillard 已提交
837 838 839
#if HAVE_SYSLOG_H
            name = strndup(str, cur - str);
            if (name == NULL)
840
                goto cleanup;
D
Daniel Veillard 已提交
841
            if (virLogAddOutputToSyslog(prio, name) == 0)
842
                count++;
D
Daniel Veillard 已提交
843 844 845 846 847
            VIR_FREE(name);
#endif /* HAVE_SYSLOG_H */
        } else if (STREQLEN(cur, "file", 4)) {
            cur += 4;
            if (*cur != ':')
848
                goto cleanup;
D
Daniel Veillard 已提交
849 850 851 852 853
            cur++;
            str = cur;
            while ((*cur != 0) && (!IS_SPACE(cur)))
                cur++;
            if (str == cur)
854
                goto cleanup;
D
Daniel Veillard 已提交
855 856
            name = strndup(str, cur - str);
            if (name == NULL)
857
                goto cleanup;
858 859 860 861 862
            if (virFileAbsPath(name, &abspath) < 0) {
                VIR_FREE(name);
                return -1; /* skip warning here because setting was fine */
            }
            if (virLogAddOutputToFile(prio, abspath) == 0)
863
                count++;
D
Daniel Veillard 已提交
864
            VIR_FREE(name);
865
            VIR_FREE(abspath);
D
Daniel Veillard 已提交
866
        } else {
867
            goto cleanup;
D
Daniel Veillard 已提交
868 869 870
        }
        virSkipSpaces(&cur);
    }
871 872 873
    ret = count;
cleanup:
    if (ret == -1)
874
        VIR_WARN0("Ignoring invalid log output setting.");
875
    return ret;
D
Daniel Veillard 已提交
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
}

/**
 * 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
 */
int virLogParseFilters(const char *filters) {
    const char *cur = filters, *str;
    char *name;
    int prio;
900 901
    int ret = -1;
    int count = 0;
D
Daniel Veillard 已提交
902 903

    if (cur == NULL)
904
        return -1;
D
Daniel Veillard 已提交
905 906 907 908

    virSkipSpaces(&cur);
    while (*cur != 0) {
        prio= virParseNumber(&cur);
909
        if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
910
            goto cleanup;
D
Daniel Veillard 已提交
911
        if (*cur != ':')
912
            goto cleanup;
D
Daniel Veillard 已提交
913 914 915 916 917
        cur++;
        str = cur;
        while ((*cur != 0) && (!IS_SPACE(cur)))
            cur++;
        if (str == cur)
918
            goto cleanup;
D
Daniel Veillard 已提交
919 920
        name = strndup(str, cur - str);
        if (name == NULL)
921
            goto cleanup;
D
Daniel Veillard 已提交
922
        if (virLogDefineFilter(name, prio, 0) >= 0)
923
            count++;
D
Daniel Veillard 已提交
924 925 926
        VIR_FREE(name);
        virSkipSpaces(&cur);
    }
927 928 929
    ret = count;
cleanup:
    if (ret == -1)
930
        VIR_WARN0("Ignoring invalid log filter setting.");
931
    return ret;
D
Daniel Veillard 已提交
932
}
933 934 935 936 937 938 939

/**
 * virLogGetDefaultPriority:
 *
 * Returns the current logging priority level.
 */
int virLogGetDefaultPriority(void) {
940
    return virLogDefaultPriority;
941 942
}

943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960
/**
 * virLogGetFilters:
 *
 * Returns a string listing the current filters, in the format originally
 * specified in the config file or environment. Caller must free the
 * result.
 */
char *virLogGetFilters(void) {
    int i;
    virBuffer filterbuf = VIR_BUFFER_INITIALIZER;

    virLogLock();
    for (i = 0; i < virLogNbFilters; i++) {
        virBufferVSprintf(&filterbuf, "%d:%s ", virLogFilters[i].priority,
                          virLogFilters[i].match);
    }
    virLogUnlock();

961 962
    if (virBufferError(&filterbuf)) {
        virBufferFreeAndReset(&filterbuf);
963
        return NULL;
964
    }
965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000

    return virBufferContentAndReset(&filterbuf);
}

/**
 * virLogGetOutputs:
 *
 * Returns a string listing the current outputs, in the format originally
 * specified in the config file or environment. Caller must free the
 * result.
 */
char *virLogGetOutputs(void) {
    int i;
    virBuffer outputbuf = VIR_BUFFER_INITIALIZER;

    virLogLock();
    for (i = 0; i < virLogNbOutputs; i++) {
        int dest = virLogOutputs[i].dest;
        if (i)
            virBufferVSprintf(&outputbuf, " ");
        switch (dest) {
            case VIR_LOG_TO_SYSLOG:
            case VIR_LOG_TO_FILE:
                virBufferVSprintf(&outputbuf, "%d:%s:%s",
                                  virLogOutputs[i].priority,
                                  virLogOutputString(dest),
                                  virLogOutputs[i].name);
                break;
            default:
                virBufferVSprintf(&outputbuf, "%d:%s",
                                  virLogOutputs[i].priority,
                                  virLogOutputString(dest));
        }
    }
    virLogUnlock();

1001 1002
    if (virBufferError(&outputbuf)) {
        virBufferFreeAndReset(&outputbuf);
1003
        return NULL;
1004
    }
1005 1006 1007 1008

    return virBufferContentAndReset(&outputbuf);
}

1009 1010 1011 1012 1013 1014
/**
 * virLogGetNbFilters:
 *
 * Returns the current number of defined log filters.
 */
int virLogGetNbFilters(void) {
1015
    return virLogNbFilters;
1016 1017 1018 1019 1020 1021 1022 1023
}

/**
 * virLogGetNbOutputs:
 *
 * Returns the current number of defined log outputs.
 */
int virLogGetNbOutputs(void) {
1024
    return virLogNbOutputs;
1025
}
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051

/**
 * 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.
 */
int virLogParseDefaultPriority(const char *priority) {
    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
1052
        VIR_WARN0("Ignoring invalid log level setting");
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070

    return ret;
}

/**
 * virLogSetFromEnv:
 *
 * Sets virLogDefaultPriority, virLogFilters and virLogOutputs based on
 * environment variables.
 */
void virLogSetFromEnv(void) {
    char *debugEnv;

    debugEnv = getenv("LIBVIRT_DEBUG");
    if (debugEnv && *debugEnv)
        virLogParseDefaultPriority(debugEnv);
    debugEnv = getenv("LIBVIRT_LOG_FILTERS");
    if (debugEnv && *debugEnv)
1071
        virLogParseFilters(debugEnv);
1072 1073
    debugEnv = getenv("LIBVIRT_LOG_OUTPUTS");
    if (debugEnv && *debugEnv)
1074
        virLogParseOutputs(debugEnv);
1075
}