Blame libglusterfs/src/logging.c

Packit Service e080da
/*
Packit Service e080da
  Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
Packit Service e080da
  This file is part of GlusterFS.
Packit Service e080da
Packit Service e080da
  This file is licensed to you under your choice of the GNU Lesser
Packit Service e080da
  General Public License, version 3 or any later version (LGPLv3 or
Packit Service e080da
  later), or the GNU General Public License, version 2 (GPLv2), in all
Packit Service e080da
  cases as published by the Free Software Foundation.
Packit Service e080da
*/
Packit Service e080da
Packit Service e080da
#include <errno.h>
Packit Service e080da
#include <pthread.h>
Packit Service e080da
#include <stdio.h>
Packit Service e080da
#include <stdarg.h>
Packit Service e080da
#include <time.h>
Packit Service e080da
#include <locale.h>
Packit Service e080da
#include <string.h>
Packit Service e080da
#include <stdlib.h>
Packit Service e080da
#include <syslog.h>
Packit Service 173fb3
#include <sys/resource.h>
Packit Service e080da
Packit Service e080da
#ifdef HAVE_BACKTRACE
Packit Service e080da
#include <execinfo.h>
Packit Service e080da
#else
Packit Service e080da
#include "execinfo_compat.h"
Packit Service e080da
#endif
Packit Service e080da
Packit Service e080da
#include <sys/stat.h>
Packit Service e080da
Packit Service e080da
#include "glusterfs/syscall.h"
Packit Service e080da
Packit Service e080da
#define GF_JSON_MSG_LENGTH 8192
Packit Service e080da
#define GF_SYSLOG_CEE_FORMAT                                                   \
Packit Service e080da
    "@cee: {\"msg\": \"%s\", \"gf_code\": \"%u\", \"gf_message\": \"%s\"}"
Packit Service e080da
#define GF_LOG_CONTROL_FILE "/etc/glusterfs/logger.conf"
Packit Service e080da
#define GF_LOG_BACKTRACE_DEPTH 5
Packit Service e080da
#define GF_LOG_BACKTRACE_SIZE 4096
Packit Service e080da
#define GF_LOG_TIMESTR_SIZE 256
Packit Service e080da
#define GF_MAX_SLOG_PAIR_COUNT 100
Packit Service e080da
Packit Service e080da
#include "glusterfs/xlator.h"
Packit Service e080da
#include "glusterfs/logging.h"
Packit Service e080da
#include "glusterfs/defaults.h"
Packit Service e080da
#include "glusterfs/glusterfs.h"
Packit Service e080da
#include "glusterfs/timer.h"
Packit Service e080da
#include "glusterfs/libglusterfs-messages.h"
Packit Service e080da
Packit Service e080da
/* Do not replace gf_log in TEST_LOG with gf_msg, as there is a slight chance
Packit Service e080da
 * that it could lead to an infinite recursion.*/
Packit Service e080da
#define TEST_LOG(__msg, __args...)                                             \
Packit Service e080da
    gf_log("logging-infra", GF_LOG_DEBUG, __msg, ##__args);
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_flush_timeout_cbk(void *data);
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
gf_log_inject_timer_event(glusterfs_ctx_t *ctx);
Packit Service e080da
Packit Service e080da
static void
Packit Service e080da
gf_log_flush_extra_msgs(glusterfs_ctx_t *ctx, uint32_t new);
Packit Service e080da
Packit Service e080da
static char *gf_level_strings[] = {"",  /* NONE */
Packit Service e080da
                                   "M", /* EMERGENCY */
Packit Service e080da
                                   "A", /* ALERT */
Packit Service e080da
                                   "C", /* CRITICAL */
Packit Service e080da
                                   "E", /* ERROR */
Packit Service e080da
                                   "W", /* WARNING */
Packit Service e080da
                                   "N", /* NOTICE */
Packit Service e080da
                                   "I", /* INFO */
Packit Service e080da
                                   "D", /* DEBUG */
Packit Service e080da
                                   "T", /* TRACE */
Packit Service e080da
                                   ""};
Packit Service e080da
Packit Service e080da
/* Ideally this should get moved to logging.h */
Packit Service e080da
struct _msg_queue {
Packit Service e080da
    struct list_head msgs;
Packit Service e080da
};
Packit Service e080da
Packit Service e080da
struct _log_msg {
Packit Service e080da
    const char *msg;
Packit Service e080da
    struct list_head queue;
Packit Service e080da
};
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_logrotate(int signum)
Packit Service e080da
{
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    ctx = THIS->ctx;
Packit Service e080da
Packit Service e080da
    if (ctx) {
Packit Service e080da
        ctx->log.logrotate = 1;
Packit Service e080da
        ctx->log.cmd_history_logrotate = 1;
Packit Service e080da
    }
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_enable_syslog(void)
Packit Service e080da
{
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    ctx = THIS->ctx;
Packit Service e080da
Packit Service e080da
    if (ctx)
Packit Service e080da
        ctx->log.gf_log_syslog = 1;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_disable_syslog(void)
Packit Service e080da
{
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    ctx = THIS->ctx;
Packit Service e080da
Packit Service e080da
    if (ctx)
Packit Service e080da
        ctx->log.gf_log_syslog = 0;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
gf_loglevel_t
Packit Service e080da
gf_log_get_loglevel(void)
Packit Service e080da
{
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    ctx = THIS->ctx;
Packit Service e080da
Packit Service e080da
    if (ctx)
Packit Service e080da
        return ctx->log.loglevel;
Packit Service e080da
    else
Packit Service e080da
        /* return global defaults (see gf_log_globals_init) */
Packit Service e080da
        return GF_LOG_INFO;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_set_loglevel(glusterfs_ctx_t *ctx, gf_loglevel_t level)
Packit Service e080da
{
Packit Service e080da
    if (ctx)
Packit Service e080da
        ctx->log.loglevel = level;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
gf_log_get_localtime(void)
Packit Service e080da
{
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    ctx = THIS->ctx;
Packit Service e080da
Packit Service e080da
    if (ctx)
Packit Service e080da
        return ctx->log.localtime;
Packit Service e080da
    else
Packit Service e080da
        /* return global defaults (see gf_log_globals_init) */
Packit Service e080da
        return 0;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_set_localtime(int on_off)
Packit Service e080da
{
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    ctx = THIS->ctx;
Packit Service e080da
Packit Service e080da
    if (ctx)
Packit Service e080da
        ctx->log.localtime = on_off;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_flush(void)
Packit Service e080da
{
Packit Service e080da
    xlator_t *this = NULL;
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    this = THIS;
Packit Service e080da
    ctx = this->ctx;
Packit Service e080da
Packit Service e080da
    if (ctx && ctx->log.logger == gf_logger_glusterlog) {
Packit Service e080da
        pthread_mutex_lock(&ctx->log.logfile_mutex);
Packit Service e080da
        fflush(ctx->log.gf_log_logfile);
Packit Service e080da
        pthread_mutex_unlock(&ctx->log.logfile_mutex);
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    return;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_set_xl_loglevel(void *this, gf_loglevel_t level)
Packit Service e080da
{
Packit Service e080da
    xlator_t *xl = this;
Packit Service e080da
    if (!xl)
Packit Service e080da
        return;
Packit Service e080da
    xl->loglevel = level;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
/* TODO: The following get/set functions are yet not invoked from anywhere
Packit Service e080da
 * in the code. The _intention_ is to pass CLI arguments to various daemons
Packit Service e080da
 * that are started, which would then invoke these set APIs as required.
Packit Service e080da
 *
Packit Service e080da
 * glusterd would read the defaults from its .vol file configuration shipped
Packit Service e080da
 * as a part of the packages distributed.
Packit Service e080da
 *
Packit Service e080da
 * For any gluster* daemon that is started the shipped configuration becomes the
Packit Service e080da
 * default, if a volume has to change its logging format or logger, then a
Packit Service e080da
 * gluster CLI is invoked to set this property for the volume in question.
Packit Service e080da
 *
Packit Service e080da
 * The property is maintained by glusterd, and passed to the daemon as a CLI
Packit Service e080da
 * option, IOW persistence of the option is maintained by glusterd persistent
Packit Service e080da
 * storage (i.e .vol file) only
Packit Service e080da
 *
Packit Service e080da
 * care needs to be taken to configure and start daemons based on the versions
Packit Service e080da
 * that supports these features */
Packit Service e080da
gf_log_format_t
Packit Service e080da
gf_log_get_logformat(void)
Packit Service e080da
{
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    ctx = THIS->ctx;
Packit Service e080da
Packit Service e080da
    if (ctx)
Packit Service e080da
        return ctx->log.logformat;
Packit Service e080da
    else
Packit Service e080da
        /* return global defaluts (see gf_log_globals_init) */
Packit Service e080da
        return gf_logformat_withmsgid;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_set_logformat(gf_log_format_t format)
Packit Service e080da
{
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    ctx = THIS->ctx;
Packit Service e080da
Packit Service e080da
    if (ctx)
Packit Service e080da
        ctx->log.logformat = format;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
gf_log_logger_t
Packit Service e080da
gf_log_get_logger(void)
Packit Service e080da
{
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    ctx = THIS->ctx;
Packit Service e080da
Packit Service e080da
    if (ctx)
Packit Service e080da
        return ctx->log.logger;
Packit Service e080da
    else
Packit Service e080da
        /* return global defaluts (see gf_log_globals_init) */
Packit Service e080da
        return gf_logger_glusterlog;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_set_logger(gf_log_logger_t logger)
Packit Service e080da
{
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    ctx = THIS->ctx;
Packit Service e080da
Packit Service e080da
    if (ctx)
Packit Service e080da
        ctx->log.logger = logger;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
gf_loglevel_t
Packit Service e080da
gf_log_get_xl_loglevel(void *this)
Packit Service e080da
{
Packit Service e080da
    xlator_t *xl = this;
Packit Service e080da
    if (!xl)
Packit Service e080da
        return 0;
Packit Service e080da
    return xl->loglevel;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_set_log_buf_size(uint32_t buf_size)
Packit Service e080da
{
Packit Service e080da
    uint32_t old = 0;
Packit Service e080da
    glusterfs_ctx_t *ctx = THIS->ctx;
Packit Service e080da
Packit Service e080da
    pthread_mutex_lock(&ctx->log.log_buf_lock);
Packit Service e080da
    {
Packit Service e080da
        old = ctx->log.lru_size;
Packit Service e080da
        ctx->log.lru_size = buf_size;
Packit Service e080da
    }
Packit Service e080da
    pthread_mutex_unlock(&ctx->log.log_buf_lock);
Packit Service e080da
Packit Service e080da
    /* If the old size is less than/equal to the new size, then do nothing.
Packit Service e080da
     *
Packit Service e080da
     * But if the new size is less than the old size, then
Packit Service e080da
     *   a. If the cur size of the buf is less than or equal the new size,
Packit Service e080da
     *      then do nothing.
Packit Service e080da
     *   b. But if the current size of the buf is greater than the new size,
Packit Service e080da
     *      then flush the least recently used (cur size - new_size) msgs
Packit Service e080da
     *      to disk.
Packit Service e080da
     */
Packit Service e080da
    if (buf_size < old)
Packit Service e080da
        gf_log_flush_extra_msgs(ctx, buf_size);
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_set_log_flush_timeout(uint32_t timeout)
Packit Service e080da
{
Packit Service e080da
    THIS->ctx->log.timeout = timeout;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
log_buf_t *
Packit Service e080da
log_buf_new()
Packit Service e080da
{
Packit Service e080da
    log_buf_t *buf = NULL;
Packit Service e080da
Packit Service e080da
    buf = mem_get0(THIS->ctx->logbuf_pool);
Packit Service e080da
Packit Service e080da
    return buf;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
/* If log_buf_init() fails (indicated by a return value of -1),
Packit Service e080da
 * call log_buf_destroy() to clean up memory allocated in heap and to return
Packit Service e080da
 * the log_buf_t object back to its memory pool.
Packit Service e080da
 */
Packit Service e080da
int
Packit Service e080da
log_buf_init(log_buf_t *buf, const char *domain, const char *file,
Packit Service e080da
             const char *function, int32_t line, gf_loglevel_t level,
Packit Service e080da
             int errnum, uint64_t msgid, char **appmsgstr, int graph_id)
Packit Service e080da
{
Packit Service e080da
    int ret = -1;
Packit Service e080da
Packit Service e080da
    if (!buf || !domain || !file || !function || !appmsgstr || !*appmsgstr)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    buf->msg = gf_strdup(*appmsgstr);
Packit Service e080da
    if (!buf->msg)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    buf->msg_id = msgid;
Packit Service e080da
    buf->errnum = errnum;
Packit Service e080da
    buf->domain = gf_strdup(domain);
Packit Service e080da
    if (!buf->domain)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    buf->file = gf_strdup(file);
Packit Service e080da
    if (!buf->file)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    buf->function = gf_strdup(function);
Packit Service e080da
    if (!buf->function)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    buf->line = line;
Packit Service e080da
    buf->level = level;
Packit Service e080da
    buf->refcount = 0;
Packit Service e080da
    buf->graph_id = graph_id;
Packit Service e080da
    INIT_LIST_HEAD(&buf->msg_list);
Packit Service e080da
Packit Service e080da
    ret = 0;
Packit Service e080da
out:
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
log_buf_destroy(log_buf_t *buf)
Packit Service e080da
{
Packit Service e080da
    if (!buf)
Packit Service e080da
        return -1;
Packit Service e080da
Packit Service e080da
    GF_FREE(buf->msg);
Packit Service e080da
    GF_FREE(buf->domain);
Packit Service e080da
    GF_FREE(buf->file);
Packit Service e080da
    GF_FREE(buf->function);
Packit Service e080da
Packit Service e080da
    mem_put(buf);
Packit Service e080da
    return 0;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
static void
Packit Service e080da
gf_log_rotate(glusterfs_ctx_t *ctx)
Packit Service e080da
{
Packit Service e080da
    int fd = -1;
Packit Service e080da
    FILE *new_logfile = NULL;
Packit Service e080da
    FILE *old_logfile = NULL;
Packit Service e080da
Packit Service e080da
    /* not involving locks on initial check to speed it up */
Packit Service e080da
    if (ctx->log.logrotate) {
Packit Service e080da
        /* let only one winner through on races */
Packit Service e080da
        pthread_mutex_lock(&ctx->log.logfile_mutex);
Packit Service e080da
Packit Service e080da
        if (!ctx->log.logrotate) {
Packit Service e080da
            pthread_mutex_unlock(&ctx->log.logfile_mutex);
Packit Service e080da
            return;
Packit Service e080da
        } else {
Packit Service e080da
            ctx->log.logrotate = 0;
Packit Service e080da
            pthread_mutex_unlock(&ctx->log.logfile_mutex);
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        fd = sys_open(ctx->log.filename, O_CREAT | O_WRONLY | O_APPEND,
Packit Service e080da
                      S_IRUSR | S_IWUSR);
Packit Service e080da
        if (fd < 0) {
Packit Service e080da
            gf_msg("logrotate", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED,
Packit Service e080da
                   "failed to open "
Packit Service e080da
                   "logfile");
Packit Service e080da
            return;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        new_logfile = fdopen(fd, "a");
Packit Service e080da
        if (!new_logfile) {
Packit Service e080da
            gf_msg("logrotate", GF_LOG_CRITICAL, errno, LG_MSG_FILE_OP_FAILED,
Packit Service e080da
                   "failed to open logfile"
Packit Service e080da
                   " %s",
Packit Service e080da
                   ctx->log.filename);
Packit Service e080da
            sys_close(fd);
Packit Service e080da
            return;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        pthread_mutex_lock(&ctx->log.logfile_mutex);
Packit Service e080da
        {
Packit Service e080da
            if (ctx->log.logfile)
Packit Service e080da
                old_logfile = ctx->log.logfile;
Packit Service e080da
Packit Service e080da
            ctx->log.gf_log_logfile = ctx->log.logfile = new_logfile;
Packit Service e080da
        }
Packit Service e080da
        pthread_mutex_unlock(&ctx->log.logfile_mutex);
Packit Service e080da
Packit Service e080da
        if (old_logfile != NULL)
Packit Service e080da
            fclose(old_logfile);
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    return;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_globals_fini(void)
Packit Service e080da
{
Packit Service e080da
    /* TODO: Nobody is invoking the fini, but cleanup needs to happen here,
Packit Service e080da
     * needs cleanup for, log.ident, log.filename, closelog, log file close
Packit Service e080da
     * rotate state, possibly under a lock */
Packit Service e080da
    pthread_mutex_destroy(&THIS->ctx->log.logfile_mutex);
Packit Service e080da
    pthread_mutex_destroy(&THIS->ctx->log.log_buf_lock);
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_disable_suppression_before_exit(glusterfs_ctx_t *ctx)
Packit Service e080da
{
Packit Service e080da
    /*
Packit Service e080da
     * First set log buf size to 0. This would ensure two things:
Packit Service e080da
     * i. that all outstanding log messages are flushed to disk, and
Packit Service e080da
     * ii. all subsequent calls to gf_msg will result in the logs getting
Packit Service e080da
     *     directly flushed to disk without being buffered.
Packit Service e080da
     *
Packit Service e080da
     * Then, cancel the current log timer event.
Packit Service e080da
     */
Packit Service e080da
Packit Service e080da
    gf_log_set_log_buf_size(0);
Packit Service e080da
    pthread_mutex_lock(&ctx->log.log_buf_lock);
Packit Service e080da
    {
Packit Service e080da
        if (ctx->log.log_flush_timer) {
Packit Service e080da
            gf_timer_call_cancel(ctx, ctx->log.log_flush_timer);
Packit Service e080da
            ctx->log.log_flush_timer = NULL;
Packit Service e080da
        }
Packit Service e080da
    }
Packit Service e080da
    pthread_mutex_unlock(&ctx->log.log_buf_lock);
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
/** gf_log_fini - function to perform the cleanup of the log information
Packit Service e080da
 * @data - glusterfs context
Packit Service e080da
 * @return: success: 0
Packit Service e080da
 *          failure: -1
Packit Service e080da
 */
Packit Service e080da
int
Packit Service e080da
gf_log_fini(void *data)
Packit Service e080da
{
Packit Service e080da
    glusterfs_ctx_t *ctx = data;
Packit Service e080da
    int ret = 0;
Packit Service e080da
    FILE *old_logfile = NULL;
Packit Service e080da
Packit Service e080da
    if (ctx == NULL) {
Packit Service e080da
        ret = -1;
Packit Service e080da
        goto out;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    gf_log_disable_suppression_before_exit(ctx);
Packit Service e080da
Packit Service e080da
    pthread_mutex_lock(&ctx->log.logfile_mutex);
Packit Service e080da
    {
Packit Service e080da
        if (ctx->log.logfile) {
Packit Service e080da
            old_logfile = ctx->log.logfile;
Packit Service e080da
Packit Service e080da
            /* Logfile needs to be set to NULL, so that any
Packit Service e080da
               call to gf_log after calling gf_log_fini, will
Packit Service e080da
               log the message to stderr.
Packit Service e080da
            */
Packit Service e080da
            ctx->log.loglevel = GF_LOG_NONE;
Packit Service e080da
            ctx->log.logfile = NULL;
Packit Service e080da
        }
Packit Service e080da
    }
Packit Service e080da
    pthread_mutex_unlock(&ctx->log.logfile_mutex);
Packit Service e080da
Packit Service e080da
    if (old_logfile && (fclose(old_logfile) != 0))
Packit Service e080da
        ret = -1;
Packit Service e080da
Packit Service e080da
    GF_FREE(ctx->log.ident);
Packit Service e080da
    GF_FREE(ctx->log.filename);
Packit Service e080da
Packit Service e080da
out:
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
/**
Packit Service e080da
 * gf_openlog -function to open syslog specific to gluster based on
Packit Service e080da
 *             existence of file /etc/glusterfs/logger.conf
Packit Service e080da
 * @ident:    optional identification string similar to openlog()
Packit Service e080da
 * @option:   optional value to option to openlog().  Passing -1 uses
Packit Service e080da
 *            'LOG_PID | LOG_NDELAY' as default
Packit Service e080da
 * @facility: optional facility code similar to openlog().  Passing -1
Packit Service e080da
 *            uses LOG_DAEMON as default
Packit Service e080da
 *
Packit Service e080da
 * @return: void
Packit Service e080da
 */
Packit Service e080da
void
Packit Service e080da
gf_openlog(const char *ident, int option, int facility)
Packit Service e080da
{
Packit Service e080da
    int _option = option;
Packit Service e080da
    int _facility = facility;
Packit Service e080da
Packit Service e080da
    if (-1 == _option) {
Packit Service e080da
        _option = LOG_PID | LOG_NDELAY;
Packit Service e080da
    }
Packit Service e080da
    if (-1 == _facility) {
Packit Service e080da
        _facility = LOG_LOCAL1;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    /* TODO: Should check for errors here and return appropriately */
Packit Service e080da
    setlocale(LC_ALL, "");
Packit Service e080da
    setlocale(LC_NUMERIC, "C"); /* C-locale for strtod, ... */
Packit Service e080da
    /* close the previous syslog if open as we are changing settings */
Packit Service e080da
    closelog();
Packit Service e080da
    openlog(ident, _option, _facility);
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
/**
Packit Service e080da
 * _json_escape -function to convert string to json encoded string
Packit Service e080da
 * @str: input string
Packit Service e080da
 * @buf: buffer to store encoded string
Packit Service e080da
 * @len: length of @buf
Packit Service e080da
 *
Packit Service e080da
 * @return: success: last unprocessed character position by pointer in @str
Packit Service e080da
 *          failure: NULL
Packit Service e080da
 *
Packit Service e080da
 * Internal function. Heavily inspired by _ul_str_escape() function in
Packit Service e080da
 * libumberlog
Packit Service e080da
 *
Packit Service e080da
 * Sample output:
Packit Service e080da
 * [1] str = "devel error"
Packit Service e080da
 *     buf = "devel error"
Packit Service e080da
 * [2] str = "devel	error"
Packit Service e080da
 *     buf = "devel\terror"
Packit Service e080da
 * [3] str = "I/O error on "/tmp/foo" file"
Packit Service e080da
 *     buf = "I/O error on \"/tmp/foo\" file"
Packit Service e080da
 * [4] str = "I/O error?on /tmp/bar file"
Packit Service e080da
 *     buf = "I/O error\u001bon /tmp/bar file"
Packit Service e080da
 *
Packit Service e080da
 */
Packit Service e080da
char *
Packit Service e080da
_json_escape(const char *str, char *buf, size_t len)
Packit Service e080da
{
Packit Service e080da
    static const unsigned char json_exceptions[UCHAR_MAX + 1] = {
Packit Service e080da
        [0x01] = 1, [0x02] = 1, [0x03] = 1, [0x04] = 1, [0x05] = 1, [0x06] = 1,
Packit Service e080da
        [0x07] = 1, [0x08] = 1, [0x09] = 1, [0x0a] = 1, [0x0b] = 1, [0x0c] = 1,
Packit Service e080da
        [0x0d] = 1, [0x0e] = 1, [0x0f] = 1, [0x10] = 1, [0x11] = 1, [0x12] = 1,
Packit Service e080da
        [0x13] = 1, [0x14] = 1, [0x15] = 1, [0x16] = 1, [0x17] = 1, [0x18] = 1,
Packit Service e080da
        [0x19] = 1, [0x1a] = 1, [0x1b] = 1, [0x1c] = 1, [0x1d] = 1, [0x1e] = 1,
Packit Service e080da
        [0x1f] = 1, ['\\'] = 1, ['"'] = 1};
Packit Service e080da
    static const char json_hex_chars[16] = "0123456789abcdef";
Packit Service e080da
    unsigned char *p = NULL;
Packit Service e080da
    size_t pos = 0;
Packit Service e080da
Packit Service e080da
    if (!str || !buf || len <= 0) {
Packit Service e080da
        return NULL;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    for (p = (unsigned char *)str; *p && (pos + 1) < len; p++) {
Packit Service e080da
        if (json_exceptions[*p] == 0) {
Packit Service e080da
            buf[pos++] = *p;
Packit Service e080da
            continue;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        if ((pos + 2) >= len) {
Packit Service e080da
            break;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        switch (*p) {
Packit Service e080da
            case '\b':
Packit Service e080da
                buf[pos++] = '\\';
Packit Service e080da
                buf[pos++] = 'b';
Packit Service e080da
                break;
Packit Service e080da
            case '\n':
Packit Service e080da
                buf[pos++] = '\\';
Packit Service e080da
                buf[pos++] = 'n';
Packit Service e080da
                break;
Packit Service e080da
            case '\r':
Packit Service e080da
                buf[pos++] = '\\';
Packit Service e080da
                buf[pos++] = 'r';
Packit Service e080da
                break;
Packit Service e080da
            case '\t':
Packit Service e080da
                buf[pos++] = '\\';
Packit Service e080da
                buf[pos++] = 't';
Packit Service e080da
                break;
Packit Service e080da
            case '\\':
Packit Service e080da
                buf[pos++] = '\\';
Packit Service e080da
                buf[pos++] = '\\';
Packit Service e080da
                break;
Packit Service e080da
            case '"':
Packit Service e080da
                buf[pos++] = '\\';
Packit Service e080da
                buf[pos++] = '"';
Packit Service e080da
                break;
Packit Service e080da
            default:
Packit Service e080da
                if ((pos + 6) >= len) {
Packit Service e080da
                    buf[pos] = '\0';
Packit Service e080da
                    return (char *)p;
Packit Service e080da
                }
Packit Service e080da
                buf[pos++] = '\\';
Packit Service e080da
                buf[pos++] = 'u';
Packit Service e080da
                buf[pos++] = '0';
Packit Service e080da
                buf[pos++] = '0';
Packit Service e080da
                buf[pos++] = json_hex_chars[(*p) >> 4];
Packit Service e080da
                buf[pos++] = json_hex_chars[(*p) & 0xf];
Packit Service e080da
                break;
Packit Service e080da
        }
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    buf[pos] = '\0';
Packit Service e080da
    return (char *)p;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
/**
Packit Service e080da
 * gf_syslog -function to submit message to syslog specific to gluster
Packit Service e080da
 * @facility_priority: facility_priority of syslog()
Packit Service e080da
 * @format:            optional format string to syslog()
Packit Service e080da
 *
Packit Service e080da
 * @return: void
Packit Service e080da
 */
Packit Service e080da
void
Packit Service e080da
gf_syslog(int facility_priority, char *format, ...)
Packit Service e080da
{
Packit Service e080da
    char *msg = NULL;
Packit Service e080da
    char json_msg[GF_JSON_MSG_LENGTH];
Packit Service e080da
    GF_UNUSED char *p = NULL;
Packit Service e080da
    va_list ap;
Packit Service e080da
Packit Service e080da
    GF_ASSERT(format);
Packit Service e080da
Packit Service e080da
    va_start(ap, format);
Packit Service e080da
    if (vasprintf(&msg, format, ap) != -1) {
Packit Service e080da
        p = _json_escape(msg, json_msg, GF_JSON_MSG_LENGTH);
Packit Service e080da
        syslog(facility_priority, "%s", msg);
Packit Service e080da
        free(msg);
Packit Service e080da
    } else
Packit Service e080da
        syslog(GF_LOG_CRITICAL, "vasprintf() failed, out of memory?");
Packit Service e080da
    va_end(ap);
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_globals_init(void *data, gf_loglevel_t level)
Packit Service e080da
{
Packit Service e080da
    glusterfs_ctx_t *ctx = data;
Packit Service e080da
Packit Service e080da
    pthread_mutex_init(&ctx->log.logfile_mutex, NULL);
Packit Service e080da
Packit Service e080da
    ctx->log.loglevel = level;
Packit Service e080da
    ctx->log.gf_log_syslog = 1;
Packit Service e080da
    ctx->log.sys_log_level = GF_LOG_CRITICAL;
Packit Service e080da
    ctx->log.logger = gf_logger_glusterlog;
Packit Service e080da
    ctx->log.logformat = gf_logformat_withmsgid;
Packit Service e080da
    ctx->log.lru_size = GF_LOG_LRU_BUFSIZE_DEFAULT;
Packit Service e080da
    ctx->log.timeout = GF_LOG_FLUSH_TIMEOUT_DEFAULT;
Packit Service e080da
    ctx->log.localtime = GF_LOG_LOCALTIME_DEFAULT;
Packit Service e080da
Packit Service e080da
    pthread_mutex_init(&ctx->log.log_buf_lock, NULL);
Packit Service e080da
Packit Service e080da
    INIT_LIST_HEAD(&ctx->log.lru_queue);
Packit Service e080da
Packit Service e080da
#ifdef GF_LINUX_HOST_OS
Packit Service e080da
    /* For the 'syslog' output. one can grep 'GlusterFS' in syslog
Packit Service e080da
       for serious logs */
Packit Service e080da
    openlog("GlusterFS", LOG_PID, LOG_DAEMON);
Packit Service e080da
#endif
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
gf_log_init(void *data, const char *file, const char *ident)
Packit Service e080da
{
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
    int fd = -1;
Packit Service e080da
    struct stat buf;
Packit Service e080da
Packit Service e080da
    ctx = data;
Packit Service e080da
Packit Service e080da
    if (ctx == NULL) {
Packit Service e080da
        fprintf(stderr, "ERROR: ctx is NULL\n");
Packit Service e080da
        return -1;
Packit Service e080da
    }
Packit Service e080da
    if (ident) {
Packit Service e080da
        GF_FREE(ctx->log.ident);
Packit Service e080da
        ctx->log.ident = gf_strdup(ident);
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    /* we keep the files and the syslog open, so that on logger change, we
Packit Service e080da
     * are ready to log anywhere, that the new value specifies */
Packit Service e080da
    if (ctx->log.ident) {
Packit Service e080da
        gf_openlog(ctx->log.ident, -1, LOG_DAEMON);
Packit Service e080da
    } else {
Packit Service e080da
        gf_openlog(NULL, -1, LOG_DAEMON);
Packit Service e080da
    }
Packit Service e080da
    /* TODO: make FACILITY configurable than LOG_DAEMON */
Packit Service e080da
    if (sys_stat(GF_LOG_CONTROL_FILE, &buf) == 0) {
Packit Service e080da
        /* use syslog logging */
Packit Service e080da
        ctx->log.log_control_file_found = 1;
Packit Service e080da
    } else {
Packit Service e080da
        /* use old style logging */
Packit Service e080da
        ctx->log.log_control_file_found = 0;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    if (!file) {
Packit Service e080da
        fprintf(stderr, "ERROR: no filename specified\n");
Packit Service e080da
        return -1;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    /* free the (possible) previous filename */
Packit Service e080da
    GF_FREE(ctx->log.filename);
Packit Service e080da
    ctx->log.filename = NULL;
Packit Service e080da
Packit Service e080da
    /* close and reopen logfile for log rotate */
Packit Service e080da
    if (ctx->log.logfile) {
Packit Service e080da
        fclose(ctx->log.logfile);
Packit Service e080da
        ctx->log.logfile = NULL;
Packit Service e080da
        ctx->log.gf_log_logfile = NULL;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    if (strcmp(file, "-") == 0) {
Packit Service e080da
        int dupfd = -1;
Packit Service e080da
Packit Service e080da
        ctx->log.filename = gf_strdup("/dev/stderr");
Packit Service e080da
        if (!ctx->log.filename) {
Packit Service e080da
            fprintf(stderr, "ERROR: strdup failed\n");
Packit Service e080da
            return -1;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        dupfd = dup(fileno(stderr));
Packit Service e080da
        if (dupfd == -1) {
Packit Service e080da
            fprintf(stderr, "ERROR: could not dup %d (%s)\n", fileno(stderr),
Packit Service e080da
                    strerror(errno));
Packit Service e080da
            return -1;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        ctx->log.logfile = fdopen(dupfd, "a");
Packit Service e080da
        if (!ctx->log.logfile) {
Packit Service e080da
            fprintf(stderr, "ERROR: could not fdopen on %d (%s)\n", dupfd,
Packit Service e080da
                    strerror(errno));
Packit Service e080da
            sys_close(dupfd);
Packit Service e080da
            return -1;
Packit Service e080da
        }
Packit Service e080da
    } else {
Packit Service e080da
        /* Also create parent dir */
Packit Service e080da
        char *logdir = gf_strdup(file);
Packit Service e080da
        if (!logdir) {
Packit Service e080da
            return -1;
Packit Service e080da
        }
Packit Service e080da
        char *tmp_index = rindex(logdir, '/');
Packit Service e080da
        if (tmp_index) {
Packit Service e080da
            tmp_index[0] = '\0';
Packit Service e080da
        }
Packit Service e080da
        if (mkdir_p(logdir, 0755, true)) {
Packit Service e080da
            /* EEXIST is handled in mkdir_p() itself */
Packit Service e080da
            gf_msg("logging", GF_LOG_ERROR, 0, LG_MSG_STRDUP_ERROR,
Packit Service e080da
                   "failed to create metrics dir %s (%s)", logdir,
Packit Service e080da
                   strerror(errno));
Packit Service e080da
            GF_FREE(logdir);
Packit Service e080da
            return -1;
Packit Service e080da
        }
Packit Service e080da
        /* no need of this variable */
Packit Service e080da
        GF_FREE(logdir);
Packit Service e080da
Packit Service e080da
        ctx->log.filename = gf_strdup(file);
Packit Service e080da
        if (!ctx->log.filename) {
Packit Service e080da
            fprintf(stderr,
Packit Service e080da
                    "ERROR: updating log-filename failed: "
Packit Service e080da
                    "%s\n",
Packit Service e080da
                    strerror(errno));
Packit Service e080da
            return -1;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        fd = sys_open(file, O_CREAT | O_WRONLY | O_APPEND, S_IRUSR | S_IWUSR);
Packit Service e080da
        if (fd < 0) {
Packit Service e080da
            fprintf(stderr,
Packit Service e080da
                    "ERROR: failed to create logfile"
Packit Service e080da
                    " \"%s\" (%s)\n",
Packit Service e080da
                    file, strerror(errno));
Packit Service e080da
            return -1;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        ctx->log.logfile = fdopen(fd, "a");
Packit Service e080da
        if (!ctx->log.logfile) {
Packit Service e080da
            fprintf(stderr,
Packit Service e080da
                    "ERROR: failed to open logfile \"%s\" "
Packit Service e080da
                    "(%s)\n",
Packit Service e080da
                    file, strerror(errno));
Packit Service e080da
            sys_close(fd);
Packit Service e080da
            return -1;
Packit Service e080da
        }
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    ctx->log.gf_log_logfile = ctx->log.logfile;
Packit Service e080da
Packit Service e080da
    return 0;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
set_sys_log_level(gf_loglevel_t level)
Packit Service e080da
{
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    ctx = THIS->ctx;
Packit Service e080da
Packit Service e080da
    if (ctx)
Packit Service e080da
        ctx->log.sys_log_level = level;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
/* Check if we should be logging
Packit Service e080da
 * Return value: _gf_false : Print the log
Packit Service e080da
 *               _gf_true : Do not Print the log
Packit Service e080da
 */
Packit Service e080da
static gf_boolean_t
Packit Service e080da
skip_logging(xlator_t *this, gf_loglevel_t level)
Packit Service e080da
{
Packit Service e080da
    gf_boolean_t ret = _gf_false;
Packit Service e080da
    gf_loglevel_t existing_level = GF_LOG_NONE;
Packit Service e080da
Packit Service e080da
    if (level == GF_LOG_NONE) {
Packit Service e080da
        ret = _gf_true;
Packit Service e080da
        goto out;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    existing_level = this->loglevel ? this->loglevel : this->ctx->log.loglevel;
Packit Service e080da
    if (level > existing_level) {
Packit Service e080da
        ret = _gf_true;
Packit Service e080da
        goto out;
Packit Service e080da
    }
Packit Service e080da
out:
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
_gf_log_callingfn(const char *domain, const char *file, const char *function,
Packit Service e080da
                  int line, gf_loglevel_t level, const char *fmt, ...)
Packit Service e080da
{
Packit Service e080da
    const char *basename = NULL;
Packit Service e080da
    xlator_t *this = NULL;
Packit Service e080da
    char *logline = NULL;
Packit Service e080da
    char *msg = NULL;
Packit Service e080da
    char timestr[256] = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
    char *callstr = NULL;
Packit Service e080da
    struct timeval tv = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
    int ret = 0;
Packit Service e080da
    va_list ap;
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    this = THIS;
Packit Service e080da
    ctx = this->ctx;
Packit Service e080da
Packit Service e080da
    if (!ctx)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    if (skip_logging(this, level))
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    static char *level_strings[] = {"",  /* NONE */
Packit Service e080da
                                    "M", /* EMERGENCY */
Packit Service e080da
                                    "A", /* ALERT */
Packit Service e080da
                                    "C", /* CRITICAL */
Packit Service e080da
                                    "E", /* ERROR */
Packit Service e080da
                                    "W", /* WARNING */
Packit Service e080da
                                    "N", /* NOTICE */
Packit Service e080da
                                    "I", /* INFO */
Packit Service e080da
                                    "D", /* DEBUG */
Packit Service e080da
                                    "T", /* TRACE */
Packit Service e080da
                                    ""};
Packit Service e080da
Packit Service e080da
    if (!domain || !file || !function || !fmt) {
Packit Service e080da
        fprintf(stderr, "logging: %s:%s():%d: invalid argument\n", __FILE__,
Packit Service e080da
                __PRETTY_FUNCTION__, __LINE__);
Packit Service e080da
        return -1;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    basename = strrchr(file, '/');
Packit Service e080da
    if (basename)
Packit Service e080da
        basename++;
Packit Service e080da
    else
Packit Service e080da
        basename = file;
Packit Service e080da
Packit Service e080da
    /*Saving the backtrace to pre-allocated ctx->btbuf
Packit Service e080da
     * to avoid allocating memory from the heap*/
Packit Service e080da
    callstr = gf_backtrace_save(NULL);
Packit Service e080da
Packit Service e080da
    va_start(ap, fmt);
Packit Service e080da
    ret = vasprintf(&msg, fmt, ap);
Packit Service e080da
    va_end(ap);
Packit Service e080da
    if (-1 == ret) {
Packit Service e080da
        goto out;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    if (ctx->log.log_control_file_found) {
Packit Service e080da
        int priority;
Packit Service e080da
        /* treat GF_LOG_TRACE and GF_LOG_NONE as LOG_DEBUG and
Packit Service e080da
           other level as is */
Packit Service e080da
        if (GF_LOG_TRACE == level || GF_LOG_NONE == level) {
Packit Service e080da
            priority = LOG_DEBUG;
Packit Service e080da
        } else {
Packit Service e080da
            priority = level - 1;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        gf_syslog(priority, "[%s:%d:%s] %s %d-%s: %s", basename, line, function,
Packit Service e080da
                  callstr, ((this->graph) ? this->graph->id : 0), domain, msg);
Packit Service e080da
Packit Service e080da
        goto out;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    ret = gettimeofday(&tv, NULL);
Packit Service e080da
    if (-1 == ret)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    gf_time_fmt(timestr, sizeof timestr, tv.tv_sec, gf_timefmt_FT);
Packit Service e080da
    snprintf(timestr + strlen(timestr), sizeof timestr - strlen(timestr),
Packit Service e080da
             ".%" GF_PRI_SUSECONDS, tv.tv_usec);
Packit Service e080da
Packit Service e080da
    ret = gf_asprintf(&logline, "[%s] %s [%s:%d:%s] %s %d-%s: %s", timestr,
Packit Service e080da
                      level_strings[level], basename, line, function, callstr,
Packit Service e080da
                      ((this->graph) ? this->graph->id : 0), domain, msg);
Packit Service e080da
    if (-1 == ret) {
Packit Service e080da
        goto out;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    pthread_mutex_lock(&ctx->log.logfile_mutex);
Packit Service e080da
    {
Packit Service e080da
        if (ctx->log.logfile) {
Packit Service e080da
            fprintf(ctx->log.logfile, "%s\n", logline);
Packit Service e080da
            fflush(ctx->log.logfile);
Packit Service e080da
        } else if (ctx->log.loglevel >= level) {
Packit Service e080da
            fprintf(stderr, "%s\n", logline);
Packit Service e080da
            fflush(stderr);
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
#ifdef GF_LINUX_HOST_OS
Packit Service e080da
        /* We want only serious log in 'syslog', not our debug
Packit Service e080da
           and trace logs */
Packit Service e080da
        if (ctx->log.gf_log_syslog && level &&
Packit Service e080da
            (level <= ctx->log.sys_log_level))
Packit Service e080da
            syslog((level - 1), "%s\n", logline);
Packit Service e080da
#endif
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    pthread_mutex_unlock(&ctx->log.logfile_mutex);
Packit Service e080da
Packit Service e080da
out:
Packit Service e080da
Packit Service e080da
    GF_FREE(logline);
Packit Service e080da
Packit Service e080da
    FREE(msg);
Packit Service e080da
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
_gf_msg_plain_internal(gf_loglevel_t level, const char *msg)
Packit Service e080da
{
Packit Service e080da
    xlator_t *this = NULL;
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
    int priority;
Packit Service e080da
Packit Service e080da
    this = THIS;
Packit Service e080da
    ctx = this->ctx;
Packit Service e080da
Packit Service e080da
    /* log to the configured logging service */
Packit Service e080da
    switch (ctx->log.logger) {
Packit Service e080da
        case gf_logger_syslog:
Packit Service e080da
            if (ctx->log.log_control_file_found && ctx->log.gf_log_syslog) {
Packit Service e080da
                SET_LOG_PRIO(level, priority);
Packit Service e080da
Packit Service e080da
                syslog(priority, "%s", msg);
Packit Service e080da
                break;
Packit Service e080da
            }
Packit Service e080da
            /* NOTE: If syslog control file is absent, which is another
Packit Service e080da
             * way to control logging to syslog, then we will fall through
Packit Service e080da
             * to the gluster log. The ideal way to do things would be to
Packit Service e080da
             * not have the extra control file check */
Packit Service e080da
        case gf_logger_glusterlog:
Packit Service e080da
            pthread_mutex_lock(&ctx->log.logfile_mutex);
Packit Service e080da
            {
Packit Service e080da
                if (ctx->log.logfile) {
Packit Service e080da
                    fprintf(ctx->log.logfile, "%s\n", msg);
Packit Service e080da
                    fflush(ctx->log.logfile);
Packit Service e080da
                } else {
Packit Service e080da
                    fprintf(stderr, "%s\n", msg);
Packit Service e080da
                    fflush(stderr);
Packit Service e080da
                }
Packit Service e080da
Packit Service e080da
#ifdef GF_LINUX_HOST_OS
Packit Service e080da
                /* We want only serious logs in 'syslog', not our debug
Packit Service e080da
                 * and trace logs */
Packit Service e080da
                if (ctx->log.gf_log_syslog && level &&
Packit Service e080da
                    (level <= ctx->log.sys_log_level))
Packit Service e080da
                    syslog((level - 1), "%s\n", msg);
Packit Service e080da
#endif
Packit Service e080da
            }
Packit Service e080da
            pthread_mutex_unlock(&ctx->log.logfile_mutex);
Packit Service e080da
Packit Service e080da
            break;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    return 0;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
_gf_msg_plain(gf_loglevel_t level, const char *fmt, ...)
Packit Service e080da
{
Packit Service e080da
    xlator_t *this = NULL;
Packit Service e080da
    int ret = 0;
Packit Service e080da
    va_list ap;
Packit Service e080da
    char *msg = NULL;
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    this = THIS;
Packit Service e080da
    ctx = this->ctx;
Packit Service e080da
Packit Service e080da
    if (!ctx)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    if (skip_logging(this, level))
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    va_start(ap, fmt);
Packit Service e080da
    ret = vasprintf(&msg, fmt, ap);
Packit Service e080da
    va_end(ap);
Packit Service e080da
    if (-1 == ret) {
Packit Service e080da
        goto out;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    ret = _gf_msg_plain_internal(level, msg);
Packit Service e080da
Packit Service e080da
    FREE(msg);
Packit Service e080da
Packit Service e080da
out:
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
_gf_msg_vplain(gf_loglevel_t level, const char *fmt, va_list ap)
Packit Service e080da
{
Packit Service e080da
    xlator_t *this = NULL;
Packit Service e080da
    int ret = 0;
Packit Service e080da
    char *msg = NULL;
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    this = THIS;
Packit Service e080da
    ctx = this->ctx;
Packit Service e080da
Packit Service e080da
    if (!ctx)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    if (skip_logging(this, level))
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    ret = vasprintf(&msg, fmt, ap);
Packit Service e080da
    if (-1 == ret) {
Packit Service e080da
        goto out;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    ret = _gf_msg_plain_internal(level, msg);
Packit Service e080da
Packit Service e080da
    FREE(msg);
Packit Service e080da
out:
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
_gf_msg_plain_nomem(gf_loglevel_t level, const char *msg)
Packit Service e080da
{
Packit Service e080da
    xlator_t *this = NULL;
Packit Service e080da
    int ret = 0;
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    this = THIS;
Packit Service e080da
    ctx = this->ctx;
Packit Service e080da
Packit Service e080da
    if (!ctx)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    if (skip_logging(this, level))
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    ret = _gf_msg_plain_internal(level, msg);
Packit Service e080da
Packit Service e080da
out:
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
_gf_msg_backtrace_nomem(gf_loglevel_t level, int stacksize)
Packit Service e080da
{
Packit Service e080da
    xlator_t *this = NULL;
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
    void *array[200];
Packit Service e080da
    size_t bt_size = 0;
Packit Service e080da
    int fd = -1;
Packit Service e080da
Packit Service e080da
    this = THIS;
Packit Service e080da
    ctx = this->ctx;
Packit Service e080da
Packit Service e080da
    if (!ctx)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    /* syslog does not have fd support, hence no no-mem variant */
Packit Service e080da
    if (ctx->log.logger != gf_logger_glusterlog)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    if (skip_logging(this, level))
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    bt_size = backtrace(array, ((stacksize <= 200) ? stacksize : 200));
Packit Service e080da
    pthread_mutex_lock(&ctx->log.logfile_mutex);
Packit Service e080da
    {
Packit Service e080da
        fd = ctx->log.logfile ? fileno(ctx->log.logfile) : fileno(stderr);
Packit Service e080da
        if (bt_size && (fd != -1)) {
Packit Service e080da
            /* print to the file fd, to prevent any
Packit Service e080da
               allocations from backtrace_symbols
Packit Service e080da
             */
Packit Service e080da
            backtrace_symbols_fd(&array[0], bt_size, fd);
Packit Service e080da
        }
Packit Service e080da
    }
Packit Service e080da
    pthread_mutex_unlock(&ctx->log.logfile_mutex);
Packit Service e080da
Packit Service e080da
out:
Packit Service e080da
    return;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
_gf_msg_backtrace(int stacksize, char *callstr, size_t strsize)
Packit Service e080da
{
Packit Service e080da
    int ret = -1;
Packit Service e080da
    int i = 0;
Packit Service e080da
    int size = 0;
Packit Service e080da
    int savstrsize = strsize;
Packit Service e080da
    void *array[200];
Packit Service e080da
    char **callingfn = NULL;
Packit Service e080da
Packit Service e080da
    /* We chop off last 2 anyway, so if request is less than tolerance
Packit Service e080da
     * nothing to do */
Packit Service e080da
    if (stacksize < 3)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    size = backtrace(array, ((stacksize <= 200) ? stacksize : 200));
Packit Service e080da
    if ((size - 3) < 0)
Packit Service e080da
        goto out;
Packit Service e080da
    if (size)
Packit Service e080da
        callingfn = backtrace_symbols(&array[2], size - 2);
Packit Service e080da
    if (!callingfn)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    ret = snprintf(callstr, strsize, "(");
Packit Service e080da
    PRINT_SIZE_CHECK(ret, out, strsize);
Packit Service e080da
Packit Service e080da
    for ((i = size - 3); i >= 0; i--) {
Packit Service e080da
        ret = snprintf(callstr + savstrsize - strsize, strsize, "-->%s ",
Packit Service e080da
                       callingfn[i]);
Packit Service e080da
        PRINT_SIZE_CHECK(ret, out, strsize);
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    ret = snprintf(callstr + savstrsize - strsize, strsize, ")");
Packit Service e080da
    PRINT_SIZE_CHECK(ret, out, strsize);
Packit Service e080da
out:
Packit Service e080da
    FREE(callingfn);
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
_gf_msg_nomem(const char *domain, const char *file, const char *function,
Packit Service e080da
              int line, gf_loglevel_t level, size_t size)
Packit Service e080da
{
Packit Service e080da
    const char *basename = NULL;
Packit Service e080da
    xlator_t *this = NULL;
Packit Service e080da
    struct timeval tv = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
    int ret = 0;
Packit Service e080da
    int fd = -1;
Packit Service e080da
    char msg[2048] = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
    char timestr[GF_LOG_TIMESTR_SIZE] = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
    int wlen = 0;
Packit Service e080da
    int priority;
Packit Service 173fb3
    struct rusage r_usage;
Packit Service e080da
Packit Service e080da
    this = THIS;
Packit Service e080da
    ctx = this->ctx;
Packit Service e080da
Packit Service e080da
    if (!ctx)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    if (skip_logging(this, level))
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    if (!domain || !file || !function) {
Packit Service e080da
        fprintf(stderr, "logging: %s:%s():%d: invalid argument\n", __FILE__,
Packit Service e080da
                __PRETTY_FUNCTION__, __LINE__);
Packit Service e080da
        return -1;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    GET_FILE_NAME_TO_LOG(file, basename);
Packit Service e080da
Packit Service e080da
    ret = gettimeofday(&tv, NULL);
Packit Service e080da
    if (-1 == ret)
Packit Service e080da
        goto out;
Packit Service e080da
    gf_time_fmt(timestr, sizeof timestr, tv.tv_sec, gf_timefmt_FT);
Packit Service e080da
    ret = snprintf(timestr + strlen(timestr), sizeof timestr - strlen(timestr),
Packit Service e080da
                   ".%" GF_PRI_SUSECONDS, tv.tv_usec);
Packit Service e080da
    if (-1 == ret) {
Packit Service e080da
        goto out;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    /* TODO: Currently we print in the enhanced format, with a message ID
Packit Service e080da
     * of 0. Need to enhance this to support format as configured */
Packit Service e080da
    ret = snprintf(msg, sizeof msg,
Packit Service e080da
                   "[%s] %s [MSGID: %" PRIu64
Packit Service e080da
                   "]"
Packit Service e080da
                   " [%s:%d:%s] %s: no memory "
Packit Service e080da
                   "available for size (%" GF_PRI_SIZET
Packit Service 173fb3
                   ") current memory usage in kilobytes %ld"
Packit Service e080da
                   " [call stack follows]\n",
Packit Service e080da
                   timestr, gf_level_strings[level], (uint64_t)0, basename,
Packit Service 173fb3
                   line, function, domain, size,
Packit Service 173fb3
                   (!getrusage(RUSAGE_SELF, &r_usage) ? r_usage.ru_maxrss : 0));
Packit Service e080da
    if (-1 == ret) {
Packit Service e080da
        goto out;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    /* log to the configured logging service */
Packit Service e080da
    switch (ctx->log.logger) {
Packit Service e080da
        case gf_logger_syslog:
Packit Service e080da
            if (ctx->log.log_control_file_found && ctx->log.gf_log_syslog) {
Packit Service e080da
                SET_LOG_PRIO(level, priority);
Packit Service e080da
Packit Service e080da
                /* if syslog allocates, then this may fail, but we
Packit Service e080da
                 * cannot do much about it at the moment */
Packit Service e080da
                /* There is no fd for syslog, hence no stack printed */
Packit Service e080da
                syslog(priority, "%s", msg);
Packit Service e080da
                break;
Packit Service e080da
            }
Packit Service e080da
            /* NOTE: If syslog control file is absent, which is another
Packit Service e080da
             * way to control logging to syslog, then we will fall through
Packit Service e080da
             * to the gluster log. The ideal way to do things would be to
Packit Service e080da
             * not have the extra control file check */
Packit Service e080da
        case gf_logger_glusterlog:
Packit Service e080da
            pthread_mutex_lock(&ctx->log.logfile_mutex);
Packit Service e080da
            {
Packit Service e080da
                fd = ctx->log.logfile ? fileno(ctx->log.logfile)
Packit Service e080da
                                      : fileno(stderr);
Packit Service e080da
                if (fd == -1) {
Packit Service e080da
                    pthread_mutex_unlock(&ctx->log.logfile_mutex);
Packit Service e080da
                    goto out;
Packit Service e080da
                }
Packit Service e080da
Packit Service e080da
                wlen = strlen(msg);
Packit Service e080da
Packit Service e080da
                /* write directly to the fd to prevent out of order
Packit Service e080da
                 * message and stack */
Packit Service e080da
                ret = sys_write(fd, msg, wlen);
Packit Service e080da
                if (ret == -1) {
Packit Service e080da
                    pthread_mutex_unlock(&ctx->log.logfile_mutex);
Packit Service e080da
                    goto out;
Packit Service e080da
                }
Packit Service e080da
#ifdef GF_LINUX_HOST_OS
Packit Service e080da
                /* We want only serious log in 'syslog', not our debug
Packit Service e080da
                 * and trace logs */
Packit Service e080da
                if (ctx->log.gf_log_syslog && level &&
Packit Service e080da
                    (level <= ctx->log.sys_log_level))
Packit Service e080da
                    syslog((level - 1), "%s\n", msg);
Packit Service e080da
#endif
Packit Service e080da
            }
Packit Service e080da
            pthread_mutex_unlock(&ctx->log.logfile_mutex);
Packit Service e080da
Packit Service e080da
            _gf_msg_backtrace_nomem(level, GF_LOG_BACKTRACE_DEPTH);
Packit Service e080da
Packit Service e080da
            break;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
out:
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
static int
Packit Service e080da
gf_log_syslog(glusterfs_ctx_t *ctx, const char *domain, const char *file,
Packit Service e080da
              const char *function, int32_t line, gf_loglevel_t level,
Packit Service e080da
              int errnum, uint64_t msgid, char **appmsgstr, char *callstr,
Packit Service e080da
              int graph_id, gf_log_format_t fmt)
Packit Service e080da
{
Packit Service e080da
    int priority;
Packit Service e080da
Packit Service e080da
    SET_LOG_PRIO(level, priority);
Packit Service e080da
Packit Service e080da
    /* log with appropriate format */
Packit Service e080da
    switch (fmt) {
Packit Service e080da
        case gf_logformat_traditional:
Packit Service e080da
            if (!callstr) {
Packit Service e080da
                if (errnum)
Packit Service e080da
                    syslog(priority, "[%s:%d:%s] %d-%s: %s [%s]", file, line,
Packit Service e080da
                           function, graph_id, domain, *appmsgstr,
Packit Service e080da
                           strerror(errnum));
Packit Service e080da
                else
Packit Service e080da
                    syslog(priority, "[%s:%d:%s] %d-%s: %s", file, line,
Packit Service e080da
                           function, graph_id, domain, *appmsgstr);
Packit Service e080da
            } else {
Packit Service e080da
                if (errnum)
Packit Service e080da
                    syslog(priority,
Packit Service e080da
                           "[%s:%d:%s] %s %d-%s:"
Packit Service e080da
                           " %s [%s]",
Packit Service e080da
                           file, line, function, callstr, graph_id, domain,
Packit Service e080da
                           *appmsgstr, strerror(errnum));
Packit Service e080da
                else
Packit Service e080da
                    syslog(priority, "[%s:%d:%s] %s %d-%s: %s", file, line,
Packit Service e080da
                           function, callstr, graph_id, domain, *appmsgstr);
Packit Service e080da
            }
Packit Service e080da
            break;
Packit Service e080da
        case gf_logformat_withmsgid:
Packit Service e080da
            if (!callstr) {
Packit Service e080da
                if (errnum)
Packit Service e080da
                    syslog(priority,
Packit Service e080da
                           "[MSGID: %" PRIu64
Packit Service e080da
                           "]"
Packit Service e080da
                           " [%s:%d:%s] %d-%s: %s [%s]",
Packit Service e080da
                           msgid, file, line, function, graph_id, domain,
Packit Service e080da
                           *appmsgstr, strerror(errnum));
Packit Service e080da
                else
Packit Service e080da
                    syslog(priority,
Packit Service e080da
                           "[MSGID: %" PRIu64
Packit Service e080da
                           "]"
Packit Service e080da
                           " [%s:%d:%s] %d-%s: %s",
Packit Service e080da
                           msgid, file, line, function, graph_id, domain,
Packit Service e080da
                           *appmsgstr);
Packit Service e080da
            } else {
Packit Service e080da
                if (errnum)
Packit Service e080da
                    syslog(priority,
Packit Service e080da
                           "[MSGID: %" PRIu64
Packit Service e080da
                           "]"
Packit Service e080da
                           " [%s:%d:%s] %s %d-%s: %s [%s]",
Packit Service e080da
                           msgid, file, line, function, callstr, graph_id,
Packit Service e080da
                           domain, *appmsgstr, strerror(errnum));
Packit Service e080da
                else
Packit Service e080da
                    syslog(priority,
Packit Service e080da
                           "[MSGID: %" PRIu64
Packit Service e080da
                           "]"
Packit Service e080da
                           " [%s:%d:%s] %s %d-%s: %s",
Packit Service e080da
                           msgid, file, line, function, callstr, graph_id,
Packit Service e080da
                           domain, *appmsgstr);
Packit Service e080da
            }
Packit Service e080da
            break;
Packit Service e080da
        case gf_logformat_cee:
Packit Service e080da
            /* TODO: Enhance CEE with additional parameters */
Packit Service e080da
            gf_syslog(priority, "[%s:%d:%s] %d-%s: %s", file, line, function,
Packit Service e080da
                      graph_id, domain, *appmsgstr);
Packit Service e080da
            break;
Packit Service e080da
Packit Service e080da
        default:
Packit Service e080da
            /* NOTE: should not get here without logging */
Packit Service e080da
            break;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    /* TODO: There can be no errors from gf_syslog? */
Packit Service e080da
    return 0;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
static int
Packit Service e080da
gf_log_glusterlog(glusterfs_ctx_t *ctx, const char *domain, const char *file,
Packit Service e080da
                  const char *function, int32_t line, gf_loglevel_t level,
Packit Service e080da
                  int errnum, uint64_t msgid, char **appmsgstr, char *callstr,
Packit Service e080da
                  struct timeval tv, int graph_id, gf_log_format_t fmt)
Packit Service e080da
{
Packit Service e080da
    char timestr[GF_LOG_TIMESTR_SIZE] = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
    char *header = NULL;
Packit Service e080da
    char *footer = NULL;
Packit Service e080da
    char *msg = NULL;
Packit Service e080da
    size_t hlen = 0, flen = 0, mlen = 0;
Packit Service e080da
    int ret = 0;
Packit Service e080da
Packit Service e080da
    /* rotate if required */
Packit Service e080da
    gf_log_rotate(ctx);
Packit Service e080da
Packit Service e080da
    /* format the time stamp */
Packit Service e080da
    gf_time_fmt(timestr, sizeof timestr, tv.tv_sec, gf_timefmt_FT);
Packit Service e080da
    snprintf(timestr + strlen(timestr), sizeof timestr - strlen(timestr),
Packit Service e080da
             ".%" GF_PRI_SUSECONDS, tv.tv_usec);
Packit Service e080da
Packit Service e080da
    /* generate header and footer */
Packit Service e080da
    if (fmt == gf_logformat_traditional) {
Packit Service e080da
        if (!callstr) {
Packit Service e080da
            ret = gf_asprintf(&header,
Packit Service e080da
                              "[%s] %s [%s:%d:%s]"
Packit Service e080da
                              " %d-%s: ",
Packit Service e080da
                              timestr, gf_level_strings[level], file, line,
Packit Service e080da
                              function, graph_id, domain);
Packit Service e080da
        } else {
Packit Service e080da
            ret = gf_asprintf(&header,
Packit Service e080da
                              "[%s] %s [%s:%d:%s] %s"
Packit Service e080da
                              " %d-%s: ",
Packit Service e080da
                              timestr, gf_level_strings[level], file, line,
Packit Service e080da
                              function, callstr, graph_id, domain);
Packit Service e080da
        }
Packit Service e080da
        if (-1 == ret) {
Packit Service e080da
            goto err;
Packit Service e080da
        }
Packit Service e080da
    } else { /* gf_logformat_withmsgid */
Packit Service e080da
        /* CEE log format unsupported in logger_glusterlog, so just
Packit Service e080da
         * print enhanced log format */
Packit Service e080da
        if (!callstr) {
Packit Service e080da
            ret = gf_asprintf(&header,
Packit Service e080da
                              "[%s] %s [MSGID: %" PRIu64
Packit Service e080da
                              "]"
Packit Service e080da
                              " [%s:%d:%s] %d-%s: ",
Packit Service e080da
                              timestr, gf_level_strings[level], msgid, file,
Packit Service e080da
                              line, function, graph_id, domain);
Packit Service e080da
        } else {
Packit Service e080da
            ret = gf_asprintf(&header,
Packit Service e080da
                              "[%s] %s [MSGID: %" PRIu64
Packit Service e080da
                              "]"
Packit Service e080da
                              " [%s:%d:%s] %s %d-%s: ",
Packit Service e080da
                              timestr, gf_level_strings[level], msgid, file,
Packit Service e080da
                              line, function, callstr, graph_id, domain);
Packit Service e080da
        }
Packit Service e080da
        if (-1 == ret) {
Packit Service e080da
            goto err;
Packit Service e080da
        }
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    if (errnum) {
Packit Service e080da
        ret = gf_asprintf(&footer, " [%s]", strerror(errnum));
Packit Service e080da
        if (-1 == ret) {
Packit Service e080da
            goto err;
Packit Service e080da
        }
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    /* generate the full message to log */
Packit Service e080da
    hlen = strlen(header);
Packit Service e080da
    flen = footer ? strlen(footer) : 0;
Packit Service e080da
    mlen = strlen(*appmsgstr);
Packit Service e080da
    msg = GF_MALLOC(hlen + flen + mlen + 1, gf_common_mt_char);
Packit Service e080da
    if (!msg) {
Packit Service e080da
        ret = -1;
Packit Service e080da
        goto err;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    strcpy(msg, header);
Packit Service e080da
    strcpy(msg + hlen, *appmsgstr);
Packit Service e080da
    if (footer)
Packit Service e080da
        strcpy(msg + hlen + mlen, footer);
Packit Service e080da
Packit Service e080da
    pthread_mutex_lock(&ctx->log.logfile_mutex);
Packit Service e080da
    {
Packit Service e080da
        if (ctx->log.logfile) {
Packit Service e080da
            fprintf(ctx->log.logfile, "%s\n", msg);
Packit Service e080da
            fflush(ctx->log.logfile);
Packit Service e080da
        } else if (ctx->log.loglevel >= level) {
Packit Service e080da
            fprintf(stderr, "%s\n", msg);
Packit Service e080da
            fflush(stderr);
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
#ifdef GF_LINUX_HOST_OS
Packit Service e080da
        /* We want only serious logs in 'syslog', not our debug
Packit Service e080da
         * and trace logs */
Packit Service e080da
        if (ctx->log.gf_log_syslog && level &&
Packit Service e080da
            (level <= ctx->log.sys_log_level))
Packit Service e080da
            syslog((level - 1), "%s\n", msg);
Packit Service e080da
#endif
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    /* TODO: Plugin in memory log buffer retention here. For logs not
Packit Service e080da
     * flushed during cores, it would be useful to retain some of the last
Packit Service e080da
     * few messages in memory */
Packit Service e080da
    pthread_mutex_unlock(&ctx->log.logfile_mutex);
Packit Service e080da
    ret = 0;
Packit Service e080da
Packit Service e080da
err:
Packit Service e080da
    GF_FREE(msg);
Packit Service e080da
    GF_FREE(header);
Packit Service e080da
    GF_FREE(footer);
Packit Service e080da
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
static int
Packit Service e080da
gf_syslog_log_repetitions(const char *domain, const char *file,
Packit Service e080da
                          const char *function, int32_t line,
Packit Service e080da
                          gf_loglevel_t level, int errnum, uint64_t msgid,
Packit Service e080da
                          char **appmsgstr, char *callstr, int refcount,
Packit Service e080da
                          struct timeval oldest, struct timeval latest,
Packit Service e080da
                          int graph_id)
Packit Service e080da
{
Packit Service e080da
    int priority;
Packit Service e080da
    char timestr_latest[256] = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
    char timestr_oldest[256] = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
Packit Service e080da
    SET_LOG_PRIO(level, priority);
Packit Service e080da
Packit Service e080da
    gf_time_fmt(timestr_latest, sizeof timestr_latest, latest.tv_sec,
Packit Service e080da
                gf_timefmt_FT);
Packit Service e080da
    snprintf(timestr_latest + strlen(timestr_latest),
Packit Service e080da
             sizeof(timestr_latest) - strlen(timestr_latest),
Packit Service e080da
             ".%" GF_PRI_SUSECONDS, latest.tv_usec);
Packit Service e080da
Packit Service e080da
    gf_time_fmt(timestr_oldest, sizeof timestr_oldest, oldest.tv_sec,
Packit Service e080da
                gf_timefmt_FT);
Packit Service e080da
    snprintf(timestr_oldest + strlen(timestr_oldest),
Packit Service e080da
             sizeof(timestr_oldest) - strlen(timestr_oldest),
Packit Service e080da
             ".%" GF_PRI_SUSECONDS, oldest.tv_usec);
Packit Service e080da
Packit Service e080da
    if (errnum) {
Packit Service e080da
        syslog(priority,
Packit Service e080da
               "The message \"[MSGID: %" PRIu64
Packit Service e080da
               "] [%s:%d:%s] "
Packit Service e080da
               "%d-%s: %s [%s] \" repeated %d times between %s and %s",
Packit Service e080da
               msgid, file, line, function, graph_id, domain, *appmsgstr,
Packit Service e080da
               strerror(errnum), refcount, timestr_oldest, timestr_latest);
Packit Service e080da
    } else {
Packit Service e080da
        syslog(priority,
Packit Service e080da
               "The message \"[MSGID: %" PRIu64
Packit Service e080da
               "] [%s:%d:%s] "
Packit Service e080da
               "%d-%s: %s \" repeated %d times between %s and %s",
Packit Service e080da
               msgid, file, line, function, graph_id, domain, *appmsgstr,
Packit Service e080da
               refcount, timestr_oldest, timestr_latest);
Packit Service e080da
    }
Packit Service e080da
    return 0;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
static int
Packit Service e080da
gf_glusterlog_log_repetitions(glusterfs_ctx_t *ctx, const char *domain,
Packit Service e080da
                              const char *file, const char *function,
Packit Service e080da
                              int32_t line, gf_loglevel_t level, int errnum,
Packit Service e080da
                              uint64_t msgid, char **appmsgstr, char *callstr,
Packit Service e080da
                              int refcount, struct timeval oldest,
Packit Service e080da
                              struct timeval latest, int graph_id)
Packit Service e080da
{
Packit Service e080da
    int ret = 0;
Packit Service e080da
    size_t hlen = 0;
Packit Service e080da
    size_t flen = 0;
Packit Service e080da
    size_t mlen = 0;
Packit Service e080da
    char timestr_latest[256] = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
    char timestr_oldest[256] = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
    char errstr[256] = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
    char *header = NULL;
Packit Service e080da
    char *footer = NULL;
Packit Service e080da
    char *msg = NULL;
Packit Service e080da
Packit Service e080da
    if (!ctx)
Packit Service e080da
        goto err;
Packit Service e080da
Packit Service e080da
    gf_log_rotate(ctx);
Packit Service e080da
Packit Service e080da
    gf_time_fmt(timestr_latest, sizeof timestr_latest, latest.tv_sec,
Packit Service e080da
                gf_timefmt_FT);
Packit Service e080da
    snprintf(timestr_latest + strlen(timestr_latest),
Packit Service e080da
             sizeof(timestr_latest) - strlen(timestr_latest),
Packit Service e080da
             ".%" GF_PRI_SUSECONDS, latest.tv_usec);
Packit Service e080da
Packit Service e080da
    gf_time_fmt(timestr_oldest, sizeof timestr_oldest, oldest.tv_sec,
Packit Service e080da
                gf_timefmt_FT);
Packit Service e080da
    snprintf(timestr_oldest + strlen(timestr_oldest),
Packit Service e080da
             sizeof(timestr_oldest) - strlen(timestr_oldest),
Packit Service e080da
             ".%" GF_PRI_SUSECONDS, oldest.tv_usec);
Packit Service e080da
Packit Service e080da
    ret = gf_asprintf(&header,
Packit Service e080da
                      "The message \"%s [MSGID: %" PRIu64
Packit Service e080da
                      "]"
Packit Service e080da
                      " [%s:%d:%s] %d-%s: ",
Packit Service e080da
                      gf_level_strings[level], msgid, file, line, function,
Packit Service e080da
                      graph_id, domain);
Packit Service e080da
    if (-1 == ret)
Packit Service e080da
        goto err;
Packit Service e080da
Packit Service e080da
    if (errnum)
Packit Service e080da
        snprintf(errstr, sizeof(errstr) - 1, " [%s]", strerror(errnum));
Packit Service e080da
Packit Service e080da
    ret = gf_asprintf(&footer,
Packit Service e080da
                      "%s\" repeated %d times between"
Packit Service e080da
                      " [%s] and [%s]",
Packit Service e080da
                      errstr, refcount, timestr_oldest, timestr_latest);
Packit Service e080da
    if (-1 == ret)
Packit Service e080da
        goto err;
Packit Service e080da
Packit Service e080da
    /* generate the full message to log */
Packit Service e080da
    hlen = strlen(header);
Packit Service e080da
    flen = strlen(footer);
Packit Service e080da
    mlen = strlen(*appmsgstr);
Packit Service e080da
    msg = GF_MALLOC(hlen + flen + mlen + 1, gf_common_mt_char);
Packit Service e080da
    if (!msg) {
Packit Service e080da
        ret = -1;
Packit Service e080da
        goto err;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    strcpy(msg, header);
Packit Service e080da
    strcpy(msg + hlen, *appmsgstr);
Packit Service e080da
    strcpy(msg + hlen + mlen, footer);
Packit Service e080da
Packit Service e080da
    pthread_mutex_lock(&ctx->log.logfile_mutex);
Packit Service e080da
    {
Packit Service e080da
        if (ctx->log.logfile) {
Packit Service e080da
            fprintf(ctx->log.logfile, "%s\n", msg);
Packit Service e080da
            fflush(ctx->log.logfile);
Packit Service e080da
        } else if (ctx->log.loglevel >= level) {
Packit Service e080da
            fprintf(stderr, "%s\n", msg);
Packit Service e080da
            fflush(stderr);
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
#ifdef GF_LINUX_HOST_OS
Packit Service e080da
        /* We want only serious logs in 'syslog', not our debug
Packit Service e080da
         * and trace logs */
Packit Service e080da
        if (ctx->log.gf_log_syslog && level &&
Packit Service e080da
            (level <= ctx->log.sys_log_level))
Packit Service e080da
            syslog((level - 1), "%s\n", msg);
Packit Service e080da
#endif
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    /* TODO: Plugin in memory log buffer retention here. For logs not
Packit Service e080da
     * flushed during cores, it would be useful to retain some of the last
Packit Service e080da
     * few messages in memory */
Packit Service e080da
    pthread_mutex_unlock(&ctx->log.logfile_mutex);
Packit Service e080da
    ret = 0;
Packit Service e080da
Packit Service e080da
err:
Packit Service e080da
    GF_FREE(msg);
Packit Service e080da
    GF_FREE(header);
Packit Service e080da
    GF_FREE(footer);
Packit Service e080da
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
static int
Packit Service e080da
gf_log_print_with_repetitions(glusterfs_ctx_t *ctx, const char *domain,
Packit Service e080da
                              const char *file, const char *function,
Packit Service e080da
                              int32_t line, gf_loglevel_t level, int errnum,
Packit Service e080da
                              uint64_t msgid, char **appmsgstr, char *callstr,
Packit Service e080da
                              int refcount, struct timeval oldest,
Packit Service e080da
                              struct timeval latest, int graph_id)
Packit Service e080da
{
Packit Service e080da
    int ret = -1;
Packit Service e080da
    gf_log_logger_t logger = 0;
Packit Service e080da
Packit Service e080da
    logger = ctx->log.logger;
Packit Service e080da
Packit Service e080da
    switch (logger) {
Packit Service e080da
        case gf_logger_syslog:
Packit Service e080da
            if (ctx->log.log_control_file_found && ctx->log.gf_log_syslog) {
Packit Service e080da
                ret = gf_syslog_log_repetitions(
Packit Service e080da
                    domain, file, function, line, level, errnum, msgid,
Packit Service e080da
                    appmsgstr, callstr, refcount, oldest, latest, graph_id);
Packit Service e080da
                break;
Packit Service e080da
            }
Packit Service e080da
        case gf_logger_glusterlog:
Packit Service e080da
            ret = gf_glusterlog_log_repetitions(
Packit Service e080da
                ctx, domain, file, function, line, level, errnum, msgid,
Packit Service e080da
                appmsgstr, callstr, refcount, oldest, latest, graph_id);
Packit Service e080da
            break;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
static int
Packit Service e080da
gf_log_print_plain_fmt(glusterfs_ctx_t *ctx, const char *domain,
Packit Service e080da
                       const char *file, const char *function, int32_t line,
Packit Service e080da
                       gf_loglevel_t level, int errnum, uint64_t msgid,
Packit Service e080da
                       char **appmsgstr, char *callstr, struct timeval tv,
Packit Service e080da
                       int graph_id, gf_log_format_t fmt)
Packit Service e080da
{
Packit Service e080da
    int ret = -1;
Packit Service e080da
    gf_log_logger_t logger = 0;
Packit Service e080da
Packit Service e080da
    logger = ctx->log.logger;
Packit Service e080da
Packit Service e080da
    /* log to the configured logging service */
Packit Service e080da
    switch (logger) {
Packit Service e080da
        case gf_logger_syslog:
Packit Service e080da
            if (ctx->log.log_control_file_found && ctx->log.gf_log_syslog) {
Packit Service e080da
                ret = gf_log_syslog(ctx, domain, file, function, line, level,
Packit Service e080da
                                    errnum, msgid, appmsgstr, callstr, graph_id,
Packit Service e080da
                                    fmt);
Packit Service e080da
                break;
Packit Service e080da
            }
Packit Service e080da
            /* NOTE: If syslog control file is absent, which is another
Packit Service e080da
             * way to control logging to syslog, then we will fall through
Packit Service e080da
             * to the gluster log. The ideal way to do things would be to
Packit Service e080da
             * not have the extra control file check */
Packit Service e080da
        case gf_logger_glusterlog:
Packit Service e080da
            ret = gf_log_glusterlog(ctx, domain, file, function, line, level,
Packit Service e080da
                                    errnum, msgid, appmsgstr, callstr, tv,
Packit Service e080da
                                    graph_id, fmt);
Packit Service e080da
            break;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_flush_message(log_buf_t *buf, glusterfs_ctx_t *ctx)
Packit Service e080da
{
Packit Service e080da
    if (buf->refcount == 1) {
Packit Service e080da
        (void)gf_log_print_plain_fmt(ctx, buf->domain, buf->file, buf->function,
Packit Service e080da
                                     buf->line, buf->level, buf->errnum,
Packit Service e080da
                                     buf->msg_id, &buf->msg, NULL, buf->latest,
Packit Service e080da
                                     buf->graph_id, gf_logformat_withmsgid);
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    if (buf->refcount > 1) {
Packit Service e080da
        gf_log_print_with_repetitions(
Packit Service e080da
            ctx, buf->domain, buf->file, buf->function, buf->line, buf->level,
Packit Service e080da
            buf->errnum, buf->msg_id, &buf->msg, NULL, buf->refcount,
Packit Service e080da
            buf->oldest, buf->latest, buf->graph_id);
Packit Service e080da
    }
Packit Service e080da
    return;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
static void
Packit Service e080da
gf_log_flush_list(struct list_head *copy, glusterfs_ctx_t *ctx)
Packit Service e080da
{
Packit Service e080da
    log_buf_t *iter = NULL;
Packit Service e080da
    log_buf_t *tmp = NULL;
Packit Service e080da
Packit Service e080da
    list_for_each_entry_safe(iter, tmp, copy, msg_list)
Packit Service e080da
    {
Packit Service e080da
        gf_log_flush_message(iter, ctx);
Packit Service e080da
        list_del_init(&iter->msg_list);
Packit Service e080da
        log_buf_destroy(iter);
Packit Service e080da
    }
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_flush_msgs(glusterfs_ctx_t *ctx)
Packit Service e080da
{
Packit Service e080da
    struct list_head copy;
Packit Service e080da
Packit Service e080da
    INIT_LIST_HEAD(©);
Packit Service e080da
Packit Service e080da
    pthread_mutex_lock(&ctx->log.log_buf_lock);
Packit Service e080da
    {
Packit Service e080da
        list_splice_init(&ctx->log.lru_queue, ©);
Packit Service e080da
        ctx->log.lru_cur_size = 0;
Packit Service e080da
    }
Packit Service e080da
    pthread_mutex_unlock(&ctx->log.log_buf_lock);
Packit Service e080da
Packit Service e080da
    gf_log_flush_list(&copy, ctx);
Packit Service e080da
Packit Service e080da
    return;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
static void
Packit Service e080da
gf_log_flush_extra_msgs(glusterfs_ctx_t *ctx, uint32_t new)
Packit Service e080da
{
Packit Service e080da
    int count = 0;
Packit Service e080da
    int i = 0;
Packit Service e080da
    log_buf_t *iter = NULL;
Packit Service e080da
    log_buf_t *tmp = NULL;
Packit Service e080da
    struct list_head copy;
Packit Service e080da
Packit Service e080da
    INIT_LIST_HEAD(©);
Packit Service e080da
Packit Service e080da
    /* If the number of outstanding log messages does not cause list
Packit Service e080da
     * overflow even after reducing the size of the list, then do nothing.
Packit Service e080da
     * Otherwise (that is if there are more items in the list than there
Packit Service e080da
     * need to be after reducing its size), move the least recently used
Packit Service e080da
     * 'diff' elements to be flushed into a separate list...
Packit Service e080da
     */
Packit Service e080da
Packit Service e080da
    pthread_mutex_lock(&ctx->log.log_buf_lock);
Packit Service e080da
    {
Packit Service e080da
        if (ctx->log.lru_cur_size <= new)
Packit Service e080da
            goto unlock;
Packit Service e080da
        count = ctx->log.lru_cur_size - new;
Packit Service e080da
        list_for_each_entry_safe(iter, tmp, &ctx->log.lru_queue, msg_list)
Packit Service e080da
        {
Packit Service e080da
            if (i == count)
Packit Service e080da
                break;
Packit Service e080da
Packit Service e080da
            list_del_init(&iter->msg_list);
Packit Service e080da
            list_add_tail(&iter->msg_list, ©);
Packit Service e080da
            i++;
Packit Service e080da
        }
Packit Service e080da
        ctx->log.lru_cur_size = ctx->log.lru_cur_size - count;
Packit Service e080da
    }
Packit Service e080da
    // ... quickly unlock ...
Packit Service e080da
unlock:
Packit Service e080da
    pthread_mutex_unlock(&ctx->log.log_buf_lock);
Packit Service e080da
    if (list_empty(&copy))
Packit Service e080da
        return;
Packit Service e080da
Packit Service e080da
    TEST_LOG(
Packit Service e080da
        "Log buffer size reduced. About to flush %d extra log "
Packit Service e080da
        "messages",
Packit Service e080da
        count);
Packit Service e080da
    // ... and then flush them outside the lock.
Packit Service e080da
    gf_log_flush_list(&copy, ctx);
Packit Service e080da
    TEST_LOG("Just flushed %d extra log messages", count);
Packit Service e080da
Packit Service e080da
    return;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
static int
Packit Service e080da
__gf_log_inject_timer_event(glusterfs_ctx_t *ctx)
Packit Service e080da
{
Packit Service e080da
    int ret = -1;
Packit Service e080da
    struct timespec timeout = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
Packit Service e080da
    if (!ctx)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    if (ctx->log.log_flush_timer) {
Packit Service e080da
        gf_timer_call_cancel(ctx, ctx->log.log_flush_timer);
Packit Service e080da
        ctx->log.log_flush_timer = NULL;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    timeout.tv_sec = ctx->log.timeout;
Packit Service e080da
    timeout.tv_nsec = 0;
Packit Service e080da
Packit Service e080da
    TEST_LOG("Starting timer now. Timeout = %u, current buf size = %d",
Packit Service e080da
             ctx->log.timeout, ctx->log.lru_size);
Packit Service e080da
    ctx->log.log_flush_timer = gf_timer_call_after(
Packit Service e080da
        ctx, timeout, gf_log_flush_timeout_cbk, (void *)ctx);
Packit Service e080da
    if (!ctx->log.log_flush_timer)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    ret = 0;
Packit Service e080da
Packit Service e080da
out:
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
gf_log_inject_timer_event(glusterfs_ctx_t *ctx)
Packit Service e080da
{
Packit Service e080da
    int ret = -1;
Packit Service e080da
Packit Service e080da
    if (!ctx)
Packit Service e080da
        return -1;
Packit Service e080da
Packit Service e080da
    pthread_mutex_lock(&ctx->log.log_buf_lock);
Packit Service e080da
    {
Packit Service e080da
        ret = __gf_log_inject_timer_event(ctx);
Packit Service e080da
    }
Packit Service e080da
    pthread_mutex_unlock(&ctx->log.log_buf_lock);
Packit Service e080da
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
void
Packit Service e080da
gf_log_flush_timeout_cbk(void *data)
Packit Service e080da
{
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    ctx = (glusterfs_ctx_t *)data;
Packit Service e080da
Packit Service e080da
    TEST_LOG(
Packit Service e080da
        "Log timer timed out. About to flush outstanding messages if "
Packit Service e080da
        "present");
Packit Service e080da
    gf_log_flush_msgs(ctx);
Packit Service e080da
Packit Service e080da
    (void)gf_log_inject_timer_event(ctx);
Packit Service e080da
Packit Service e080da
    return;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
static int
Packit Service e080da
_gf_msg_internal(const char *domain, const char *file, const char *function,
Packit Service e080da
                 int32_t line, gf_loglevel_t level, int errnum, uint64_t msgid,
Packit Service e080da
                 char **appmsgstr, char *callstr, int graph_id)
Packit Service e080da
{
Packit Service e080da
    int ret = -1;
Packit Service e080da
    uint32_t size = 0;
Packit Service e080da
    const char *basename = NULL;
Packit Service e080da
    xlator_t *this = NULL;
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
    log_buf_t *iter = NULL;
Packit Service e080da
    log_buf_t *buf_tmp = NULL;
Packit Service e080da
    log_buf_t *buf_new = NULL;
Packit Service e080da
    log_buf_t *first = NULL;
Packit Service e080da
    struct timeval tv = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
    gf_boolean_t found = _gf_false;
Packit Service e080da
    gf_boolean_t flush_lru = _gf_false;
Packit Service e080da
    gf_boolean_t flush_logged_msg = _gf_false;
Packit Service e080da
Packit Service e080da
    this = THIS;
Packit Service e080da
    ctx = this->ctx;
Packit Service e080da
Packit Service e080da
    if (!ctx)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    GET_FILE_NAME_TO_LOG(file, basename);
Packit Service e080da
Packit Service e080da
    ret = gettimeofday(&tv, NULL);
Packit Service e080da
    if (ret)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    /* If this function is called via _gf_msg_callingfn () (indicated by a
Packit Service e080da
     * non-NULL callstr), or if the logformat is traditional, flush the
Packit Service e080da
     * message directly to disk.
Packit Service e080da
     */
Packit Service e080da
Packit Service e080da
    if ((callstr) || (ctx->log.logformat == gf_logformat_traditional)) {
Packit Service e080da
        ret = gf_log_print_plain_fmt(ctx, domain, basename, function, line,
Packit Service e080da
                                     level, errnum, msgid, appmsgstr, callstr,
Packit Service e080da
                                     tv, graph_id, gf_logformat_traditional);
Packit Service e080da
        goto out;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    pthread_mutex_lock(&ctx->log.log_buf_lock);
Packit Service e080da
    {
Packit Service e080da
        /* Check if the msg being logged is already part of the list */
Packit Service e080da
        list_for_each_entry_safe_reverse(iter, buf_tmp, &ctx->log.lru_queue,
Packit Service e080da
                                         msg_list)
Packit Service e080da
        {
Packit Service e080da
            if (first == NULL)
Packit Service e080da
                // Remember the first (lru) element in first ptr
Packit Service e080da
                first = iter;
Packit Service e080da
Packit Service e080da
            /* Try to fail the search early on by doing the less
Packit Service e080da
             * expensive integer comparisons and continue to string
Packit Service e080da
             * parameter comparisons only after all int parameters
Packit Service e080da
             * are found to be matching.
Packit Service e080da
             */
Packit Service e080da
            if (line != iter->line)
Packit Service e080da
                continue;
Packit Service e080da
Packit Service e080da
            if (errnum != iter->errnum)
Packit Service e080da
                continue;
Packit Service e080da
Packit Service e080da
            if (msgid != iter->msg_id)
Packit Service e080da
                continue;
Packit Service e080da
Packit Service e080da
            if (level != iter->level)
Packit Service e080da
                continue;
Packit Service e080da
Packit Service e080da
            if (graph_id != iter->graph_id)
Packit Service e080da
                continue;
Packit Service e080da
Packit Service e080da
            if (strcmp(domain, iter->domain))
Packit Service e080da
                continue;
Packit Service e080da
Packit Service e080da
            if (strcmp(basename, iter->file))
Packit Service e080da
                continue;
Packit Service e080da
Packit Service e080da
            if (strcmp(function, iter->function))
Packit Service e080da
                continue;
Packit Service e080da
Packit Service e080da
            if (strcmp(*appmsgstr, iter->msg))
Packit Service e080da
                continue;
Packit Service e080da
Packit Service e080da
            // Ah! Found a match!
Packit Service e080da
            list_move_tail(&iter->msg_list, &ctx->log.lru_queue);
Packit Service e080da
            iter->refcount++;
Packit Service e080da
            found = _gf_true;
Packit Service e080da
            // Update the 'latest' timestamp.
Packit Service e080da
            memcpy((void *)&(iter->latest), (void *)&tv,
Packit Service e080da
                   sizeof(struct timeval));
Packit Service e080da
            break;
Packit Service e080da
        }
Packit Service e080da
        if (found) {
Packit Service e080da
            ret = 0;
Packit Service e080da
            goto unlock;
Packit Service e080da
        }
Packit Service e080da
        // else ...
Packit Service e080da
Packit Service e080da
        size = ctx->log.lru_size;
Packit Service e080da
        /* If the upper limit on the log buf size is 0, flush the msg to
Packit Service e080da
         * disk directly after unlock. There's no need to buffer the
Packit Service e080da
         * msg here.
Packit Service e080da
         */
Packit Service e080da
        if (size == 0) {
Packit Service e080da
            flush_logged_msg = _gf_true;
Packit Service e080da
            goto unlock;
Packit Service e080da
        } else if ((ctx->log.lru_cur_size + 1) > size) {
Packit Service e080da
            /* If the list is full, flush the lru msg to disk and also
Packit Service e080da
             * release it after unlock, and ...
Packit Service e080da
             * */
Packit Service e080da
            if (first->refcount >= 1)
Packit Service e080da
                TEST_LOG(
Packit Service e080da
                    "Buffer overflow of a buffer whose size limit "
Packit Service e080da
                    "is %d. About to flush least recently used log"
Packit Service e080da
                    " message to disk",
Packit Service e080da
                    size);
Packit Service e080da
            list_del_init(&first->msg_list);
Packit Service e080da
            ctx->log.lru_cur_size--;
Packit Service e080da
            flush_lru = _gf_true;
Packit Service e080da
        }
Packit Service e080da
        /* create a new list element, initialise and enqueue it.
Packit Service e080da
         * Additionally, this being the first occurrence of the msg,
Packit Service e080da
         * log it directly to disk after unlock. */
Packit Service e080da
        buf_new = log_buf_new();
Packit Service e080da
        if (!buf_new) {
Packit Service e080da
            ret = -1;
Packit Service e080da
            goto unlock;
Packit Service e080da
        }
Packit Service e080da
        ret = log_buf_init(buf_new, domain, basename, function, line, level,
Packit Service e080da
                           errnum, msgid, appmsgstr, graph_id);
Packit Service e080da
        if (ret) {
Packit Service e080da
            log_buf_destroy(buf_new);
Packit Service e080da
            goto unlock;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        memcpy((void *)&(buf_new->latest), (void *)&tv, sizeof(struct timeval));
Packit Service e080da
        memcpy((void *)&(buf_new->oldest), (void *)&tv, sizeof(struct timeval));
Packit Service e080da
Packit Service e080da
        list_add_tail(&buf_new->msg_list, &ctx->log.lru_queue);
Packit Service e080da
        ctx->log.lru_cur_size++;
Packit Service e080da
        flush_logged_msg = _gf_true;
Packit Service e080da
        ret = 0;
Packit Service e080da
    }
Packit Service e080da
unlock:
Packit Service e080da
    pthread_mutex_unlock(&ctx->log.log_buf_lock);
Packit Service e080da
Packit Service e080da
    /* Value of @ret is a don't-care below since irrespective of success or
Packit Service e080da
     * failure post setting of @flush_lru, @first must be flushed and freed.
Packit Service e080da
     */
Packit Service e080da
    if (flush_lru) {
Packit Service e080da
        gf_log_flush_message(first, ctx);
Packit Service e080da
        log_buf_destroy(first);
Packit Service e080da
    }
Packit Service e080da
    /* Similarly, irrespective of whether all operations since setting of
Packit Service e080da
     * @flush_logged_msg were successful or not, flush the message being
Packit Service e080da
     * logged to disk in the plain format.
Packit Service e080da
     */
Packit Service e080da
    if (flush_logged_msg) {
Packit Service e080da
        ret = gf_log_print_plain_fmt(ctx, domain, basename, function, line,
Packit Service e080da
                                     level, errnum, msgid, appmsgstr, callstr,
Packit Service e080da
                                     tv, graph_id, gf_logformat_withmsgid);
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
out:
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
_gf_msg(const char *domain, const char *file, const char *function,
Packit Service e080da
        int32_t line, gf_loglevel_t level, int errnum, int trace,
Packit Service e080da
        uint64_t msgid, const char *fmt, ...)
Packit Service e080da
{
Packit Service e080da
    int ret = 0;
Packit Service e080da
    char *msgstr = NULL;
Packit Service e080da
    va_list ap;
Packit Service e080da
    xlator_t *this = NULL;
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
    char callstr[GF_LOG_BACKTRACE_SIZE] = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
    int passcallstr = 0;
Packit Service e080da
    int log_inited = 0;
Packit Service e080da
Packit Service e080da
    /* in args check */
Packit Service e080da
    if (!domain || !file || !function || !fmt) {
Packit Service e080da
        fprintf(stderr, "logging: %s:%s():%d: invalid argument\n", __FILE__,
Packit Service e080da
                __PRETTY_FUNCTION__, __LINE__);
Packit Service e080da
        return -1;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    this = THIS;
Packit Service e080da
Packit Service e080da
    if (this == NULL)
Packit Service e080da
        return -1;
Packit Service e080da
Packit Service e080da
    ctx = this->ctx;
Packit Service e080da
    if (ctx == NULL) {
Packit Service e080da
        /* messages before context initialization are ignored */
Packit Service e080da
        return -1;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    /* check if we should be logging */
Packit Service e080da
    if (skip_logging(this, level))
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    if (trace) {
Packit Service e080da
        ret = _gf_msg_backtrace(GF_LOG_BACKTRACE_DEPTH, callstr,
Packit Service e080da
                                GF_LOG_BACKTRACE_SIZE);
Packit Service e080da
        if (ret >= 0)
Packit Service e080da
            passcallstr = 1;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    pthread_mutex_lock(&ctx->log.logfile_mutex);
Packit Service e080da
    {
Packit Service e080da
        if (ctx->log.logfile) {
Packit Service e080da
            log_inited = 1;
Packit Service e080da
        }
Packit Service e080da
    }
Packit Service e080da
    pthread_mutex_unlock(&ctx->log.logfile_mutex);
Packit Service e080da
Packit Service e080da
    /* form the message */
Packit Service e080da
    va_start(ap, fmt);
Packit Service e080da
    ret = vasprintf(&msgstr, fmt, ap);
Packit Service e080da
    va_end(ap);
Packit Service e080da
Packit Service e080da
    /* log */
Packit Service e080da
    if (ret != -1) {
Packit Service e080da
        if (!log_inited && ctx->log.gf_log_syslog) {
Packit Service e080da
            ret = gf_log_syslog(
Packit Service e080da
                ctx, domain, file, function, line, level, errnum, msgid,
Packit Service e080da
                &msgstr, (passcallstr ? callstr : NULL),
Packit Service e080da
                (this->graph) ? this->graph->id : 0, gf_logformat_traditional);
Packit Service e080da
        } else {
Packit Service e080da
            ret = _gf_msg_internal(domain, file, function, line, level, errnum,
Packit Service e080da
                                   msgid, &msgstr,
Packit Service e080da
                                   (passcallstr ? callstr : NULL),
Packit Service e080da
                                   (this->graph) ? this->graph->id : 0);
Packit Service e080da
        }
Packit Service e080da
    } else {
Packit Service e080da
        /* man (3) vasprintf states on error strp contents
Packit Service e080da
         * are undefined, be safe */
Packit Service e080da
        msgstr = NULL;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    FREE(msgstr);
Packit Service e080da
Packit Service e080da
out:
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
/* TODO: Deprecate (delete) _gf_log, _gf_log_callingfn,
Packit Service e080da
 * once messages are changed to use _gf_msgXXX APIs for logging */
Packit Service e080da
int
Packit Service e080da
_gf_log(const char *domain, const char *file, const char *function, int line,
Packit Service e080da
        gf_loglevel_t level, const char *fmt, ...)
Packit Service e080da
{
Packit Service e080da
    const char *basename = NULL;
Packit Service e080da
    FILE *new_logfile = NULL;
Packit Service e080da
    va_list ap;
Packit Service e080da
    char timestr[GF_LOG_TIMESTR_SIZE] = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
    struct timeval tv = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
    char *logline = NULL;
Packit Service e080da
    char *msg = NULL;
Packit Service e080da
    int ret = 0;
Packit Service e080da
    int fd = -1;
Packit Service e080da
    xlator_t *this = NULL;
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    this = THIS;
Packit Service e080da
    ctx = this->ctx;
Packit Service e080da
Packit Service e080da
    if (!ctx)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    if (skip_logging(this, level))
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    static char *level_strings[] = {"",  /* NONE */
Packit Service e080da
                                    "M", /* EMERGENCY */
Packit Service e080da
                                    "A", /* ALERT */
Packit Service e080da
                                    "C", /* CRITICAL */
Packit Service e080da
                                    "E", /* ERROR */
Packit Service e080da
                                    "W", /* WARNING */
Packit Service e080da
                                    "N", /* NOTICE */
Packit Service e080da
                                    "I", /* INFO */
Packit Service e080da
                                    "D", /* DEBUG */
Packit Service e080da
                                    "T", /* TRACE */
Packit Service e080da
                                    ""};
Packit Service e080da
Packit Service e080da
    if (!domain || !file || !function || !fmt) {
Packit Service e080da
        fprintf(stderr, "logging: %s:%s():%d: invalid argument\n", __FILE__,
Packit Service e080da
                __PRETTY_FUNCTION__, __LINE__);
Packit Service e080da
        return -1;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    basename = strrchr(file, '/');
Packit Service e080da
    if (basename)
Packit Service e080da
        basename++;
Packit Service e080da
    else
Packit Service e080da
        basename = file;
Packit Service e080da
Packit Service e080da
    va_start(ap, fmt);
Packit Service e080da
    ret = vasprintf(&msg, fmt, ap);
Packit Service e080da
    va_end(ap);
Packit Service e080da
    if (-1 == ret) {
Packit Service e080da
        goto err;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    if (ctx->log.log_control_file_found) {
Packit Service e080da
        int priority;
Packit Service e080da
        /* treat GF_LOG_TRACE and GF_LOG_NONE as LOG_DEBUG and
Packit Service e080da
           other level as is */
Packit Service e080da
        if (GF_LOG_TRACE == level || GF_LOG_NONE == level) {
Packit Service e080da
            priority = LOG_DEBUG;
Packit Service e080da
        } else {
Packit Service e080da
            priority = level - 1;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        gf_syslog(priority, "[%s:%d:%s] %d-%s: %s", basename, line, function,
Packit Service e080da
                  ((this->graph) ? this->graph->id : 0), domain, msg);
Packit Service e080da
        goto err;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    if (ctx->log.logrotate) {
Packit Service e080da
        ctx->log.logrotate = 0;
Packit Service e080da
Packit Service e080da
        fd = sys_open(ctx->log.filename, O_CREAT | O_RDONLY, S_IRUSR | S_IWUSR);
Packit Service e080da
        if (fd < 0) {
Packit Service e080da
            gf_msg("logrotate", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED,
Packit Service e080da
                   "failed to open logfile");
Packit Service e080da
            return -1;
Packit Service e080da
        }
Packit Service e080da
        sys_close(fd);
Packit Service e080da
Packit Service e080da
        new_logfile = fopen(ctx->log.filename, "a");
Packit Service e080da
        if (!new_logfile) {
Packit Service e080da
            gf_msg("logrotate", GF_LOG_CRITICAL, errno, LG_MSG_FILE_OP_FAILED,
Packit Service e080da
                   "failed to open logfile %s", ctx->log.filename);
Packit Service e080da
            goto log;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        pthread_mutex_lock(&ctx->log.logfile_mutex);
Packit Service e080da
        {
Packit Service e080da
            if (ctx->log.logfile)
Packit Service e080da
                fclose(ctx->log.logfile);
Packit Service e080da
Packit Service e080da
            ctx->log.gf_log_logfile = ctx->log.logfile = new_logfile;
Packit Service e080da
        }
Packit Service e080da
        pthread_mutex_unlock(&ctx->log.logfile_mutex);
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
log:
Packit Service e080da
    ret = gettimeofday(&tv, NULL);
Packit Service e080da
    if (-1 == ret)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    gf_time_fmt(timestr, sizeof timestr, tv.tv_sec, gf_timefmt_FT);
Packit Service e080da
    snprintf(timestr + strlen(timestr), sizeof timestr - strlen(timestr),
Packit Service e080da
             ".%" GF_PRI_SUSECONDS, tv.tv_usec);
Packit Service e080da
Packit Service e080da
    ret = gf_asprintf(&logline, "[%s] %s [%s:%d:%s] %d-%s: %s", timestr,
Packit Service e080da
                      level_strings[level], basename, line, function,
Packit Service e080da
                      ((this->graph) ? this->graph->id : 0), domain, msg);
Packit Service e080da
    if (-1 == ret) {
Packit Service e080da
        goto err;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    pthread_mutex_lock(&ctx->log.logfile_mutex);
Packit Service e080da
    {
Packit Service e080da
        if (ctx->log.logfile) {
Packit Service e080da
            fprintf(ctx->log.logfile, "%s\n", logline);
Packit Service e080da
            fflush(ctx->log.logfile);
Packit Service e080da
        } else if (ctx->log.loglevel >= level) {
Packit Service e080da
            fprintf(stderr, "%s\n", logline);
Packit Service e080da
            fflush(stderr);
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
#ifdef GF_LINUX_HOST_OS
Packit Service e080da
        /* We want only serious log in 'syslog', not our debug
Packit Service e080da
           and trace logs */
Packit Service e080da
        if (ctx->log.gf_log_syslog && level &&
Packit Service e080da
            (level <= ctx->log.sys_log_level))
Packit Service e080da
            syslog((level - 1), "%s\n", logline);
Packit Service e080da
#endif
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    pthread_mutex_unlock(&ctx->log.logfile_mutex);
Packit Service e080da
Packit Service e080da
err:
Packit Service e080da
    GF_FREE(logline);
Packit Service e080da
Packit Service e080da
    FREE(msg);
Packit Service e080da
Packit Service e080da
out:
Packit Service e080da
    return (0);
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
_gf_log_eh(const char *function, const char *fmt, ...)
Packit Service e080da
{
Packit Service e080da
    int ret = -1;
Packit Service e080da
    va_list ap;
Packit Service e080da
    char *logline = NULL;
Packit Service e080da
    char *msg = NULL;
Packit Service e080da
    xlator_t *this = NULL;
Packit Service e080da
Packit Service e080da
    this = THIS;
Packit Service e080da
Packit Service e080da
    va_start(ap, fmt);
Packit Service e080da
    ret = vasprintf(&msg, fmt, ap);
Packit Service e080da
    va_end(ap);
Packit Service e080da
    if (-1 == ret) {
Packit Service e080da
        goto out;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    ret = gf_asprintf(&logline, "[%d] %s: %s",
Packit Service e080da
                      ((this->graph) ? this->graph->id : 0), function, msg);
Packit Service e080da
    if (-1 == ret) {
Packit Service e080da
        goto out;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    ret = eh_save_history(this->history, logline);
Packit Service e080da
Packit Service e080da
out:
Packit Service e080da
    GF_FREE(logline);
Packit Service e080da
Packit Service e080da
    FREE(msg);
Packit Service e080da
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
gf_cmd_log_init(const char *filename)
Packit Service e080da
{
Packit Service e080da
    int fd = -1;
Packit Service e080da
    xlator_t *this = NULL;
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    this = THIS;
Packit Service e080da
    ctx = this->ctx;
Packit Service e080da
Packit Service e080da
    if (!ctx)
Packit Service e080da
        return -1;
Packit Service e080da
Packit Service e080da
    if (!filename) {
Packit Service e080da
        gf_msg(this->name, GF_LOG_CRITICAL, 0, LG_MSG_INVALID_ENTRY,
Packit Service e080da
               "gf_cmd_log_init: no filename specified\n");
Packit Service e080da
        return -1;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    ctx->log.cmd_log_filename = gf_strdup(filename);
Packit Service e080da
    if (!ctx->log.cmd_log_filename) {
Packit Service e080da
        return -1;
Packit Service e080da
    }
Packit Service e080da
    /* close and reopen cmdlogfile for log rotate*/
Packit Service e080da
    if (ctx->log.cmdlogfile) {
Packit Service e080da
        fclose(ctx->log.cmdlogfile);
Packit Service e080da
        ctx->log.cmdlogfile = NULL;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    fd = sys_open(ctx->log.cmd_log_filename, O_CREAT | O_WRONLY | O_APPEND,
Packit Service e080da
                  S_IRUSR | S_IWUSR);
Packit Service e080da
    if (fd < 0) {
Packit Service e080da
        gf_msg(this->name, GF_LOG_CRITICAL, errno, LG_MSG_FILE_OP_FAILED,
Packit Service e080da
               "failed to open cmd_log_file");
Packit Service e080da
        return -1;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    ctx->log.cmdlogfile = fdopen(fd, "a");
Packit Service e080da
    if (!ctx->log.cmdlogfile) {
Packit Service e080da
        gf_msg(this->name, GF_LOG_CRITICAL, errno, LG_MSG_FILE_OP_FAILED,
Packit Service e080da
               "gf_cmd_log_init: failed to open logfile \"%s\" "
Packit Service e080da
               "\n",
Packit Service e080da
               ctx->log.cmd_log_filename);
Packit Service e080da
        sys_close(fd);
Packit Service e080da
        return -1;
Packit Service e080da
    }
Packit Service e080da
    return 0;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
gf_cmd_log(const char *domain, const char *fmt, ...)
Packit Service e080da
{
Packit Service e080da
    va_list ap;
Packit Service e080da
    char timestr[64];
Packit Service e080da
    struct timeval tv = {
Packit Service e080da
        0,
Packit Service e080da
    };
Packit Service e080da
    char *logline = NULL;
Packit Service e080da
    char *msg = NULL;
Packit Service e080da
    int ret = 0;
Packit Service e080da
    int fd = -1;
Packit Service e080da
    glusterfs_ctx_t *ctx = NULL;
Packit Service e080da
Packit Service e080da
    ctx = THIS->ctx;
Packit Service e080da
Packit Service e080da
    if (!ctx)
Packit Service e080da
        return -1;
Packit Service e080da
Packit Service e080da
    if (!ctx->log.cmdlogfile)
Packit Service e080da
        return -1;
Packit Service e080da
Packit Service e080da
    if (!domain || !fmt) {
Packit Service e080da
        gf_msg_trace("glusterd", 0, "logging: invalid argument\n");
Packit Service e080da
        return -1;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    ret = gettimeofday(&tv, NULL);
Packit Service e080da
    if (ret == -1)
Packit Service e080da
        goto out;
Packit Service e080da
    va_start(ap, fmt);
Packit Service e080da
    ret = vasprintf(&msg, fmt, ap);
Packit Service e080da
    va_end(ap);
Packit Service e080da
    if (ret == -1) {
Packit Service e080da
        goto out;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    gf_time_fmt(timestr, sizeof timestr, tv.tv_sec, gf_timefmt_FT);
Packit Service e080da
    snprintf(timestr + strlen(timestr), GF_LOG_TIMESTR_SIZE - strlen(timestr),
Packit Service e080da
             ".%" GF_PRI_SUSECONDS, tv.tv_usec);
Packit Service e080da
Packit Service e080da
    ret = gf_asprintf(&logline, "[%s] %s : %s", timestr, domain, msg);
Packit Service e080da
    if (ret == -1) {
Packit Service e080da
        goto out;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    /* close and reopen cmdlogfile fd for in case of log rotate*/
Packit Service e080da
    if (ctx->log.cmd_history_logrotate) {
Packit Service e080da
        ctx->log.cmd_history_logrotate = 0;
Packit Service e080da
Packit Service e080da
        if (ctx->log.cmdlogfile) {
Packit Service e080da
            fclose(ctx->log.cmdlogfile);
Packit Service e080da
            ctx->log.cmdlogfile = NULL;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        fd = sys_open(ctx->log.cmd_log_filename, O_CREAT | O_WRONLY | O_APPEND,
Packit Service e080da
                      S_IRUSR | S_IWUSR);
Packit Service e080da
        if (fd < 0) {
Packit Service e080da
            gf_msg(THIS->name, GF_LOG_CRITICAL, errno, LG_MSG_FILE_OP_FAILED,
Packit Service e080da
                   "failed to open "
Packit Service e080da
                   "logfile \"%s\" \n",
Packit Service e080da
                   ctx->log.cmd_log_filename);
Packit Service e080da
            ret = -1;
Packit Service e080da
            goto out;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        ctx->log.cmdlogfile = fdopen(fd, "a");
Packit Service e080da
        if (!ctx->log.cmdlogfile) {
Packit Service e080da
            gf_msg(THIS->name, GF_LOG_CRITICAL, errno, LG_MSG_FILE_OP_FAILED,
Packit Service e080da
                   "failed to open logfile \"%s\""
Packit Service e080da
                   " \n",
Packit Service e080da
                   ctx->log.cmd_log_filename);
Packit Service e080da
            ret = -1;
Packit Service e080da
            sys_close(fd);
Packit Service e080da
            goto out;
Packit Service e080da
        }
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    fprintf(ctx->log.cmdlogfile, "%s\n", logline);
Packit Service e080da
    fflush(ctx->log.cmdlogfile);
Packit Service e080da
Packit Service e080da
out:
Packit Service e080da
    GF_FREE(logline);
Packit Service e080da
Packit Service e080da
    FREE(msg);
Packit Service e080da
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
static int
Packit Service e080da
_do_slog_format(const char *event, va_list inp, char **msg)
Packit Service e080da
{
Packit Service e080da
    va_list valist_tmp;
Packit Service e080da
    int i = 0;
Packit Service e080da
    int j = 0;
Packit Service e080da
    int k = 0;
Packit Service e080da
    int ret = 0;
Packit Service e080da
    char *fmt = NULL;
Packit Service e080da
    char *buffer = NULL;
Packit Service e080da
    int num_format_chars = 0;
Packit Service e080da
    char format_char = '%';
Packit Service e080da
    char *tmp1 = NULL;
Packit Service e080da
    char *tmp2 = NULL;
Packit Service e080da
Packit Service e080da
    ret = gf_asprintf(&tmp2, "%s", event);
Packit Service e080da
    if (ret == -1)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    /* Hardcoded value for max key value pairs, exits early */
Packit Service e080da
    /* from loop if found NULL */
Packit Service e080da
    for (i = 0; i < GF_MAX_SLOG_PAIR_COUNT; i++) {
Packit Service e080da
        fmt = va_arg(inp, char *);
Packit Service e080da
        if (fmt == NULL) {
Packit Service e080da
            break;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        /* Get number of times % is used in input for formatting, */
Packit Service e080da
        /* this count will be used to skip those many args from the */
Packit Service e080da
        /* main list and will be used to format inner format */
Packit Service e080da
        num_format_chars = 0;
Packit Service e080da
        for (k = 0; fmt[k] != '\0'; k++) {
Packit Service e080da
            /* If %% is used then that is escaped */
Packit Service e080da
            if (fmt[k] == format_char && fmt[k + 1] == format_char) {
Packit Service e080da
                k++;
Packit Service e080da
            } else if (fmt[k] == format_char) {
Packit Service e080da
                num_format_chars++;
Packit Service e080da
            }
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        tmp1 = gf_strdup(tmp2);
Packit Service e080da
        if (!tmp1) {
Packit Service e080da
            ret = -1;
Packit Service e080da
            goto out;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        GF_FREE(tmp2);
Packit Service e080da
        tmp2 = NULL;
Packit Service e080da
Packit Service e080da
        if (num_format_chars > 0) {
Packit Service e080da
            /* Make separate valist and format the string */
Packit Service e080da
            va_copy(valist_tmp, inp);
Packit Service e080da
            ret = gf_vasprintf(&buffer, fmt, valist_tmp);
Packit Service e080da
            if (ret < 0) {
Packit Service e080da
                va_end(valist_tmp);
Packit Service e080da
                goto out;
Packit Service e080da
            }
Packit Service e080da
            va_end(valist_tmp);
Packit Service e080da
Packit Service e080da
            for (j = 0; j < num_format_chars; j++) {
Packit Service e080da
                /* Skip the va_arg value since these values
Packit Service e080da
                   are already used for internal formatting */
Packit Service e080da
                (void)va_arg(inp, void *);
Packit Service e080da
            }
Packit Service e080da
Packit Service e080da
            ret = gf_asprintf(&tmp2, "%s\t%s", tmp1, buffer);
Packit Service e080da
            if (ret < 0)
Packit Service e080da
                goto out;
Packit Service e080da
Packit Service e080da
            GF_FREE(buffer);
Packit Service e080da
            buffer = NULL;
Packit Service e080da
        } else {
Packit Service e080da
            ret = gf_asprintf(&tmp2, "%s\t%s", tmp1, fmt);
Packit Service e080da
            if (ret < 0)
Packit Service e080da
                goto out;
Packit Service e080da
        }
Packit Service e080da
Packit Service e080da
        GF_FREE(tmp1);
Packit Service e080da
        tmp1 = NULL;
Packit Service e080da
    }
Packit Service e080da
Packit Service e080da
    *msg = gf_strdup(tmp2);
Packit Service e080da
    if (!*msg)
Packit Service e080da
        ret = -1;
Packit Service e080da
Packit Service e080da
out:
Packit Service e080da
    if (buffer)
Packit Service e080da
        GF_FREE(buffer);
Packit Service e080da
Packit Service e080da
    if (tmp1)
Packit Service e080da
        GF_FREE(tmp1);
Packit Service e080da
Packit Service e080da
    if (tmp2)
Packit Service e080da
        GF_FREE(tmp2);
Packit Service e080da
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
_gf_smsg(const char *domain, const char *file, const char *function,
Packit Service e080da
         int32_t line, gf_loglevel_t level, int errnum, int trace,
Packit Service e080da
         uint64_t msgid, const char *event, ...)
Packit Service e080da
{
Packit Service e080da
    va_list valist;
Packit Service e080da
    char *msg = NULL;
Packit Service e080da
    int ret = 0;
Packit Service e080da
Packit Service e080da
    va_start(valist, event);
Packit Service e080da
    ret = _do_slog_format(event, valist, &msg;;
Packit Service e080da
    if (ret == -1)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    ret = _gf_msg(domain, file, function, line, level, errnum, trace, msgid,
Packit Service e080da
                  "%s", msg);
Packit Service e080da
Packit Service e080da
out:
Packit Service e080da
    va_end(valist);
Packit Service e080da
    if (msg)
Packit Service e080da
        GF_FREE(msg);
Packit Service e080da
    return ret;
Packit Service e080da
}
Packit Service e080da
Packit Service e080da
int
Packit Service e080da
_gf_slog(const char *domain, const char *file, const char *function, int line,
Packit Service e080da
         gf_loglevel_t level, const char *event, ...)
Packit Service e080da
{
Packit Service e080da
    va_list valist;
Packit Service e080da
    char *msg = NULL;
Packit Service e080da
    int ret = 0;
Packit Service e080da
Packit Service e080da
    va_start(valist, event);
Packit Service e080da
    ret = _do_slog_format(event, valist, &msg;;
Packit Service e080da
    if (ret == -1)
Packit Service e080da
        goto out;
Packit Service e080da
Packit Service e080da
    ret = _gf_log(domain, file, function, line, level, "%s", msg);
Packit Service e080da
Packit Service e080da
out:
Packit Service e080da
    va_end(valist);
Packit Service e080da
    if (msg)
Packit Service e080da
        GF_FREE(msg);
Packit Service e080da
    return ret;
Packit Service e080da
}