#include "virconf.h"
#include "memory.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "rpc/virnetserver.h"
#include "configmake.h"
#include "remote/remote_protocol.h"
# include <rpc/xdr.h>
# include "remote_protocol.h"
# include "qemu_protocol.h"
-# include "logging.h"
+# include "virlog.h"
# include "threads.h"
# if HAVE_SASL
# include "virnetsaslcontext.h"
#include "libvirt_internal.h"
#include "datatypes.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "util.h"
#include "stream.h"
#include "uuid.h"
#include "stream.h"
#include "remote.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virnetserverclient.h"
#include "virterror_internal.h"
# These files are not related to driver APIs. Simply generic
# helper APIs for various purposes
UTIL_SOURCES = \
- util/logging.c util/logging.h \
util/memory.c util/memory.h \
util/pci.c util/pci.h \
util/processinfo.c util/processinfo.h \
util/virnodesuspend.c util/virnodesuspend.h \
util/viriptables.c util/viriptables.h \
util/virjson.c util/virjson.h \
+ util/virlog.c util/virlog.h \
util/virobject.c util/virobject.h \
util/virpidfile.c util/virpidfile.h \
util/virprocess.c util/virprocess.h \
#include "domain_audit.h"
#include "viraudit.h"
#include "uuid.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
/* Return nn:mm in hex for block and character devices, and NULL
#include "uuid.h"
#include "util.h"
#include "virbuffer.h"
-#include "logging.h"
+#include "virlog.h"
#include "nwfilter_conf.h"
#include "storage_file.h"
#include "virfile.h"
#include <config.h>
#include "domain_event.h"
-#include "logging.h"
+#include "virlog.h"
#include "datatypes.h"
#include "memory.h"
#include "virterror_internal.h"
#include "datatypes.h"
#include "nwfilter_params.h"
#include "domain_conf.h"
-#include "logging.h"
+#include "virlog.h"
#define VIR_FROM_THIS VIR_FROM_NWFILTER
#include "internal.h"
#include "virbuffer.h"
#include "datatypes.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "secret_conf.h"
#include "virterror_internal.h"
#include "count-one-bits.h"
#include "datatypes.h"
#include "domain_conf.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "netdev_bandwidth_conf.h"
#include "netdev_vport_profile_conf.h"
#include "threads.h"
#include "memory.h"
#include "virpidfile.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "virfile.h"
#include <config.h>
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "xml.h"
#include "cpu.h"
#include <config.h>
#include <stdint.h>
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "util.h"
#include "cpu.h"
#include <stdint.h>
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "util.h"
#include "cpu.h"
#include "datatypes.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "uuid.h"
#include "util.h"
#include "driver.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "util.h"
#include "configmake.h"
#include "internal.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "esx_private.h"
#include "esx_device_monitor.h"
#include "virauth.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "vmx.h"
#include "virtypedparam.h"
#include "internal.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "interface_conf.h"
#include "virsocketaddr.h"
#include "internal.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "network_conf.h"
#include "esx_private.h"
#include "internal.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "esx_private.h"
#include "esx_nwfilter_driver.h"
#include "internal.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "esx_private.h"
#include "esx_secret_driver.h"
#include "md5.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "storage_conf.h"
#include "storage_file.h"
#include "md5.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "storage_conf.h"
#include "storage_file.h"
#include "datatypes.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "vmx.h"
#include "esx_private.h"
#include "virbuffer.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "util.h"
#include "uuid.h"
#include "vmx.h"
#include "virbuffer.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "esx_vi_methods.h"
#include "esx_util.h"
#include "virbuffer.h"
#include "datatypes.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "util.h"
#include "esx_vi.h"
#include "esx_vi_types.h"
#include "fdstream.h"
#include "virterror_internal.h"
#include "datatypes.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "util.h"
#include "virfile.h"
#include "datatypes.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "hyperv_device_monitor.h"
#include "virauth.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "hyperv_driver.h"
#include "hyperv_interface_driver.h"
#include "datatypes.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "hyperv_interface_driver.h"
#include "datatypes.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "hyperv_network_driver.h"
#include "datatypes.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "hyperv_nwfilter_driver.h"
#include "datatypes.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "hyperv_secret_driver.h"
#include "datatypes.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "hyperv_storage_driver.h"
#include "datatypes.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "hyperv_private.h"
#include "hyperv_util.h"
#include "internal.h"
#include "virterror_internal.h"
#include "datatypes.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "util.h"
#include "uuid.h"
#include "interface_driver.h"
#include "interface_conf.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#define VIR_FROM_THIS VIR_FROM_INTERFACE
#include <config.h>
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "datatypes.h"
#include "libvirt/libvirt-qemu.h"
#endif
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "datatypes.h"
#include "driver.h"
#include <sys/socket.h>
#include "internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "datatypes.h"
#include "virfile.h"
#include <fcntl.h>
#include "internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "virconf.h"
#include "datatypes.h"
#include "memory.h"
#include "uuid.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#define VIR_FROM_THIS VIR_FROM_LOCKING
#include "virpidfile.h"
#include "virprocess.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "virconf.h"
#include "rpc/virnetserver.h"
#include "virconf.h"
#include "memory.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "rpc/virnetserver.h"
#include "configmake.h"
#include "rpc/virnetserver.h"
#include "rpc/virnetserverclient.h"
#include "util.h"
-#include "logging.h"
+#include "virlog.h"
#include "lock_daemon.h"
#include "lock_protocol.h"
#include "lock_driver.h"
#include "virconf.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "util.h"
#include "virfile.h"
#include "lock_driver_nop.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "dirname.h"
#include "lock_driver.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "memory.h"
#include "util.h"
#include "lock_manager.h"
#include "lock_driver_nop.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "util.h"
#include "memory.h"
#include "uuid.h"
#include "lxc_container.h"
#include "virfile.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "vircgroup.h"
#include "virterror_internal.h"
#include "virconf.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "configmake.h"
#include "lxc_container.h"
#endif
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "lxc_container.h"
#include "util.h"
#include "memory.h"
#endif
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "util.h"
#include "lxc_conf.h"
#include "lxc_domain.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#define VIR_FROM_THIS VIR_FROM_LXC
#include <wait.h>
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "datatypes.h"
#include "lxc_cgroup.h"
#include "lxc_conf.h"
#include "lxc_fuse.h"
#include "lxc_cgroup.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#include "virbuffer.h"
#include <config.h>
#include "lxc_hostdev.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "memory.h"
#include "memory.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "threads.h"
#include "rpc/virnetclient.h"
#include "memory.h"
#include "domain_audit.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "vircommand.h"
#include "lxc_hostdev.h"
#include "virhook.h"
#include "memory.h"
#include "uuid.h"
#include "viriptables.h"
-#include "logging.h"
+#include "virlog.h"
#include "virdnsmasq.h"
#include "configmake.h"
#include "virnetdev.h"
#include "virterror_internal.h"
#include "datatypes.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "node_device_conf.h"
#include "node_device_hal.h"
#include "node_device_driver.h"
#include "memory.h"
#include "uuid.h"
#include "pci.h"
-#include "logging.h"
+#include "virlog.h"
#include "node_device_driver.h"
#include "virdbus.h"
#include "node_device_hal.h"
#include "virterror_internal.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#define VIR_FROM_THIS VIR_FROM_NODEDEV
#include "node_device_driver.h"
#include "driver.h"
#include "datatypes.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "uuid.h"
#include "util.h"
#include "nodeinfo.h"
#include "physmem.h"
#include "util.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "count-one-bits.h"
#include "intprops.h"
#include <net/if.h>
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "datatypes.h"
#include "virterror_internal.h"
#include "conf/domain_conf.h"
#include <config.h>
#include "virdbus.h"
-#include "logging.h"
+#include "virlog.h"
#include "internal.h"
#include "virbuffer.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "domain_conf.h"
#include "nwfilter_conf.h"
#include "internal.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "domain_conf.h"
#include "virterror_internal.h"
#include "nwfilter_gentech_driver.h"
#include "intprops.h"
#include "virbuffer.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "datatypes.h"
#include "virnetdev.h"
#include "virterror_internal.h"
#include "memory.h"
#include "virfile.h"
#include "virtypedparam.h"
-#include "logging.h"
+#include "virlog.h"
#include "vircommand.h"
#include "viruri.h"
#include "stats_linux.h"
#include "virterror_internal.h"
#include "memory.h"
#include "util.h"
-#include "logging.h"
+#include "virlog.h"
#include "vircommand.h"
#include "configmake.h"
#include "storage_file.h"
#include "datatypes.h"
#include "virbuffer.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "driver.h"
#include "libvirt/libvirt.h"
#include "virterror_internal.h"
#include "qemu_agent.h"
#include "qemu_command.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "virjson.h"
#include "virfile.h"
#include "qemu_driver.h"
#include "util.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "qemu_bridge_filter.h"
#include "qemu_capabilities.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "util.h"
#include "virfile.h"
#include "qemu_domain.h"
#include "qemu_process.h"
#include "vircgroup.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "virterror_internal.h"
#include "util.h"
#include "qemu_bridge_filter.h"
#include "cpu/cpu.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "util.h"
#include "virarch.h"
#include "datatypes.h"
#include "xml.h"
#include "nodeinfo.h"
-#include "logging.h"
+#include "virlog.h"
#include "cpu/cpu.h"
#include "domain_nwfilter.h"
#include "virfile.h"
#include "qemu_capabilities.h"
#include "qemu_migration.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "c-ctype.h"
#include "cpu/cpu.h"
#include "qemu_migration.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "datatypes.h"
#include "virbuffer.h"
#include "util.h"
#include <config.h>
#include "qemu_hostdev.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "memory.h"
#include "pci.h"
#include "qemu_hostdev.h"
#include "domain_audit.h"
#include "domain_nwfilter.h"
-#include "logging.h"
+#include "virlog.h"
#include "datatypes.h"
#include "virterror_internal.h"
#include "memory.h"
#include "qemu_cgroup.h"
#include "domain_audit.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "memory.h"
#include "util.h"
#include "qemu_monitor_json.h"
#include "virterror_internal.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#include "virprocess.h"
#include "virobject.h"
#include "qemu_command.h"
#include "qemu_capabilities.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "driver.h"
#include "datatypes.h"
#include "virterror_internal.h"
#include "c-ctype.h"
#include "c-strcasestr.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "driver.h"
#include "datatypes.h"
#include "virterror_internal.h"
#endif
#include "datatypes.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "memory.h"
#include "virhook.h"
#include "virnetclientprogram.h"
#include "virnetclientstream.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "datatypes.h"
#include "domain_event.h"
#include "driver.h"
#include "memory.h"
#include "threads.h"
#include "virfile.h"
-#include "logging.h"
+#include "virlog.h"
#include "util.h"
#include "virterror_internal.h"
#include "virnetsocket.h"
#include "memory.h"
#include "threads.h"
#include "virfile.h"
-#include "logging.h"
+#include "virlog.h"
#include "util.h"
#include "virterror_internal.h"
#include "memory.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "util.h"
#include "virfile.h"
#include "threads.h"
#include "virnetclient.h"
#include "memory.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "threads.h"
#define VIR_FROM_THIS VIR_FROM_RPC
#include "virnetmessage.h"
#include "memory.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#include "util.h"
#include "virterror_internal.h"
#include "memory.h"
#include "threads.h"
-#include "logging.h"
+#include "virlog.h"
#define VIR_FROM_THIS VIR_FROM_RPC
#include <fcntl.h>
#include "virnetserver.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "virterror_internal.h"
#include "threads.h"
#include "virnetserverclient.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "memory.h"
#include "threads.h"
#include "vireventpoll.h"
#include "memory.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#define VIR_FROM_THIS VIR_FROM_RPC
#include "memory.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#include "threads.h"
#include "util.h"
#include "memory.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#include "threads.h"
#include "virprocess.h"
#include "internal.h"
#include "virbuffer.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "configmake.h"
#include "threads.h"
#include "util.h"
#include "memory.h"
#include "virterror_internal.h"
#include "util.h"
-#include "logging.h"
+#include "virlog.h"
#include "threads.h"
#include "configmake.h"
#include "base64.h"
#include "datatypes.h"
#include "driver.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "secret_conf.h"
#include "secret_driver.h"
#include "virfile.h"
#include "configmake.h"
#include "vircommand.h"
-#include "logging.h"
+#include "virlog.h"
#define VIR_FROM_THIS VIR_FROM_SECURITY
#define SECURITY_APPARMOR_VOID_DOI "0"
#include "virterror_internal.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "pci.h"
#include "virusb.h"
#include "storage_file.h"
#include <string.h>
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "security_driver.h"
#ifdef WITH_SECDRIVER_SELINUX
#include "security_dac.h"
#include "virterror_internal.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#define VIR_FROM_THIS VIR_FROM_SECURITY
#include "virterror_internal.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "pci.h"
#include "virusb.h"
#include "storage_file.h"
#include "uuid.h"
#include "storage_file.h"
#include "storage_backend.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#include "stat-time.h"
#include <stdio.h>
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "storage_backend_disk.h"
#include "util.h"
#include "memory.h"
#include "memory.h"
#include "xml.h"
#include "virfile.h"
-#include "logging.h"
+#include "virlog.h"
#define VIR_FROM_THIS VIR_FROM_STORAGE
#include "storage_backend_iscsi.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#include "vircommand.h"
#include "virrandom.h"
#include "storage_conf.h"
#include "vircommand.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#define VIR_FROM_THIS VIR_FROM_STORAGE
#include "storage_conf.h"
#include "storage_backend.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#define VIR_FROM_THIS VIR_FROM_STORAGE
#include "storage_conf.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "base64.h"
#include "uuid.h"
#include "rados/librados.h"
#include "virterror_internal.h"
#include "storage_backend_scsi.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#include "vircommand.h"
#include "vircommand.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#define VIR_FROM_THIS VIR_FROM_STORAGE
#include "storage_conf.h"
#include "memory.h"
#include "storage_backend.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#include "fdstream.h"
#include "configmake.h"
#include "node_device_conf.h"
#include "xml.h"
#include "threads.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#include "virtypedparam.h"
#include "virrandom.h"
#include "util.h"
#include "memory.h"
#include "nodeinfo.h"
-#include "logging.h"
+#include "virlog.h"
#include "domain_nwfilter.h"
#include "virfile.h"
#include "vircommand.h"
#include "domain_conf.h"
#include "domain_audit.h"
#include "datatypes.h"
-#include "logging.h"
+#include "virlog.h"
#include "domain_nwfilter.h"
#include "virfile.h"
#include "fdstream.h"
+++ /dev/null
-/*
- * logging.c: internal logging and debugging
- *
- * Copyright (C) 2008, 2010-2012 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <signal.h>
-#include <execinfo.h>
-#if HAVE_SYSLOG_H
-# include <syslog.h>
-#endif
-#include <sys/socket.h>
-#if HAVE_SYS_UN_H
-# include <sys/un.h>
-#endif
-
-#include "virterror_internal.h"
-#include "logging.h"
-#include "memory.h"
-#include "util.h"
-#include "virbuffer.h"
-#include "threads.h"
-#include "virfile.h"
-#include "virtime.h"
-#include "intprops.h"
-
-/* Journald output is only supported on Linux new enough to expose
- * htole64. */
-#if HAVE_SYSLOG_H && defined(__linux__) && HAVE_DECL_HTOLE64
-# define USE_JOURNALD 1
-#endif
-
-#define VIR_FROM_THIS VIR_FROM_NONE
-
-VIR_ENUM_DECL(virLogSource)
-VIR_ENUM_IMPL(virLogSource, VIR_LOG_FROM_LAST,
- "file",
- "error",
- "audit",
- "trace",
- "library");
-
-/*
- * A logging buffer to keep some history over logs
- */
-
-static int virLogSize = 64 * 1024;
-static char *virLogBuffer = NULL;
-static int virLogLen = 0;
-static int virLogStart = 0;
-static int virLogEnd = 0;
-
-/*
- * Filters are used to refine the rules on what to keep or drop
- * based on a matching pattern (currently a substring)
- */
-struct _virLogFilter {
- const char *match;
- virLogPriority priority;
- unsigned int flags;
-};
-typedef struct _virLogFilter virLogFilter;
-typedef virLogFilter *virLogFilterPtr;
-
-static virLogFilterPtr virLogFilters = NULL;
-static int virLogNbFilters = 0;
-
-/*
- * Outputs are used to emit the messages retained
- * after filtering, multiple output can be used simultaneously
- */
-struct _virLogOutput {
- bool logVersion;
- void *data;
- virLogOutputFunc f;
- virLogCloseFunc c;
- virLogPriority priority;
- virLogDestination dest;
- const char *name;
-};
-typedef struct _virLogOutput virLogOutput;
-typedef virLogOutput *virLogOutputPtr;
-
-static virLogOutputPtr virLogOutputs = NULL;
-static int virLogNbOutputs = 0;
-
-/*
- * Default priorities
- */
-static virLogPriority virLogDefaultPriority = VIR_LOG_DEFAULT;
-
-static int virLogResetFilters(void);
-static int virLogResetOutputs(void);
-static void virLogOutputToFd(virLogSource src,
- virLogPriority priority,
- const char *filename,
- int linenr,
- const char *funcname,
- const char *timestamp,
- virLogMetadataPtr metadata,
- unsigned int flags,
- const char *rawstr,
- const char *str,
- void *data);
-
-/*
- * Logs accesses must be serialized though a mutex
- */
-virMutex virLogMutex;
-
-void
-virLogLock(void)
-{
- virMutexLock(&virLogMutex);
-}
-
-
-void
-virLogUnlock(void)
-{
- virMutexUnlock(&virLogMutex);
-}
-
-
-static const char *
-virLogOutputString(virLogDestination ldest)
-{
- switch (ldest) {
- case VIR_LOG_TO_STDERR:
- return "stderr";
- case VIR_LOG_TO_SYSLOG:
- return "syslog";
- case VIR_LOG_TO_FILE:
- return "file";
- case VIR_LOG_TO_JOURNALD:
- return "journald";
- }
- return "unknown";
-}
-
-
-static const char *
-virLogPriorityString(virLogPriority lvl)
-{
- switch (lvl) {
- case VIR_LOG_DEBUG:
- return "debug";
- case VIR_LOG_INFO:
- return "info";
- case VIR_LOG_WARN:
- return "warning";
- case VIR_LOG_ERROR:
- return "error";
- }
- return "unknown";
-}
-
-
-static int
-virLogOnceInit(void)
-{
- const char *pbm = NULL;
-
- if (virMutexInit(&virLogMutex) < 0)
- return -1;
-
- virLogLock();
- if (VIR_ALLOC_N(virLogBuffer, virLogSize + 1) < 0) {
- /*
- * The debug buffer is not a critical component, allow startup
- * even in case of failure to allocate it in case of a
- * configuration mistake.
- */
- virLogSize = 64 * 1024;
- if (VIR_ALLOC_N(virLogBuffer, virLogSize + 1) < 0) {
- pbm = "Failed to allocate debug buffer: deactivating debug log\n";
- virLogSize = 0;
- } else {
- pbm = "Failed to allocate debug buffer: reduced to 64 kB\n";
- }
- }
- virLogLen = 0;
- virLogStart = 0;
- virLogEnd = 0;
- virLogDefaultPriority = VIR_LOG_DEFAULT;
- virLogUnlock();
- if (pbm)
- VIR_WARN("%s", pbm);
- return 0;
-}
-
-VIR_ONCE_GLOBAL_INIT(virLog)
-
-
-/**
- * virLogSetBufferSize:
- * @size: size of the buffer in kilobytes or <= 0 to deactivate
- *
- * Dynamically set the size or deactivate the logging buffer used to keep
- * a trace of all recent debug output. Note that the content of the buffer
- * is lost if it gets reallocated.
- *
- * Return -1 in case of failure or 0 in case of success
- */
-int
-virLogSetBufferSize(int size)
-{
- int ret = 0;
- int oldsize;
- char *oldLogBuffer;
- const char *pbm = NULL;
-
- if (size < 0)
- size = 0;
-
- if (virLogInitialize() < 0)
- return -1;
-
- if (size * 1024 == virLogSize)
- return ret;
-
- virLogLock();
-
- oldsize = virLogSize;
- oldLogBuffer = virLogBuffer;
-
- if (INT_MAX / 1024 <= size) {
- pbm = "Requested log size of %d kB too large\n";
- ret = -1;
- goto error;
- }
-
- virLogSize = size * 1024;
- if (VIR_ALLOC_N(virLogBuffer, virLogSize + 1) < 0) {
- pbm = "Failed to allocate debug buffer of %d kB\n";
- virLogBuffer = oldLogBuffer;
- virLogSize = oldsize;
- ret = -1;
- goto error;
- }
- VIR_FREE(oldLogBuffer);
- virLogLen = 0;
- virLogStart = 0;
- virLogEnd = 0;
-
-error:
- virLogUnlock();
- if (pbm)
- VIR_ERROR(pbm, size);
- return ret;
-}
-
-
-/**
- * virLogReset:
- *
- * Reset the logging module to its default initial state
- *
- * Returns 0 if successful, and -1 in case or error
- */
-int
-virLogReset(void)
-{
- if (virLogInitialize() < 0)
- return -1;
-
- virLogLock();
- virLogResetFilters();
- virLogResetOutputs();
- virLogLen = 0;
- virLogStart = 0;
- virLogEnd = 0;
- virLogDefaultPriority = VIR_LOG_DEFAULT;
- virLogUnlock();
- return 0;
-}
-
-
-/*
- * Store a string in the ring buffer
- */
-static void
-virLogStr(const char *str)
-{
- int tmp;
- int len;
-
- if ((str == NULL) || (virLogBuffer == NULL) || (virLogSize <= 0))
- return;
- len = strlen(str);
- if (len >= virLogSize)
- return;
-
- /*
- * copy the data and reset the end, we cycle over the end of the buffer
- */
- if (virLogEnd + len >= virLogSize) {
- tmp = virLogSize - virLogEnd;
- memcpy(&virLogBuffer[virLogEnd], str, tmp);
- memcpy(&virLogBuffer[0], &str[tmp], len - tmp);
- virLogEnd = len - tmp;
- } else {
- memcpy(&virLogBuffer[virLogEnd], str, len);
- virLogEnd += len;
- }
- virLogBuffer[virLogEnd] = 0;
- /*
- * Update the log length, and if full move the start index
- */
- virLogLen += len;
- if (virLogLen > virLogSize) {
- tmp = virLogLen - virLogSize;
- virLogLen = virLogSize;
- virLogStart += tmp;
- if (virLogStart >= virLogSize)
- virLogStart -= virLogSize;
- }
-}
-
-
-static void
-virLogDumpAllFD(const char *msg, int len)
-{
- int i, found = 0;
-
- if (len <= 0)
- len = strlen(msg);
-
- for (i = 0; i < virLogNbOutputs;i++) {
- if (virLogOutputs[i].f == virLogOutputToFd) {
- int fd = (intptr_t) virLogOutputs[i].data;
-
- if (fd >= 0) {
- ignore_value(safewrite(fd, msg, len));
- found = 1;
- }
- }
- }
- if (!found)
- ignore_value(safewrite(STDERR_FILENO, msg, len));
-}
-
-
-/**
- * virLogEmergencyDumpAll:
- * @signum: the signal number
- *
- * Emergency function called, possibly from a signal handler.
- * It need to output the debug ring buffer through the log
- * output which are safe to use from a signal handler.
- * In case none is found it is emitted to standard error.
- */
-void
-virLogEmergencyDumpAll(int signum)
-{
- int len;
- int oldLogStart, oldLogLen;
-
- switch (signum) {
-#ifdef SIGFPE
- case SIGFPE:
- virLogDumpAllFD("Caught signal Floating-point exception", -1);
- break;
-#endif
-#ifdef SIGSEGV
- case SIGSEGV:
- virLogDumpAllFD("Caught Segmentation violation", -1);
- break;
-#endif
-#ifdef SIGILL
- case SIGILL:
- virLogDumpAllFD("Caught illegal instruction", -1);
- break;
-#endif
-#ifdef SIGABRT
- case SIGABRT:
- virLogDumpAllFD("Caught abort signal", -1);
- break;
-#endif
-#ifdef SIGBUS
- case SIGBUS:
- virLogDumpAllFD("Caught bus error", -1);
- break;
-#endif
-#ifdef SIGUSR2
- case SIGUSR2:
- virLogDumpAllFD("Caught User-defined signal 2", -1);
- break;
-#endif
- default:
- virLogDumpAllFD("Caught unexpected signal", -1);
- break;
- }
- if ((virLogBuffer == NULL) || (virLogSize <= 0)) {
- virLogDumpAllFD(" internal log buffer deactivated\n", -1);
- return;
- }
-
- virLogDumpAllFD(" dumping internal log buffer:\n", -1);
- virLogDumpAllFD("\n\n ====== start of log =====\n\n", -1);
-
- /*
- * Since we can't lock the buffer safely from a signal handler
- * we mark it as empty in case of concurrent access, and proceed
- * with the data, at worse we will output something a bit weird
- * if another thread start logging messages at the same time.
- * Note that virLogStr() uses virLogEnd for the computations and
- * writes to the buffer and only then updates virLogLen and virLogStart
- * so it's best to reset it first.
- */
- oldLogStart = virLogStart;
- oldLogLen = virLogLen;
- virLogEnd = 0;
- virLogLen = 0;
- virLogStart = 0;
-
- while (oldLogLen > 0) {
- if (oldLogStart + oldLogLen < virLogSize) {
- virLogBuffer[oldLogStart + oldLogLen] = 0;
- virLogDumpAllFD(&virLogBuffer[oldLogStart], oldLogLen);
- oldLogStart += oldLogLen;
- oldLogLen = 0;
- } else {
- len = virLogSize - oldLogStart;
- virLogBuffer[virLogSize] = 0;
- virLogDumpAllFD(&virLogBuffer[oldLogStart], len);
- oldLogLen -= len;
- oldLogStart = 0;
- }
- }
- virLogDumpAllFD("\n\n ====== end of log =====\n\n", -1);
-}
-
-
-/**
- * virLogSetDefaultPriority:
- * @priority: the default priority level
- *
- * Set the default priority level, i.e. any logged data of a priority
- * equal or superior to this level will be logged, unless a specific rule
- * was defined for the log category of the message.
- *
- * Returns 0 if successful, -1 in case of error.
- */
-int
-virLogSetDefaultPriority(virLogPriority priority)
-{
- if ((priority < VIR_LOG_DEBUG) || (priority > VIR_LOG_ERROR)) {
- VIR_WARN("Ignoring invalid log level setting.");
- return -1;
- }
- if (virLogInitialize() < 0)
- return -1;
-
- virLogDefaultPriority = priority;
- return 0;
-}
-
-
-/**
- * virLogResetFilters:
- *
- * Removes the set of logging filters defined.
- *
- * Returns the number of filters removed
- */
-static int
-virLogResetFilters(void)
-{
- int i;
-
- for (i = 0; i < virLogNbFilters;i++)
- VIR_FREE(virLogFilters[i].match);
- VIR_FREE(virLogFilters);
- virLogNbFilters = 0;
- return i;
-}
-
-
-/**
- * virLogDefineFilter:
- * @match: the pattern to match
- * @priority: the priority to give to messages matching the pattern
- * @flags: extra flags, see virLogFilterFlags enum
- *
- * Defines a pattern used for log filtering, it allow to select or
- * reject messages independently of the default priority.
- * The filter defines a rules that will apply only to messages matching
- * the pattern (currently if @match is a substring of the message category)
- *
- * Returns -1 in case of failure or the filter number if successful
- */
-int
-virLogDefineFilter(const char *match,
- virLogPriority priority,
- unsigned int flags)
-{
- int i;
- char *mdup = NULL;
-
- virCheckFlags(VIR_LOG_STACK_TRACE, -1);
-
- if ((match == NULL) || (priority < VIR_LOG_DEBUG) ||
- (priority > VIR_LOG_ERROR))
- return -1;
-
- virLogLock();
- for (i = 0;i < virLogNbFilters;i++) {
- if (STREQ(virLogFilters[i].match, match)) {
- virLogFilters[i].priority = priority;
- goto cleanup;
- }
- }
-
- mdup = strdup(match);
- if (mdup == NULL) {
- i = -1;
- goto cleanup;
- }
- i = virLogNbFilters;
- if (VIR_REALLOC_N(virLogFilters, virLogNbFilters + 1)) {
- i = -1;
- VIR_FREE(mdup);
- goto cleanup;
- }
- virLogFilters[i].match = mdup;
- virLogFilters[i].priority = priority;
- virLogFilters[i].flags = flags;
- virLogNbFilters++;
-cleanup:
- virLogUnlock();
- return i;
-}
-
-
-/**
- * virLogFiltersCheck:
- * @input: the input string
- *
- * Check the input of the message against the existing filters. Currently
- * the match is just a substring check of the category used as the input
- * string, a more subtle approach could be used instead
- *
- * Returns 0 if not matched or the new priority if found.
- */
-static int
-virLogFiltersCheck(const char *input,
- unsigned int *flags)
-{
- int ret = 0;
- int i;
-
- virLogLock();
- for (i = 0;i < virLogNbFilters;i++) {
- if (strstr(input, virLogFilters[i].match)) {
- ret = virLogFilters[i].priority;
- *flags = virLogFilters[i].flags;
- break;
- }
- }
- virLogUnlock();
- return ret;
-}
-
-
-/**
- * virLogResetOutputs:
- *
- * Removes the set of logging output defined.
- *
- * Returns the number of output removed
- */
-static int
-virLogResetOutputs(void)
-{
- int i;
-
- for (i = 0;i < virLogNbOutputs;i++) {
- if (virLogOutputs[i].c != NULL)
- virLogOutputs[i].c(virLogOutputs[i].data);
- VIR_FREE(virLogOutputs[i].name);
- }
- VIR_FREE(virLogOutputs);
- i = virLogNbOutputs;
- virLogNbOutputs = 0;
- return i;
-}
-
-
-/**
- * virLogDefineOutput:
- * @f: the function to call to output a message
- * @c: the function to call to close the output (or NULL)
- * @data: extra data passed as first arg to the function
- * @priority: minimal priority for this filter, use 0 for none
- * @dest: where to send output of this priority
- * @name: optional name data associated with an output
- * @flags: extra flag, currently unused
- *
- * Defines an output function for log messages. Each message once
- * gone though filtering is emitted through each registered output.
- *
- * Returns -1 in case of failure or the output number if successful
- */
-int
-virLogDefineOutput(virLogOutputFunc f,
- virLogCloseFunc c,
- void *data,
- virLogPriority priority,
- virLogDestination dest,
- const char *name,
- unsigned int flags)
-{
- int ret = -1;
- char *ndup = NULL;
-
- virCheckFlags(0, -1);
-
- if (f == NULL)
- return -1;
-
- if (dest == VIR_LOG_TO_SYSLOG || dest == VIR_LOG_TO_FILE) {
- if (name == NULL)
- return -1;
- ndup = strdup(name);
- if (ndup == NULL)
- return -1;
- }
-
- virLogLock();
- if (VIR_REALLOC_N(virLogOutputs, virLogNbOutputs + 1)) {
- VIR_FREE(ndup);
- goto cleanup;
- }
- ret = virLogNbOutputs++;
- virLogOutputs[ret].logVersion = true;
- virLogOutputs[ret].f = f;
- virLogOutputs[ret].c = c;
- virLogOutputs[ret].data = data;
- virLogOutputs[ret].priority = priority;
- virLogOutputs[ret].dest = dest;
- virLogOutputs[ret].name = ndup;
-cleanup:
- virLogUnlock();
- return ret;
-}
-
-
-static int
-virLogFormatString(char **msg,
- int linenr,
- const char *funcname,
- virLogPriority priority,
- const char *str)
-{
- int ret;
-
- /*
- * Be careful when changing the following log message formatting, we rely
- * on it when stripping libvirt debug messages from qemu log files. So when
- * changing this, you might also need to change the code there.
- * virLogFormatString() function name is mentioned there so it's sufficient
- * to just grep for it to find the right place.
- */
- if ((funcname != NULL)) {
- ret = virAsprintf(msg, "%d: %s : %s:%d : %s\n",
- virThreadSelfID(), virLogPriorityString(priority),
- funcname, linenr, str);
- } else {
- ret = virAsprintf(msg, "%d: %s : %s\n",
- virThreadSelfID(), virLogPriorityString(priority),
- str);
- }
- return ret;
-}
-
-
-static int
-virLogVersionString(const char **rawmsg,
- char **msg)
-{
-#ifdef PACKAGER_VERSION
-# ifdef PACKAGER
-# define LOG_VERSION_STRING \
- "libvirt version: " VERSION ", package: " PACKAGER_VERSION " (" PACKAGER ")"
-# else
-# define LOG_VERSION_STRING \
- "libvirt version: " VERSION ", package: " PACKAGER_VERSION
-# endif
-#else
-# define LOG_VERSION_STRING \
- "libvirt version: " VERSION
-#endif
-
- *rawmsg = LOG_VERSION_STRING;
- return virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, LOG_VERSION_STRING);
-}
-
-
-/**
- * virLogMessage:
- * @source: where is that message coming from
- * @priority: the priority level
- * @filename: file where the message was emitted
- * @linenr: line where the message was emitted
- * @funcname: the function emitting the (debug) message
- * @metadata: NULL or metadata array, terminated by an item with NULL key
- * @fmt: the string format
- * @...: the arguments
- *
- * Call the libvirt logger with some information. Based on the configuration
- * the message may be stored, sent to output or just discarded
- */
-void
-virLogMessage(virLogSource source,
- virLogPriority priority,
- const char *filename,
- int linenr,
- const char *funcname,
- virLogMetadataPtr metadata,
- const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- virLogVMessage(source, priority,
- filename, linenr, funcname,
- metadata, fmt, ap);
- va_end(ap);
-}
-
-
-/**
- * virLogVMessage:
- * @source: where is that message coming from
- * @priority: the priority level
- * @filename: file where the message was emitted
- * @linenr: line where the message was emitted
- * @funcname: the function emitting the (debug) message
- * @metadata: NULL or metadata array, terminated by an item with NULL key
- * @fmt: the string format
- * @vargs: format args
- *
- * Call the libvirt logger with some information. Based on the configuration
- * the message may be stored, sent to output or just discarded
- */
-void
-virLogVMessage(virLogSource source,
- virLogPriority priority,
- const char *filename,
- int linenr,
- const char *funcname,
- virLogMetadataPtr metadata,
- const char *fmt,
- va_list vargs)
-{
- static bool logVersionStderr = true;
- char *str = NULL;
- char *msg = NULL;
- char timestamp[VIR_TIME_STRING_BUFLEN];
- int fprio, i, ret;
- int saved_errno = errno;
- int emit = 1;
- unsigned int filterflags = 0;
-
- if (virLogInitialize() < 0)
- return;
-
- if (fmt == NULL)
- goto cleanup;
-
- /*
- * check against list of specific logging patterns
- */
- fprio = virLogFiltersCheck(filename, &filterflags);
- if (fprio == 0) {
- if (priority < virLogDefaultPriority)
- emit = 0;
- } else if (priority < fprio) {
- emit = 0;
- }
-
- if ((emit == 0) && ((virLogBuffer == NULL) || (virLogSize <= 0)))
- goto cleanup;
-
- /*
- * serialize the error message, add level and timestamp
- */
- if (virVasprintf(&str, fmt, vargs) < 0) {
- goto cleanup;
- }
-
- ret = virLogFormatString(&msg, linenr, funcname, priority, str);
- if (ret < 0)
- goto cleanup;
-
- if (virTimeStringNowRaw(timestamp) < 0)
- timestamp[0] = '\0';
-
- /*
- * Log based on defaults, first store in the history buffer,
- * then if emit push the message on the outputs defined, if none
- * use stderr.
- * NOTE: the locking is a single point of contention for multiple
- * threads, but avoid intermixing. Maybe set up locks per output
- * to improve paralellism.
- */
- virLogLock();
- virLogStr(timestamp);
- virLogStr(msg);
- virLogUnlock();
- if (emit == 0)
- goto cleanup;
-
- virLogLock();
- for (i = 0; i < virLogNbOutputs; i++) {
- if (priority >= virLogOutputs[i].priority) {
- if (virLogOutputs[i].logVersion) {
- const char *rawver;
- char *ver = NULL;
- if (virLogVersionString(&rawver, &ver) >= 0)
- virLogOutputs[i].f(VIR_LOG_FROM_FILE, VIR_LOG_INFO,
- __FILE__, __LINE__, __func__,
- timestamp, NULL, 0, rawver, ver,
- virLogOutputs[i].data);
- VIR_FREE(ver);
- virLogOutputs[i].logVersion = false;
- }
- virLogOutputs[i].f(source, priority,
- filename, linenr, funcname,
- timestamp, metadata, filterflags,
- str, msg, virLogOutputs[i].data);
- }
- }
- if ((virLogNbOutputs == 0) && (source != VIR_LOG_FROM_ERROR)) {
- if (logVersionStderr) {
- const char *rawver;
- char *ver = NULL;
- if (virLogVersionString(&rawver, &ver) >= 0)
- virLogOutputToFd(VIR_LOG_FROM_FILE, VIR_LOG_INFO,
- __FILE__, __LINE__, __func__,
- timestamp, NULL, 0, rawver, ver,
- (void *) STDERR_FILENO);
- VIR_FREE(ver);
- logVersionStderr = false;
- }
- virLogOutputToFd(source, priority,
- filename, linenr, funcname,
- timestamp, metadata, filterflags,
- str, msg, (void *) STDERR_FILENO);
- }
- virLogUnlock();
-
-cleanup:
- VIR_FREE(str);
- VIR_FREE(msg);
- errno = saved_errno;
-}
-
-
-static void
-virLogStackTraceToFd(int fd)
-{
- void *array[100];
- int size;
- static bool doneWarning = false;
- const char *msg = "Stack trace not available on this platform\n";
-
-#define STRIP_DEPTH 3
- size = backtrace(array, ARRAY_CARDINALITY(array));
- if (size) {
- backtrace_symbols_fd(array + STRIP_DEPTH, size - STRIP_DEPTH, fd);
- ignore_value(safewrite(fd, "\n", 1));
- } else if (!doneWarning) {
- ignore_value(safewrite(fd, msg, strlen(msg)));
- doneWarning = true;
- }
-#undef STRIP_DEPTH
-}
-
-static void
-virLogOutputToFd(virLogSource source ATTRIBUTE_UNUSED,
- virLogPriority priority ATTRIBUTE_UNUSED,
- const char *filename ATTRIBUTE_UNUSED,
- int linenr ATTRIBUTE_UNUSED,
- const char *funcname ATTRIBUTE_UNUSED,
- const char *timestamp,
- virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
- unsigned int flags,
- const char *rawstr ATTRIBUTE_UNUSED,
- const char *str,
- void *data)
-{
- int fd = (intptr_t) data;
- char *msg;
-
- if (fd < 0)
- return;
-
- if (virAsprintf(&msg, "%s: %s", timestamp, str) < 0)
- return;
-
- ignore_value(safewrite(fd, msg, strlen(msg)));
- VIR_FREE(msg);
-
- if (flags & VIR_LOG_STACK_TRACE)
- virLogStackTraceToFd(fd);
-}
-
-
-static void
-virLogCloseFd(void *data)
-{
- int fd = (intptr_t) data;
-
- VIR_LOG_CLOSE(fd);
-}
-
-
-static int
-virLogAddOutputToStderr(virLogPriority priority)
-{
- if (virLogDefineOutput(virLogOutputToFd, NULL, (void *)2L, priority,
- VIR_LOG_TO_STDERR, NULL, 0) < 0)
- return -1;
- return 0;
-}
-
-
-static int
-virLogAddOutputToFile(virLogPriority priority,
- const char *file)
-{
- int fd;
-
- fd = open(file, O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR);
- if (fd < 0)
- return -1;
- if (virLogDefineOutput(virLogOutputToFd, virLogCloseFd,
- (void *)(intptr_t)fd,
- priority, VIR_LOG_TO_FILE, file, 0) < 0) {
- VIR_FORCE_CLOSE(fd);
- return -1;
- }
- return 0;
-}
-
-
-#if HAVE_SYSLOG_H
-static int
-virLogPrioritySyslog(virLogPriority priority)
-{
- switch (priority) {
- case VIR_LOG_DEBUG:
- return LOG_DEBUG;
- case VIR_LOG_INFO:
- return LOG_INFO;
- case VIR_LOG_WARN:
- return LOG_WARNING;
- case VIR_LOG_ERROR:
- return LOG_ERR;
- default:
- return LOG_ERR;
- }
-}
-
-
-static void
-virLogOutputToSyslog(virLogSource source ATTRIBUTE_UNUSED,
- virLogPriority priority,
- const char *filename ATTRIBUTE_UNUSED,
- int linenr ATTRIBUTE_UNUSED,
- const char *funcname ATTRIBUTE_UNUSED,
- const char *timestamp ATTRIBUTE_UNUSED,
- virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
- unsigned int flags,
- const char *rawstr ATTRIBUTE_UNUSED,
- const char *str,
- void *data ATTRIBUTE_UNUSED)
-{
- virCheckFlags(VIR_LOG_STACK_TRACE,);
-
- syslog(virLogPrioritySyslog(priority), "%s", str);
-}
-
-static char *current_ident = NULL;
-
-
-static void
-virLogCloseSyslog(void *data ATTRIBUTE_UNUSED)
-{
- closelog();
- VIR_FREE(current_ident);
-}
-
-
-static int
-virLogAddOutputToSyslog(virLogPriority priority,
- const char *ident)
-{
- /*
- * ident needs to be kept around on Solaris
- */
- VIR_FREE(current_ident);
- current_ident = strdup(ident);
- if (current_ident == NULL)
- return -1;
-
- openlog(current_ident, 0, 0);
- if (virLogDefineOutput(virLogOutputToSyslog, virLogCloseSyslog, NULL,
- priority, VIR_LOG_TO_SYSLOG, ident, 0) < 0) {
- closelog();
- VIR_FREE(current_ident);
- return -1;
- }
- return 0;
-}
-
-
-# if USE_JOURNALD
-# define IOVEC_SET(iov, data, size) \
- do { \
- struct iovec *_i = &(iov); \
- _i->iov_base = (void*)(data); \
- _i->iov_len = (size); \
- } while (0)
-
-# define IOVEC_SET_STRING(iov, str) IOVEC_SET(iov, str, strlen(str))
-
-/* Used for conversion of numbers to strings, and for length of binary data */
-# define JOURNAL_BUF_SIZE (MAX(INT_BUFSIZE_BOUND(int), sizeof(uint64_t)))
-
-struct journalState
-{
- struct iovec *iov, *iov_end;
- char (*bufs)[JOURNAL_BUF_SIZE], (*bufs_end)[JOURNAL_BUF_SIZE];
-};
-
-static void
-journalAddString(struct journalState *state, const char *field,
- const char *value)
-{
- static const char newline = '\n', equals = '=';
-
- if (strchr(value, '\n') != NULL) {
- uint64_t nstr;
-
- /* If 'str' contains a newline, then we must
- * encode the string length, since we can't
- * rely on the newline for the field separator
- */
- if (state->iov_end - state->iov < 5 || state->bufs == state->bufs_end)
- return; /* Silently drop */
- nstr = htole64(strlen(value));
- memcpy(state->bufs[0], &nstr, sizeof(nstr));
-
- IOVEC_SET_STRING(state->iov[0], field);
- IOVEC_SET(state->iov[1], &newline, sizeof(newline));
- IOVEC_SET(state->iov[2], state->bufs[0], sizeof(nstr));
- state->bufs++;
- state->iov += 3;
- } else {
- if (state->iov_end - state->iov < 4)
- return; /* Silently drop */
- IOVEC_SET_STRING(state->iov[0], field);
- IOVEC_SET(state->iov[1], (void *)&equals, sizeof(equals));
- state->iov += 2;
- }
- IOVEC_SET_STRING(state->iov[0], value);
- IOVEC_SET(state->iov[1], (void *)&newline, sizeof(newline));
- state->iov += 2;
-}
-
-static void
-journalAddInt(struct journalState *state, const char *field, int value)
-{
- static const char newline = '\n', equals = '=';
-
- char *num;
-
- if (state->iov_end - state->iov < 4 || state->bufs == state->bufs_end)
- return; /* Silently drop */
-
- num = virFormatIntDecimal(state->bufs[0], sizeof(state->bufs[0]), value);
-
- IOVEC_SET_STRING(state->iov[0], field);
- IOVEC_SET(state->iov[1], (void *)&equals, sizeof(equals));
- IOVEC_SET_STRING(state->iov[2], num);
- IOVEC_SET(state->iov[3], (void *)&newline, sizeof(newline));
- state->bufs++;
- state->iov += 4;
-}
-
-static int journalfd = -1;
-
-static void
-virLogOutputToJournald(virLogSource source,
- virLogPriority priority,
- const char *filename,
- int linenr,
- const char *funcname,
- const char *timestamp ATTRIBUTE_UNUSED,
- virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
- unsigned int flags,
- const char *rawstr,
- const char *str ATTRIBUTE_UNUSED,
- void *data ATTRIBUTE_UNUSED)
-{
- virCheckFlags(VIR_LOG_STACK_TRACE,);
- int buffd = -1;
- struct msghdr mh;
- struct sockaddr_un sa;
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control;
- struct cmsghdr *cmsg;
- /* We use /dev/shm instead of /tmp here, since we want this to
- * be a tmpfs, and one that is available from early boot on
- * and where unprivileged users can create files. */
- char path[] = "/dev/shm/journal.XXXXXX";
-
-# define NUM_FIELDS 6
- struct iovec iov[NUM_FIELDS * 5];
- char iov_bufs[NUM_FIELDS][JOURNAL_BUF_SIZE];
- struct journalState state;
-
- state.iov = iov;
- state.iov_end = iov + ARRAY_CARDINALITY(iov);
- state.bufs = iov_bufs;
- state.bufs_end = iov_bufs + ARRAY_CARDINALITY(iov_bufs);
-
- journalAddString(&state ,"MESSAGE", rawstr);
- journalAddInt(&state, "PRIORITY", priority);
- journalAddString(&state, "LIBVIRT_SOURCE",
- virLogSourceTypeToString(source));
- journalAddString(&state, "CODE_FILE", filename);
- journalAddInt(&state, "CODE_LINE", linenr);
- journalAddString(&state, "CODE_FUNC", funcname);
-
- memset(&sa, 0, sizeof(sa));
- sa.sun_family = AF_UNIX;
- if (!virStrcpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path)))
- return;
-
- memset(&mh, 0, sizeof(mh));
- mh.msg_name = &sa;
- mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
- mh.msg_iov = iov;
- mh.msg_iovlen = state.iov - iov;
-
- if (sendmsg(journalfd, &mh, MSG_NOSIGNAL) >= 0)
- return;
-
- if (errno != EMSGSIZE && errno != ENOBUFS)
- return;
-
- /* Message was too large, so dump to temporary file
- * and pass an FD to the journal
- */
-
- /* NB: mkostemp is not declared async signal safe by
- * POSIX, but this is Linux only code and the GLibc
- * impl is safe enough, only using open() and inline
- * asm to read a timestamp (falling back to gettimeofday
- * on some arches
- */
- if ((buffd = mkostemp(path, O_CLOEXEC|O_RDWR)) < 0)
- return;
-
- if (unlink(path) < 0)
- goto cleanup;
-
- if (writev(buffd, iov, state.iov - iov) < 0)
- goto cleanup;
-
- mh.msg_iov = NULL;
- mh.msg_iovlen = 0;
-
- memset(&control, 0, sizeof(control));
- mh.msg_control = &control;
- mh.msg_controllen = sizeof(control);
-
- cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- memcpy(CMSG_DATA(cmsg), &buffd, sizeof(int));
-
- mh.msg_controllen = cmsg->cmsg_len;
-
- sendmsg(journalfd, &mh, MSG_NOSIGNAL);
-
-cleanup:
- VIR_LOG_CLOSE(buffd);
-}
-
-
-static void virLogCloseJournald(void *data ATTRIBUTE_UNUSED)
-{
- VIR_LOG_CLOSE(journalfd);
-}
-
-
-static int virLogAddOutputToJournald(int priority)
-{
- if ((journalfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
- return -1;
- if (virSetInherit(journalfd, false) < 0) {
- VIR_LOG_CLOSE(journalfd);
- return -1;
- }
- if (virLogDefineOutput(virLogOutputToJournald, virLogCloseJournald, NULL,
- priority, VIR_LOG_TO_JOURNALD, NULL, 0) < 0) {
- return -1;
- }
- return 0;
-}
-# endif /* USE_JOURNALD */
-#endif /* HAVE_SYSLOG_H */
-
-#define IS_SPACE(cur) \
- ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') || \
- (*cur == '\r') || (*cur == '\\'))
-
-
-/**
- * virLogParseOutputs:
- * @outputs: string defining a (set of) output(s)
- *
- * The format for an output can be:
- * x:stderr
- * output goes to stderr
- * x:syslog:name
- * use syslog for the output and use the given name as the ident
- * x:file:file_path
- * output to a file, with the given filepath
- * In all case the x prefix is the minimal level, acting as a filter
- * 0: everything
- * 1: DEBUG
- * 2: INFO
- * 3: WARNING
- * 4: ERROR
- *
- * Multiple output can be defined in a single @output, they just need to be
- * separated by spaces.
- *
- * Returns the number of output parsed and installed or -1 in case of error
- */
-int
-virLogParseOutputs(const char *outputs)
-{
- const char *cur = outputs, *str;
- char *name;
- char *abspath;
- virLogPriority prio;
- int ret = -1;
- int count = 0;
-
- if (cur == NULL)
- return -1;
-
- VIR_DEBUG("outputs=%s", outputs);
-
- virSkipSpaces(&cur);
- while (*cur != 0) {
- prio= virParseNumber(&cur);
- if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
- goto cleanup;
- if (*cur != ':')
- goto cleanup;
- cur++;
- if (STREQLEN(cur, "stderr", 6)) {
- cur += 6;
- if (virLogAddOutputToStderr(prio) == 0)
- count++;
- } else if (STREQLEN(cur, "syslog", 6)) {
- cur += 6;
- if (*cur != ':')
- goto cleanup;
- cur++;
- str = cur;
- while ((*cur != 0) && (!IS_SPACE(cur)))
- cur++;
- if (str == cur)
- goto cleanup;
-#if HAVE_SYSLOG_H
- name = strndup(str, cur - str);
- if (name == NULL)
- goto cleanup;
- if (virLogAddOutputToSyslog(prio, name) == 0)
- count++;
- VIR_FREE(name);
-#endif /* HAVE_SYSLOG_H */
- } else if (STREQLEN(cur, "file", 4)) {
- cur += 4;
- if (*cur != ':')
- goto cleanup;
- cur++;
- str = cur;
- while ((*cur != 0) && (!IS_SPACE(cur)))
- cur++;
- if (str == cur)
- goto cleanup;
- name = strndup(str, cur - str);
- if (name == NULL)
- goto cleanup;
- if (virFileAbsPath(name, &abspath) < 0) {
- VIR_FREE(name);
- return -1; /* skip warning here because setting was fine */
- }
- if (virLogAddOutputToFile(prio, abspath) == 0)
- count++;
- VIR_FREE(name);
- VIR_FREE(abspath);
- } else if (STREQLEN(cur, "journald", 8)) {
- cur += 8;
-#if USE_JOURNALD
- if (virLogAddOutputToJournald(prio) == 0)
- count++;
-#endif /* USE_JOURNALD */
- } else {
- goto cleanup;
- }
- virSkipSpaces(&cur);
- }
- ret = count;
-cleanup:
- if (ret == -1)
- VIR_WARN("Ignoring invalid log output setting.");
- return ret;
-}
-
-
-/**
- * virLogParseFilters:
- * @filters: string defining a (set of) filter(s)
- *
- * The format for a filter is:
- * x:name
- * where name is a match string
- * the x prefix is the minimal level where the messages should be logged
- * 1: DEBUG
- * 2: INFO
- * 3: WARNING
- * 4: ERROR
- *
- * Multiple filter can be defined in a single @filters, they just need to be
- * separated by spaces.
- *
- * Returns the number of filter parsed and installed or -1 in case of error
- */
-int
-virLogParseFilters(const char *filters)
-{
- const char *cur = filters, *str;
- char *name;
- virLogPriority prio;
- int ret = -1;
- int count = 0;
-
- if (cur == NULL)
- return -1;
-
- virSkipSpaces(&cur);
- while (*cur != 0) {
- unsigned int flags = 0;
- prio= virParseNumber(&cur);
- if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
- goto cleanup;
- if (*cur != ':')
- goto cleanup;
- cur++;
- if (*cur == '+') {
- flags |= VIR_LOG_STACK_TRACE;
- cur++;
- }
- str = cur;
- while ((*cur != 0) && (!IS_SPACE(cur)))
- cur++;
- if (str == cur)
- goto cleanup;
- name = strndup(str, cur - str);
- if (name == NULL)
- goto cleanup;
- if (virLogDefineFilter(name, prio, flags) >= 0)
- count++;
- VIR_FREE(name);
- virSkipSpaces(&cur);
- }
- ret = count;
-cleanup:
- if (ret == -1)
- VIR_WARN("Ignoring invalid log filter setting.");
- return ret;
-}
-
-
-/**
- * virLogGetDefaultPriority:
- *
- * Returns the current logging priority level.
- */
-virLogPriority
-virLogGetDefaultPriority(void)
-{
- return virLogDefaultPriority;
-}
-
-
-/**
- * virLogGetFilters:
- *
- * Returns a string listing the current filters, in the format originally
- * specified in the config file or environment. Caller must free the
- * result.
- */
-char *
-virLogGetFilters(void)
-{
- int i;
- virBuffer filterbuf = VIR_BUFFER_INITIALIZER;
-
- virLogLock();
- for (i = 0; i < virLogNbFilters; i++) {
- const char *sep = ":";
- if (virLogFilters[i].flags & VIR_LOG_STACK_TRACE)
- sep = ":+";
- virBufferAsprintf(&filterbuf, "%d%s%s ",
- virLogFilters[i].priority,
- sep,
- virLogFilters[i].match);
- }
- virLogUnlock();
-
- if (virBufferError(&filterbuf)) {
- virBufferFreeAndReset(&filterbuf);
- return NULL;
- }
-
- return virBufferContentAndReset(&filterbuf);
-}
-
-
-/**
- * virLogGetOutputs:
- *
- * Returns a string listing the current outputs, in the format originally
- * specified in the config file or environment. Caller must free the
- * result.
- */
-char *
-virLogGetOutputs(void)
-{
- int i;
- virBuffer outputbuf = VIR_BUFFER_INITIALIZER;
-
- virLogLock();
- for (i = 0; i < virLogNbOutputs; i++) {
- virLogDestination dest = virLogOutputs[i].dest;
- if (i)
- virBufferAsprintf(&outputbuf, " ");
- switch (dest) {
- case VIR_LOG_TO_SYSLOG:
- case VIR_LOG_TO_FILE:
- virBufferAsprintf(&outputbuf, "%d:%s:%s",
- virLogOutputs[i].priority,
- virLogOutputString(dest),
- virLogOutputs[i].name);
- break;
- default:
- virBufferAsprintf(&outputbuf, "%d:%s",
- virLogOutputs[i].priority,
- virLogOutputString(dest));
- }
- }
- virLogUnlock();
-
- if (virBufferError(&outputbuf)) {
- virBufferFreeAndReset(&outputbuf);
- return NULL;
- }
-
- return virBufferContentAndReset(&outputbuf);
-}
-
-
-/**
- * virLogGetNbFilters:
- *
- * Returns the current number of defined log filters.
- */
-int
-virLogGetNbFilters(void)
-{
- return virLogNbFilters;
-}
-
-
-/**
- * virLogGetNbOutputs:
- *
- * Returns the current number of defined log outputs.
- */
-int
-virLogGetNbOutputs(void)
-{
- return virLogNbOutputs;
-}
-
-
-/**
- * virLogParseDefaultPriority:
- * @priority: string defining the desired logging level
- *
- * Parses and sets the default log priority level. It can take a string or
- * number corresponding to the following levels:
- * 1: DEBUG
- * 2: INFO
- * 3: WARNING
- * 4: ERROR
- *
- * Returns the parsed log level or -1 on error.
- */
-int
-virLogParseDefaultPriority(const char *priority)
-{
- int ret = -1;
-
- if (STREQ(priority, "1") || STREQ(priority, "debug"))
- ret = virLogSetDefaultPriority(VIR_LOG_DEBUG);
- else if (STREQ(priority, "2") || STREQ(priority, "info"))
- ret = virLogSetDefaultPriority(VIR_LOG_INFO);
- else if (STREQ(priority, "3") || STREQ(priority, "warning"))
- ret = virLogSetDefaultPriority(VIR_LOG_WARN);
- else if (STREQ(priority, "4") || STREQ(priority, "error"))
- ret = virLogSetDefaultPriority(VIR_LOG_ERROR);
- else
- VIR_WARN("Ignoring invalid log level setting");
-
- return ret;
-}
-
-
-/**
- * virLogSetFromEnv:
- *
- * Sets virLogDefaultPriority, virLogFilters and virLogOutputs based on
- * environment variables.
- */
-void
-virLogSetFromEnv(void)
-{
- char *debugEnv;
-
- debugEnv = getenv("LIBVIRT_DEBUG");
- if (debugEnv && *debugEnv)
- virLogParseDefaultPriority(debugEnv);
- debugEnv = getenv("LIBVIRT_LOG_FILTERS");
- if (debugEnv && *debugEnv)
- virLogParseFilters(debugEnv);
- debugEnv = getenv("LIBVIRT_LOG_OUTPUTS");
- if (debugEnv && *debugEnv)
- virLogParseOutputs(debugEnv);
-}
+++ /dev/null
-/*
- * logging.h: internal logging and debugging
- *
- * Copyright (C) 2006-2008, 2011-2012 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see
- * <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef __VIRTLOG_H_
-# define __VIRTLOG_H_
-
-# include "internal.h"
-# include "virbuffer.h"
-
-/*
- * To be made public
- */
-typedef enum {
- VIR_LOG_DEBUG = 1,
- VIR_LOG_INFO,
- VIR_LOG_WARN,
- VIR_LOG_ERROR,
-} virLogPriority;
-
-# define VIR_LOG_DEFAULT VIR_LOG_WARN
-
-typedef enum {
- VIR_LOG_TO_STDERR = 1,
- VIR_LOG_TO_SYSLOG,
- VIR_LOG_TO_FILE,
- VIR_LOG_TO_JOURNALD,
-} virLogDestination;
-
-typedef enum {
- VIR_LOG_FROM_FILE,
- VIR_LOG_FROM_ERROR,
- VIR_LOG_FROM_AUDIT,
- VIR_LOG_FROM_TRACE,
- VIR_LOG_FROM_LIBRARY,
-
- VIR_LOG_FROM_LAST,
-} virLogSource;
-
-/*
- * If configured with --enable-debug=yes then library calls
- * are printed to stderr for debugging or to an appropriate channel
- * defined at runtime from the libvirt daemon configuration file
- */
-# ifdef ENABLE_DEBUG
-# define VIR_DEBUG_INT(src, filename, linenr, funcname, ...) \
- virLogMessage(src, VIR_LOG_DEBUG, filename, linenr, funcname, NULL, __VA_ARGS__)
-# else
-/**
- * virLogEatParams:
- *
- * Do nothing but eat parameters.
- */
-static inline void virLogEatParams(virLogSource unused, ...)
-{
- /* Silence gcc */
- unused = unused;
-}
-# define VIR_DEBUG_INT(src, filename, linenr, funcname, ...) \
- virLogEatParams(src, filename, linenr, funcname, __VA_ARGS__)
-# endif /* !ENABLE_DEBUG */
-
-# define VIR_INFO_INT(src, filename, linenr, funcname, ...) \
- virLogMessage(src, VIR_LOG_INFO, filename, linenr, funcname, NULL, __VA_ARGS__)
-# define VIR_WARN_INT(src, filename, linenr, funcname, ...) \
- virLogMessage(src, VIR_LOG_WARN, filename, linenr, funcname, NULL, __VA_ARGS__)
-# define VIR_ERROR_INT(src, filename, linenr, funcname, ...) \
- virLogMessage(src, VIR_LOG_ERROR, filename, linenr, funcname, NULL, __VA_ARGS__)
-
-# define VIR_DEBUG(...) \
- VIR_DEBUG_INT(VIR_LOG_FROM_FILE, __FILE__, __LINE__, __func__, __VA_ARGS__)
-# define VIR_INFO(...) \
- VIR_INFO_INT(VIR_LOG_FROM_FILE, __FILE__, __LINE__, __func__, __VA_ARGS__)
-# define VIR_WARN(...) \
- VIR_WARN_INT(VIR_LOG_FROM_FILE, __FILE__, __LINE__, __func__, __VA_ARGS__)
-# define VIR_ERROR(...) \
- VIR_ERROR_INT(VIR_LOG_FROM_FILE, __FILE__, __LINE__, __func__, __VA_ARGS__)
-
-
-struct _virLogMetadata {
- const char *key;
- const char *s; /* String value, or NULL to use "i" */
- int i;
-};
-
-typedef struct _virLogMetadata virLogMetadata;
-typedef struct _virLogMetadata *virLogMetadataPtr;
-
-/**
- * virLogOutputFunc:
- * @src: the src for the message
- * @priority: the priority for the message
- * @filename: file where the message was emitted
- * @linenr: line where the message was emitted
- * @funcname: the function emitting the message
- * @timestamp: zero terminated string with timestamp of the message
- * @metadata: NULL or metadata array, terminated by an item with NULL key
- * @flags: flags associated with the message
- * @rawstr: the unformatted message to log, zero terminated
- * @str: the message to log, preformatted and zero terminated
- * @data: extra output logging data
- *
- * Callback function used to output messages
- */
-typedef void (*virLogOutputFunc) (virLogSource src,
- virLogPriority priority,
- const char *filename,
- int linenr,
- const char *funcname,
- const char *timestamp,
- virLogMetadataPtr metadata,
- unsigned int flags,
- const char *rawstr,
- const char *str,
- void *data);
-
-/**
- * virLogCloseFunc:
- * @data: extra output logging data
- *
- * Callback function used to close a log output
- */
-typedef void (*virLogCloseFunc) (void *data);
-
-typedef enum {
- VIR_LOG_STACK_TRACE = (1 << 0),
-} virLogFlags;
-
-extern int virLogGetNbFilters(void);
-extern int virLogGetNbOutputs(void);
-extern char *virLogGetFilters(void);
-extern char *virLogGetOutputs(void);
-extern virLogPriority virLogGetDefaultPriority(void);
-extern int virLogSetDefaultPriority(virLogPriority priority);
-extern void virLogSetFromEnv(void);
-extern int virLogDefineFilter(const char *match,
- virLogPriority priority,
- unsigned int flags);
-extern int virLogDefineOutput(virLogOutputFunc f,
- virLogCloseFunc c,
- void *data,
- virLogPriority priority,
- virLogDestination dest,
- const char *name,
- unsigned int flags);
-
-/*
- * Internal logging API
- */
-
-extern void virLogLock(void);
-extern void virLogUnlock(void);
-extern int virLogReset(void);
-extern int virLogParseDefaultPriority(const char *priority);
-extern int virLogParseFilters(const char *filters);
-extern int virLogParseOutputs(const char *output);
-extern void virLogMessage(virLogSource src,
- virLogPriority priority,
- const char *filename,
- int linenr,
- const char *funcname,
- virLogMetadataPtr metadata,
- const char *fmt, ...) ATTRIBUTE_FMT_PRINTF(7, 8);
-extern void virLogVMessage(virLogSource src,
- virLogPriority priority,
- const char *filename,
- int linenr,
- const char *funcname,
- virLogMetadataPtr metadata,
- const char *fmt,
- va_list vargs) ATTRIBUTE_FMT_PRINTF(7, 0);
-extern int virLogSetBufferSize(int size);
-extern void virLogEmergencyDumpAll(int signum);
-#endif
#include <stdlib.h>
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#if TEST_OOM
static int testMallocNext = 0;
#include <unistd.h>
#include <stdlib.h>
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "vircommand.h"
#include "virterror_internal.h"
#include "dirname.h"
#include "memory.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#include "c-ctype.h"
#include "vircommand.h"
#include "virterror_internal.h"
#include "sysinfo.h"
#include "util.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "vircommand.h"
#include "c-ctype.h"
#include "dirname.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "virbuffer.h"
#include "util.h"
#include "storage_file.h"
#include "internal.h"
#include "util.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "virfile.h"
#include "virrandom.h"
#include <sys/utsname.h>
-#include "logging.h"
+#include "virlog.h"
#include "virarch.h"
#include "verify.h"
#include <unistd.h>
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "viraudit.h"
#include "util.h"
#include "virfile.h"
#include "virauth.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "datatypes.h"
#include "virterror_internal.h"
#include "configmake.h"
#include "virkeyfile.h"
#include "memory.h"
#include "util.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "util.h"
#include "memory.h"
#include "vircgroup.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#include "virhash.h"
#include "virhashcode.h"
#include "memory.h"
#include "virterror_internal.h"
#include "util.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#include "virpidfile.h"
#include "virprocess.h"
#include "virconf.h"
#include "util.h"
#include "c-ctype.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "virfile.h"
#include "virdbus.h"
#include "memory.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "threads.h"
#define VIR_FROM_THIS VIR_FROM_DBUS
#include "vircommand.h"
#include "memory.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#define VIR_FROM_THIS VIR_FROM_NETWORK
#include "vircommand.h"
#include "memory.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "threads.h"
#if HAVE_FIREWALLD
#include "virevent.h"
#include "vireventpoll.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include <stdlib.h>
#include <fcntl.h>
#include "threads.h"
-#include "logging.h"
+#include "virlog.h"
#include "vireventpoll.h"
#include "memory.h"
#include "util.h"
#include "configmake.h"
#include "memory.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#define VIR_FROM_THIS VIR_FROM_NONE
#include "virterror_internal.h"
#include "virhash.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virhashcode.h"
#include "virrandom.h"
#include "virterror_internal.h"
#include "virhook.h"
#include "util.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "virfile.h"
#include "configmake.h"
#include "vircommand.h"
#include "memory.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "threads.h"
#if HAVE_FIREWALLD
#include "virjson.h"
#include "memory.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "util.h"
#if HAVE_YAJL
#include <stdio.h>
#include "c-ctype.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "util.h"
#include "virhash.h"
#include <config.h>
#include "virlockspace.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "virterror_internal.h"
#include "util.h"
--- /dev/null
+/*
+ * virlog.c: internal logging and debugging
+ *
+ * Copyright (C) 2008, 2010-2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <execinfo.h>
+#if HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+#include <sys/socket.h>
+#if HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+
+#include "virterror_internal.h"
+#include "virlog.h"
+#include "memory.h"
+#include "util.h"
+#include "virbuffer.h"
+#include "threads.h"
+#include "virfile.h"
+#include "virtime.h"
+#include "intprops.h"
+
+/* Journald output is only supported on Linux new enough to expose
+ * htole64. */
+#if HAVE_SYSLOG_H && defined(__linux__) && HAVE_DECL_HTOLE64
+# define USE_JOURNALD 1
+#endif
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+VIR_ENUM_DECL(virLogSource)
+VIR_ENUM_IMPL(virLogSource, VIR_LOG_FROM_LAST,
+ "file",
+ "error",
+ "audit",
+ "trace",
+ "library");
+
+/*
+ * A logging buffer to keep some history over logs
+ */
+
+static int virLogSize = 64 * 1024;
+static char *virLogBuffer = NULL;
+static int virLogLen = 0;
+static int virLogStart = 0;
+static int virLogEnd = 0;
+
+/*
+ * Filters are used to refine the rules on what to keep or drop
+ * based on a matching pattern (currently a substring)
+ */
+struct _virLogFilter {
+ const char *match;
+ virLogPriority priority;
+ unsigned int flags;
+};
+typedef struct _virLogFilter virLogFilter;
+typedef virLogFilter *virLogFilterPtr;
+
+static virLogFilterPtr virLogFilters = NULL;
+static int virLogNbFilters = 0;
+
+/*
+ * Outputs are used to emit the messages retained
+ * after filtering, multiple output can be used simultaneously
+ */
+struct _virLogOutput {
+ bool logVersion;
+ void *data;
+ virLogOutputFunc f;
+ virLogCloseFunc c;
+ virLogPriority priority;
+ virLogDestination dest;
+ const char *name;
+};
+typedef struct _virLogOutput virLogOutput;
+typedef virLogOutput *virLogOutputPtr;
+
+static virLogOutputPtr virLogOutputs = NULL;
+static int virLogNbOutputs = 0;
+
+/*
+ * Default priorities
+ */
+static virLogPriority virLogDefaultPriority = VIR_LOG_DEFAULT;
+
+static int virLogResetFilters(void);
+static int virLogResetOutputs(void);
+static void virLogOutputToFd(virLogSource src,
+ virLogPriority priority,
+ const char *filename,
+ int linenr,
+ const char *funcname,
+ const char *timestamp,
+ virLogMetadataPtr metadata,
+ unsigned int flags,
+ const char *rawstr,
+ const char *str,
+ void *data);
+
+/*
+ * Logs accesses must be serialized though a mutex
+ */
+virMutex virLogMutex;
+
+void
+virLogLock(void)
+{
+ virMutexLock(&virLogMutex);
+}
+
+
+void
+virLogUnlock(void)
+{
+ virMutexUnlock(&virLogMutex);
+}
+
+
+static const char *
+virLogOutputString(virLogDestination ldest)
+{
+ switch (ldest) {
+ case VIR_LOG_TO_STDERR:
+ return "stderr";
+ case VIR_LOG_TO_SYSLOG:
+ return "syslog";
+ case VIR_LOG_TO_FILE:
+ return "file";
+ case VIR_LOG_TO_JOURNALD:
+ return "journald";
+ }
+ return "unknown";
+}
+
+
+static const char *
+virLogPriorityString(virLogPriority lvl)
+{
+ switch (lvl) {
+ case VIR_LOG_DEBUG:
+ return "debug";
+ case VIR_LOG_INFO:
+ return "info";
+ case VIR_LOG_WARN:
+ return "warning";
+ case VIR_LOG_ERROR:
+ return "error";
+ }
+ return "unknown";
+}
+
+
+static int
+virLogOnceInit(void)
+{
+ const char *pbm = NULL;
+
+ if (virMutexInit(&virLogMutex) < 0)
+ return -1;
+
+ virLogLock();
+ if (VIR_ALLOC_N(virLogBuffer, virLogSize + 1) < 0) {
+ /*
+ * The debug buffer is not a critical component, allow startup
+ * even in case of failure to allocate it in case of a
+ * configuration mistake.
+ */
+ virLogSize = 64 * 1024;
+ if (VIR_ALLOC_N(virLogBuffer, virLogSize + 1) < 0) {
+ pbm = "Failed to allocate debug buffer: deactivating debug log\n";
+ virLogSize = 0;
+ } else {
+ pbm = "Failed to allocate debug buffer: reduced to 64 kB\n";
+ }
+ }
+ virLogLen = 0;
+ virLogStart = 0;
+ virLogEnd = 0;
+ virLogDefaultPriority = VIR_LOG_DEFAULT;
+ virLogUnlock();
+ if (pbm)
+ VIR_WARN("%s", pbm);
+ return 0;
+}
+
+VIR_ONCE_GLOBAL_INIT(virLog)
+
+
+/**
+ * virLogSetBufferSize:
+ * @size: size of the buffer in kilobytes or <= 0 to deactivate
+ *
+ * Dynamically set the size or deactivate the logging buffer used to keep
+ * a trace of all recent debug output. Note that the content of the buffer
+ * is lost if it gets reallocated.
+ *
+ * Return -1 in case of failure or 0 in case of success
+ */
+int
+virLogSetBufferSize(int size)
+{
+ int ret = 0;
+ int oldsize;
+ char *oldLogBuffer;
+ const char *pbm = NULL;
+
+ if (size < 0)
+ size = 0;
+
+ if (virLogInitialize() < 0)
+ return -1;
+
+ if (size * 1024 == virLogSize)
+ return ret;
+
+ virLogLock();
+
+ oldsize = virLogSize;
+ oldLogBuffer = virLogBuffer;
+
+ if (INT_MAX / 1024 <= size) {
+ pbm = "Requested log size of %d kB too large\n";
+ ret = -1;
+ goto error;
+ }
+
+ virLogSize = size * 1024;
+ if (VIR_ALLOC_N(virLogBuffer, virLogSize + 1) < 0) {
+ pbm = "Failed to allocate debug buffer of %d kB\n";
+ virLogBuffer = oldLogBuffer;
+ virLogSize = oldsize;
+ ret = -1;
+ goto error;
+ }
+ VIR_FREE(oldLogBuffer);
+ virLogLen = 0;
+ virLogStart = 0;
+ virLogEnd = 0;
+
+error:
+ virLogUnlock();
+ if (pbm)
+ VIR_ERROR(pbm, size);
+ return ret;
+}
+
+
+/**
+ * virLogReset:
+ *
+ * Reset the logging module to its default initial state
+ *
+ * Returns 0 if successful, and -1 in case or error
+ */
+int
+virLogReset(void)
+{
+ if (virLogInitialize() < 0)
+ return -1;
+
+ virLogLock();
+ virLogResetFilters();
+ virLogResetOutputs();
+ virLogLen = 0;
+ virLogStart = 0;
+ virLogEnd = 0;
+ virLogDefaultPriority = VIR_LOG_DEFAULT;
+ virLogUnlock();
+ return 0;
+}
+
+
+/*
+ * Store a string in the ring buffer
+ */
+static void
+virLogStr(const char *str)
+{
+ int tmp;
+ int len;
+
+ if ((str == NULL) || (virLogBuffer == NULL) || (virLogSize <= 0))
+ return;
+ len = strlen(str);
+ if (len >= virLogSize)
+ return;
+
+ /*
+ * copy the data and reset the end, we cycle over the end of the buffer
+ */
+ if (virLogEnd + len >= virLogSize) {
+ tmp = virLogSize - virLogEnd;
+ memcpy(&virLogBuffer[virLogEnd], str, tmp);
+ memcpy(&virLogBuffer[0], &str[tmp], len - tmp);
+ virLogEnd = len - tmp;
+ } else {
+ memcpy(&virLogBuffer[virLogEnd], str, len);
+ virLogEnd += len;
+ }
+ virLogBuffer[virLogEnd] = 0;
+ /*
+ * Update the log length, and if full move the start index
+ */
+ virLogLen += len;
+ if (virLogLen > virLogSize) {
+ tmp = virLogLen - virLogSize;
+ virLogLen = virLogSize;
+ virLogStart += tmp;
+ if (virLogStart >= virLogSize)
+ virLogStart -= virLogSize;
+ }
+}
+
+
+static void
+virLogDumpAllFD(const char *msg, int len)
+{
+ int i, found = 0;
+
+ if (len <= 0)
+ len = strlen(msg);
+
+ for (i = 0; i < virLogNbOutputs;i++) {
+ if (virLogOutputs[i].f == virLogOutputToFd) {
+ int fd = (intptr_t) virLogOutputs[i].data;
+
+ if (fd >= 0) {
+ ignore_value(safewrite(fd, msg, len));
+ found = 1;
+ }
+ }
+ }
+ if (!found)
+ ignore_value(safewrite(STDERR_FILENO, msg, len));
+}
+
+
+/**
+ * virLogEmergencyDumpAll:
+ * @signum: the signal number
+ *
+ * Emergency function called, possibly from a signal handler.
+ * It need to output the debug ring buffer through the log
+ * output which are safe to use from a signal handler.
+ * In case none is found it is emitted to standard error.
+ */
+void
+virLogEmergencyDumpAll(int signum)
+{
+ int len;
+ int oldLogStart, oldLogLen;
+
+ switch (signum) {
+#ifdef SIGFPE
+ case SIGFPE:
+ virLogDumpAllFD("Caught signal Floating-point exception", -1);
+ break;
+#endif
+#ifdef SIGSEGV
+ case SIGSEGV:
+ virLogDumpAllFD("Caught Segmentation violation", -1);
+ break;
+#endif
+#ifdef SIGILL
+ case SIGILL:
+ virLogDumpAllFD("Caught illegal instruction", -1);
+ break;
+#endif
+#ifdef SIGABRT
+ case SIGABRT:
+ virLogDumpAllFD("Caught abort signal", -1);
+ break;
+#endif
+#ifdef SIGBUS
+ case SIGBUS:
+ virLogDumpAllFD("Caught bus error", -1);
+ break;
+#endif
+#ifdef SIGUSR2
+ case SIGUSR2:
+ virLogDumpAllFD("Caught User-defined signal 2", -1);
+ break;
+#endif
+ default:
+ virLogDumpAllFD("Caught unexpected signal", -1);
+ break;
+ }
+ if ((virLogBuffer == NULL) || (virLogSize <= 0)) {
+ virLogDumpAllFD(" internal log buffer deactivated\n", -1);
+ return;
+ }
+
+ virLogDumpAllFD(" dumping internal log buffer:\n", -1);
+ virLogDumpAllFD("\n\n ====== start of log =====\n\n", -1);
+
+ /*
+ * Since we can't lock the buffer safely from a signal handler
+ * we mark it as empty in case of concurrent access, and proceed
+ * with the data, at worse we will output something a bit weird
+ * if another thread start logging messages at the same time.
+ * Note that virLogStr() uses virLogEnd for the computations and
+ * writes to the buffer and only then updates virLogLen and virLogStart
+ * so it's best to reset it first.
+ */
+ oldLogStart = virLogStart;
+ oldLogLen = virLogLen;
+ virLogEnd = 0;
+ virLogLen = 0;
+ virLogStart = 0;
+
+ while (oldLogLen > 0) {
+ if (oldLogStart + oldLogLen < virLogSize) {
+ virLogBuffer[oldLogStart + oldLogLen] = 0;
+ virLogDumpAllFD(&virLogBuffer[oldLogStart], oldLogLen);
+ oldLogStart += oldLogLen;
+ oldLogLen = 0;
+ } else {
+ len = virLogSize - oldLogStart;
+ virLogBuffer[virLogSize] = 0;
+ virLogDumpAllFD(&virLogBuffer[oldLogStart], len);
+ oldLogLen -= len;
+ oldLogStart = 0;
+ }
+ }
+ virLogDumpAllFD("\n\n ====== end of log =====\n\n", -1);
+}
+
+
+/**
+ * virLogSetDefaultPriority:
+ * @priority: the default priority level
+ *
+ * Set the default priority level, i.e. any logged data of a priority
+ * equal or superior to this level will be logged, unless a specific rule
+ * was defined for the log category of the message.
+ *
+ * Returns 0 if successful, -1 in case of error.
+ */
+int
+virLogSetDefaultPriority(virLogPriority priority)
+{
+ if ((priority < VIR_LOG_DEBUG) || (priority > VIR_LOG_ERROR)) {
+ VIR_WARN("Ignoring invalid log level setting.");
+ return -1;
+ }
+ if (virLogInitialize() < 0)
+ return -1;
+
+ virLogDefaultPriority = priority;
+ return 0;
+}
+
+
+/**
+ * virLogResetFilters:
+ *
+ * Removes the set of logging filters defined.
+ *
+ * Returns the number of filters removed
+ */
+static int
+virLogResetFilters(void)
+{
+ int i;
+
+ for (i = 0; i < virLogNbFilters;i++)
+ VIR_FREE(virLogFilters[i].match);
+ VIR_FREE(virLogFilters);
+ virLogNbFilters = 0;
+ return i;
+}
+
+
+/**
+ * virLogDefineFilter:
+ * @match: the pattern to match
+ * @priority: the priority to give to messages matching the pattern
+ * @flags: extra flags, see virLogFilterFlags enum
+ *
+ * Defines a pattern used for log filtering, it allow to select or
+ * reject messages independently of the default priority.
+ * The filter defines a rules that will apply only to messages matching
+ * the pattern (currently if @match is a substring of the message category)
+ *
+ * Returns -1 in case of failure or the filter number if successful
+ */
+int
+virLogDefineFilter(const char *match,
+ virLogPriority priority,
+ unsigned int flags)
+{
+ int i;
+ char *mdup = NULL;
+
+ virCheckFlags(VIR_LOG_STACK_TRACE, -1);
+
+ if ((match == NULL) || (priority < VIR_LOG_DEBUG) ||
+ (priority > VIR_LOG_ERROR))
+ return -1;
+
+ virLogLock();
+ for (i = 0;i < virLogNbFilters;i++) {
+ if (STREQ(virLogFilters[i].match, match)) {
+ virLogFilters[i].priority = priority;
+ goto cleanup;
+ }
+ }
+
+ mdup = strdup(match);
+ if (mdup == NULL) {
+ i = -1;
+ goto cleanup;
+ }
+ i = virLogNbFilters;
+ if (VIR_REALLOC_N(virLogFilters, virLogNbFilters + 1)) {
+ i = -1;
+ VIR_FREE(mdup);
+ goto cleanup;
+ }
+ virLogFilters[i].match = mdup;
+ virLogFilters[i].priority = priority;
+ virLogFilters[i].flags = flags;
+ virLogNbFilters++;
+cleanup:
+ virLogUnlock();
+ return i;
+}
+
+
+/**
+ * virLogFiltersCheck:
+ * @input: the input string
+ *
+ * Check the input of the message against the existing filters. Currently
+ * the match is just a substring check of the category used as the input
+ * string, a more subtle approach could be used instead
+ *
+ * Returns 0 if not matched or the new priority if found.
+ */
+static int
+virLogFiltersCheck(const char *input,
+ unsigned int *flags)
+{
+ int ret = 0;
+ int i;
+
+ virLogLock();
+ for (i = 0;i < virLogNbFilters;i++) {
+ if (strstr(input, virLogFilters[i].match)) {
+ ret = virLogFilters[i].priority;
+ *flags = virLogFilters[i].flags;
+ break;
+ }
+ }
+ virLogUnlock();
+ return ret;
+}
+
+
+/**
+ * virLogResetOutputs:
+ *
+ * Removes the set of logging output defined.
+ *
+ * Returns the number of output removed
+ */
+static int
+virLogResetOutputs(void)
+{
+ int i;
+
+ for (i = 0;i < virLogNbOutputs;i++) {
+ if (virLogOutputs[i].c != NULL)
+ virLogOutputs[i].c(virLogOutputs[i].data);
+ VIR_FREE(virLogOutputs[i].name);
+ }
+ VIR_FREE(virLogOutputs);
+ i = virLogNbOutputs;
+ virLogNbOutputs = 0;
+ return i;
+}
+
+
+/**
+ * virLogDefineOutput:
+ * @f: the function to call to output a message
+ * @c: the function to call to close the output (or NULL)
+ * @data: extra data passed as first arg to the function
+ * @priority: minimal priority for this filter, use 0 for none
+ * @dest: where to send output of this priority
+ * @name: optional name data associated with an output
+ * @flags: extra flag, currently unused
+ *
+ * Defines an output function for log messages. Each message once
+ * gone though filtering is emitted through each registered output.
+ *
+ * Returns -1 in case of failure or the output number if successful
+ */
+int
+virLogDefineOutput(virLogOutputFunc f,
+ virLogCloseFunc c,
+ void *data,
+ virLogPriority priority,
+ virLogDestination dest,
+ const char *name,
+ unsigned int flags)
+{
+ int ret = -1;
+ char *ndup = NULL;
+
+ virCheckFlags(0, -1);
+
+ if (f == NULL)
+ return -1;
+
+ if (dest == VIR_LOG_TO_SYSLOG || dest == VIR_LOG_TO_FILE) {
+ if (name == NULL)
+ return -1;
+ ndup = strdup(name);
+ if (ndup == NULL)
+ return -1;
+ }
+
+ virLogLock();
+ if (VIR_REALLOC_N(virLogOutputs, virLogNbOutputs + 1)) {
+ VIR_FREE(ndup);
+ goto cleanup;
+ }
+ ret = virLogNbOutputs++;
+ virLogOutputs[ret].logVersion = true;
+ virLogOutputs[ret].f = f;
+ virLogOutputs[ret].c = c;
+ virLogOutputs[ret].data = data;
+ virLogOutputs[ret].priority = priority;
+ virLogOutputs[ret].dest = dest;
+ virLogOutputs[ret].name = ndup;
+cleanup:
+ virLogUnlock();
+ return ret;
+}
+
+
+static int
+virLogFormatString(char **msg,
+ int linenr,
+ const char *funcname,
+ virLogPriority priority,
+ const char *str)
+{
+ int ret;
+
+ /*
+ * Be careful when changing the following log message formatting, we rely
+ * on it when stripping libvirt debug messages from qemu log files. So when
+ * changing this, you might also need to change the code there.
+ * virLogFormatString() function name is mentioned there so it's sufficient
+ * to just grep for it to find the right place.
+ */
+ if ((funcname != NULL)) {
+ ret = virAsprintf(msg, "%d: %s : %s:%d : %s\n",
+ virThreadSelfID(), virLogPriorityString(priority),
+ funcname, linenr, str);
+ } else {
+ ret = virAsprintf(msg, "%d: %s : %s\n",
+ virThreadSelfID(), virLogPriorityString(priority),
+ str);
+ }
+ return ret;
+}
+
+
+static int
+virLogVersionString(const char **rawmsg,
+ char **msg)
+{
+#ifdef PACKAGER_VERSION
+# ifdef PACKAGER
+# define LOG_VERSION_STRING \
+ "libvirt version: " VERSION ", package: " PACKAGER_VERSION " (" PACKAGER ")"
+# else
+# define LOG_VERSION_STRING \
+ "libvirt version: " VERSION ", package: " PACKAGER_VERSION
+# endif
+#else
+# define LOG_VERSION_STRING \
+ "libvirt version: " VERSION
+#endif
+
+ *rawmsg = LOG_VERSION_STRING;
+ return virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, LOG_VERSION_STRING);
+}
+
+
+/**
+ * virLogMessage:
+ * @source: where is that message coming from
+ * @priority: the priority level
+ * @filename: file where the message was emitted
+ * @linenr: line where the message was emitted
+ * @funcname: the function emitting the (debug) message
+ * @metadata: NULL or metadata array, terminated by an item with NULL key
+ * @fmt: the string format
+ * @...: the arguments
+ *
+ * Call the libvirt logger with some information. Based on the configuration
+ * the message may be stored, sent to output or just discarded
+ */
+void
+virLogMessage(virLogSource source,
+ virLogPriority priority,
+ const char *filename,
+ int linenr,
+ const char *funcname,
+ virLogMetadataPtr metadata,
+ const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ virLogVMessage(source, priority,
+ filename, linenr, funcname,
+ metadata, fmt, ap);
+ va_end(ap);
+}
+
+
+/**
+ * virLogVMessage:
+ * @source: where is that message coming from
+ * @priority: the priority level
+ * @filename: file where the message was emitted
+ * @linenr: line where the message was emitted
+ * @funcname: the function emitting the (debug) message
+ * @metadata: NULL or metadata array, terminated by an item with NULL key
+ * @fmt: the string format
+ * @vargs: format args
+ *
+ * Call the libvirt logger with some information. Based on the configuration
+ * the message may be stored, sent to output or just discarded
+ */
+void
+virLogVMessage(virLogSource source,
+ virLogPriority priority,
+ const char *filename,
+ int linenr,
+ const char *funcname,
+ virLogMetadataPtr metadata,
+ const char *fmt,
+ va_list vargs)
+{
+ static bool logVersionStderr = true;
+ char *str = NULL;
+ char *msg = NULL;
+ char timestamp[VIR_TIME_STRING_BUFLEN];
+ int fprio, i, ret;
+ int saved_errno = errno;
+ int emit = 1;
+ unsigned int filterflags = 0;
+
+ if (virLogInitialize() < 0)
+ return;
+
+ if (fmt == NULL)
+ goto cleanup;
+
+ /*
+ * check against list of specific logging patterns
+ */
+ fprio = virLogFiltersCheck(filename, &filterflags);
+ if (fprio == 0) {
+ if (priority < virLogDefaultPriority)
+ emit = 0;
+ } else if (priority < fprio) {
+ emit = 0;
+ }
+
+ if ((emit == 0) && ((virLogBuffer == NULL) || (virLogSize <= 0)))
+ goto cleanup;
+
+ /*
+ * serialize the error message, add level and timestamp
+ */
+ if (virVasprintf(&str, fmt, vargs) < 0) {
+ goto cleanup;
+ }
+
+ ret = virLogFormatString(&msg, linenr, funcname, priority, str);
+ if (ret < 0)
+ goto cleanup;
+
+ if (virTimeStringNowRaw(timestamp) < 0)
+ timestamp[0] = '\0';
+
+ /*
+ * Log based on defaults, first store in the history buffer,
+ * then if emit push the message on the outputs defined, if none
+ * use stderr.
+ * NOTE: the locking is a single point of contention for multiple
+ * threads, but avoid intermixing. Maybe set up locks per output
+ * to improve paralellism.
+ */
+ virLogLock();
+ virLogStr(timestamp);
+ virLogStr(msg);
+ virLogUnlock();
+ if (emit == 0)
+ goto cleanup;
+
+ virLogLock();
+ for (i = 0; i < virLogNbOutputs; i++) {
+ if (priority >= virLogOutputs[i].priority) {
+ if (virLogOutputs[i].logVersion) {
+ const char *rawver;
+ char *ver = NULL;
+ if (virLogVersionString(&rawver, &ver) >= 0)
+ virLogOutputs[i].f(VIR_LOG_FROM_FILE, VIR_LOG_INFO,
+ __FILE__, __LINE__, __func__,
+ timestamp, NULL, 0, rawver, ver,
+ virLogOutputs[i].data);
+ VIR_FREE(ver);
+ virLogOutputs[i].logVersion = false;
+ }
+ virLogOutputs[i].f(source, priority,
+ filename, linenr, funcname,
+ timestamp, metadata, filterflags,
+ str, msg, virLogOutputs[i].data);
+ }
+ }
+ if ((virLogNbOutputs == 0) && (source != VIR_LOG_FROM_ERROR)) {
+ if (logVersionStderr) {
+ const char *rawver;
+ char *ver = NULL;
+ if (virLogVersionString(&rawver, &ver) >= 0)
+ virLogOutputToFd(VIR_LOG_FROM_FILE, VIR_LOG_INFO,
+ __FILE__, __LINE__, __func__,
+ timestamp, NULL, 0, rawver, ver,
+ (void *) STDERR_FILENO);
+ VIR_FREE(ver);
+ logVersionStderr = false;
+ }
+ virLogOutputToFd(source, priority,
+ filename, linenr, funcname,
+ timestamp, metadata, filterflags,
+ str, msg, (void *) STDERR_FILENO);
+ }
+ virLogUnlock();
+
+cleanup:
+ VIR_FREE(str);
+ VIR_FREE(msg);
+ errno = saved_errno;
+}
+
+
+static void
+virLogStackTraceToFd(int fd)
+{
+ void *array[100];
+ int size;
+ static bool doneWarning = false;
+ const char *msg = "Stack trace not available on this platform\n";
+
+#define STRIP_DEPTH 3
+ size = backtrace(array, ARRAY_CARDINALITY(array));
+ if (size) {
+ backtrace_symbols_fd(array + STRIP_DEPTH, size - STRIP_DEPTH, fd);
+ ignore_value(safewrite(fd, "\n", 1));
+ } else if (!doneWarning) {
+ ignore_value(safewrite(fd, msg, strlen(msg)));
+ doneWarning = true;
+ }
+#undef STRIP_DEPTH
+}
+
+static void
+virLogOutputToFd(virLogSource source ATTRIBUTE_UNUSED,
+ virLogPriority priority ATTRIBUTE_UNUSED,
+ const char *filename ATTRIBUTE_UNUSED,
+ int linenr ATTRIBUTE_UNUSED,
+ const char *funcname ATTRIBUTE_UNUSED,
+ const char *timestamp,
+ virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
+ unsigned int flags,
+ const char *rawstr ATTRIBUTE_UNUSED,
+ const char *str,
+ void *data)
+{
+ int fd = (intptr_t) data;
+ char *msg;
+
+ if (fd < 0)
+ return;
+
+ if (virAsprintf(&msg, "%s: %s", timestamp, str) < 0)
+ return;
+
+ ignore_value(safewrite(fd, msg, strlen(msg)));
+ VIR_FREE(msg);
+
+ if (flags & VIR_LOG_STACK_TRACE)
+ virLogStackTraceToFd(fd);
+}
+
+
+static void
+virLogCloseFd(void *data)
+{
+ int fd = (intptr_t) data;
+
+ VIR_LOG_CLOSE(fd);
+}
+
+
+static int
+virLogAddOutputToStderr(virLogPriority priority)
+{
+ if (virLogDefineOutput(virLogOutputToFd, NULL, (void *)2L, priority,
+ VIR_LOG_TO_STDERR, NULL, 0) < 0)
+ return -1;
+ return 0;
+}
+
+
+static int
+virLogAddOutputToFile(virLogPriority priority,
+ const char *file)
+{
+ int fd;
+
+ fd = open(file, O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR);
+ if (fd < 0)
+ return -1;
+ if (virLogDefineOutput(virLogOutputToFd, virLogCloseFd,
+ (void *)(intptr_t)fd,
+ priority, VIR_LOG_TO_FILE, file, 0) < 0) {
+ VIR_FORCE_CLOSE(fd);
+ return -1;
+ }
+ return 0;
+}
+
+
+#if HAVE_SYSLOG_H
+static int
+virLogPrioritySyslog(virLogPriority priority)
+{
+ switch (priority) {
+ case VIR_LOG_DEBUG:
+ return LOG_DEBUG;
+ case VIR_LOG_INFO:
+ return LOG_INFO;
+ case VIR_LOG_WARN:
+ return LOG_WARNING;
+ case VIR_LOG_ERROR:
+ return LOG_ERR;
+ default:
+ return LOG_ERR;
+ }
+}
+
+
+static void
+virLogOutputToSyslog(virLogSource source ATTRIBUTE_UNUSED,
+ virLogPriority priority,
+ const char *filename ATTRIBUTE_UNUSED,
+ int linenr ATTRIBUTE_UNUSED,
+ const char *funcname ATTRIBUTE_UNUSED,
+ const char *timestamp ATTRIBUTE_UNUSED,
+ virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
+ unsigned int flags,
+ const char *rawstr ATTRIBUTE_UNUSED,
+ const char *str,
+ void *data ATTRIBUTE_UNUSED)
+{
+ virCheckFlags(VIR_LOG_STACK_TRACE,);
+
+ syslog(virLogPrioritySyslog(priority), "%s", str);
+}
+
+static char *current_ident = NULL;
+
+
+static void
+virLogCloseSyslog(void *data ATTRIBUTE_UNUSED)
+{
+ closelog();
+ VIR_FREE(current_ident);
+}
+
+
+static int
+virLogAddOutputToSyslog(virLogPriority priority,
+ const char *ident)
+{
+ /*
+ * ident needs to be kept around on Solaris
+ */
+ VIR_FREE(current_ident);
+ current_ident = strdup(ident);
+ if (current_ident == NULL)
+ return -1;
+
+ openlog(current_ident, 0, 0);
+ if (virLogDefineOutput(virLogOutputToSyslog, virLogCloseSyslog, NULL,
+ priority, VIR_LOG_TO_SYSLOG, ident, 0) < 0) {
+ closelog();
+ VIR_FREE(current_ident);
+ return -1;
+ }
+ return 0;
+}
+
+
+# if USE_JOURNALD
+# define IOVEC_SET(iov, data, size) \
+ do { \
+ struct iovec *_i = &(iov); \
+ _i->iov_base = (void*)(data); \
+ _i->iov_len = (size); \
+ } while (0)
+
+# define IOVEC_SET_STRING(iov, str) IOVEC_SET(iov, str, strlen(str))
+
+/* Used for conversion of numbers to strings, and for length of binary data */
+# define JOURNAL_BUF_SIZE (MAX(INT_BUFSIZE_BOUND(int), sizeof(uint64_t)))
+
+struct journalState
+{
+ struct iovec *iov, *iov_end;
+ char (*bufs)[JOURNAL_BUF_SIZE], (*bufs_end)[JOURNAL_BUF_SIZE];
+};
+
+static void
+journalAddString(struct journalState *state, const char *field,
+ const char *value)
+{
+ static const char newline = '\n', equals = '=';
+
+ if (strchr(value, '\n') != NULL) {
+ uint64_t nstr;
+
+ /* If 'str' contains a newline, then we must
+ * encode the string length, since we can't
+ * rely on the newline for the field separator
+ */
+ if (state->iov_end - state->iov < 5 || state->bufs == state->bufs_end)
+ return; /* Silently drop */
+ nstr = htole64(strlen(value));
+ memcpy(state->bufs[0], &nstr, sizeof(nstr));
+
+ IOVEC_SET_STRING(state->iov[0], field);
+ IOVEC_SET(state->iov[1], &newline, sizeof(newline));
+ IOVEC_SET(state->iov[2], state->bufs[0], sizeof(nstr));
+ state->bufs++;
+ state->iov += 3;
+ } else {
+ if (state->iov_end - state->iov < 4)
+ return; /* Silently drop */
+ IOVEC_SET_STRING(state->iov[0], field);
+ IOVEC_SET(state->iov[1], (void *)&equals, sizeof(equals));
+ state->iov += 2;
+ }
+ IOVEC_SET_STRING(state->iov[0], value);
+ IOVEC_SET(state->iov[1], (void *)&newline, sizeof(newline));
+ state->iov += 2;
+}
+
+static void
+journalAddInt(struct journalState *state, const char *field, int value)
+{
+ static const char newline = '\n', equals = '=';
+
+ char *num;
+
+ if (state->iov_end - state->iov < 4 || state->bufs == state->bufs_end)
+ return; /* Silently drop */
+
+ num = virFormatIntDecimal(state->bufs[0], sizeof(state->bufs[0]), value);
+
+ IOVEC_SET_STRING(state->iov[0], field);
+ IOVEC_SET(state->iov[1], (void *)&equals, sizeof(equals));
+ IOVEC_SET_STRING(state->iov[2], num);
+ IOVEC_SET(state->iov[3], (void *)&newline, sizeof(newline));
+ state->bufs++;
+ state->iov += 4;
+}
+
+static int journalfd = -1;
+
+static void
+virLogOutputToJournald(virLogSource source,
+ virLogPriority priority,
+ const char *filename,
+ int linenr,
+ const char *funcname,
+ const char *timestamp ATTRIBUTE_UNUSED,
+ virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
+ unsigned int flags,
+ const char *rawstr,
+ const char *str ATTRIBUTE_UNUSED,
+ void *data ATTRIBUTE_UNUSED)
+{
+ virCheckFlags(VIR_LOG_STACK_TRACE,);
+ int buffd = -1;
+ struct msghdr mh;
+ struct sockaddr_un sa;
+ union {
+ struct cmsghdr cmsghdr;
+ uint8_t buf[CMSG_SPACE(sizeof(int))];
+ } control;
+ struct cmsghdr *cmsg;
+ /* We use /dev/shm instead of /tmp here, since we want this to
+ * be a tmpfs, and one that is available from early boot on
+ * and where unprivileged users can create files. */
+ char path[] = "/dev/shm/journal.XXXXXX";
+
+# define NUM_FIELDS 6
+ struct iovec iov[NUM_FIELDS * 5];
+ char iov_bufs[NUM_FIELDS][JOURNAL_BUF_SIZE];
+ struct journalState state;
+
+ state.iov = iov;
+ state.iov_end = iov + ARRAY_CARDINALITY(iov);
+ state.bufs = iov_bufs;
+ state.bufs_end = iov_bufs + ARRAY_CARDINALITY(iov_bufs);
+
+ journalAddString(&state ,"MESSAGE", rawstr);
+ journalAddInt(&state, "PRIORITY", priority);
+ journalAddString(&state, "LIBVIRT_SOURCE",
+ virLogSourceTypeToString(source));
+ journalAddString(&state, "CODE_FILE", filename);
+ journalAddInt(&state, "CODE_LINE", linenr);
+ journalAddString(&state, "CODE_FUNC", funcname);
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sun_family = AF_UNIX;
+ if (!virStrcpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path)))
+ return;
+
+ memset(&mh, 0, sizeof(mh));
+ mh.msg_name = &sa;
+ mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
+ mh.msg_iov = iov;
+ mh.msg_iovlen = state.iov - iov;
+
+ if (sendmsg(journalfd, &mh, MSG_NOSIGNAL) >= 0)
+ return;
+
+ if (errno != EMSGSIZE && errno != ENOBUFS)
+ return;
+
+ /* Message was too large, so dump to temporary file
+ * and pass an FD to the journal
+ */
+
+ /* NB: mkostemp is not declared async signal safe by
+ * POSIX, but this is Linux only code and the GLibc
+ * impl is safe enough, only using open() and inline
+ * asm to read a timestamp (falling back to gettimeofday
+ * on some arches
+ */
+ if ((buffd = mkostemp(path, O_CLOEXEC|O_RDWR)) < 0)
+ return;
+
+ if (unlink(path) < 0)
+ goto cleanup;
+
+ if (writev(buffd, iov, state.iov - iov) < 0)
+ goto cleanup;
+
+ mh.msg_iov = NULL;
+ mh.msg_iovlen = 0;
+
+ memset(&control, 0, sizeof(control));
+ mh.msg_control = &control;
+ mh.msg_controllen = sizeof(control);
+
+ cmsg = CMSG_FIRSTHDR(&mh);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cmsg), &buffd, sizeof(int));
+
+ mh.msg_controllen = cmsg->cmsg_len;
+
+ sendmsg(journalfd, &mh, MSG_NOSIGNAL);
+
+cleanup:
+ VIR_LOG_CLOSE(buffd);
+}
+
+
+static void virLogCloseJournald(void *data ATTRIBUTE_UNUSED)
+{
+ VIR_LOG_CLOSE(journalfd);
+}
+
+
+static int virLogAddOutputToJournald(int priority)
+{
+ if ((journalfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
+ return -1;
+ if (virSetInherit(journalfd, false) < 0) {
+ VIR_LOG_CLOSE(journalfd);
+ return -1;
+ }
+ if (virLogDefineOutput(virLogOutputToJournald, virLogCloseJournald, NULL,
+ priority, VIR_LOG_TO_JOURNALD, NULL, 0) < 0) {
+ return -1;
+ }
+ return 0;
+}
+# endif /* USE_JOURNALD */
+#endif /* HAVE_SYSLOG_H */
+
+#define IS_SPACE(cur) \
+ ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') || \
+ (*cur == '\r') || (*cur == '\\'))
+
+
+/**
+ * virLogParseOutputs:
+ * @outputs: string defining a (set of) output(s)
+ *
+ * The format for an output can be:
+ * x:stderr
+ * output goes to stderr
+ * x:syslog:name
+ * use syslog for the output and use the given name as the ident
+ * x:file:file_path
+ * output to a file, with the given filepath
+ * In all case the x prefix is the minimal level, acting as a filter
+ * 0: everything
+ * 1: DEBUG
+ * 2: INFO
+ * 3: WARNING
+ * 4: ERROR
+ *
+ * Multiple output can be defined in a single @output, they just need to be
+ * separated by spaces.
+ *
+ * Returns the number of output parsed and installed or -1 in case of error
+ */
+int
+virLogParseOutputs(const char *outputs)
+{
+ const char *cur = outputs, *str;
+ char *name;
+ char *abspath;
+ virLogPriority prio;
+ int ret = -1;
+ int count = 0;
+
+ if (cur == NULL)
+ return -1;
+
+ VIR_DEBUG("outputs=%s", outputs);
+
+ virSkipSpaces(&cur);
+ while (*cur != 0) {
+ prio= virParseNumber(&cur);
+ if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
+ goto cleanup;
+ if (*cur != ':')
+ goto cleanup;
+ cur++;
+ if (STREQLEN(cur, "stderr", 6)) {
+ cur += 6;
+ if (virLogAddOutputToStderr(prio) == 0)
+ count++;
+ } else if (STREQLEN(cur, "syslog", 6)) {
+ cur += 6;
+ if (*cur != ':')
+ goto cleanup;
+ cur++;
+ str = cur;
+ while ((*cur != 0) && (!IS_SPACE(cur)))
+ cur++;
+ if (str == cur)
+ goto cleanup;
+#if HAVE_SYSLOG_H
+ name = strndup(str, cur - str);
+ if (name == NULL)
+ goto cleanup;
+ if (virLogAddOutputToSyslog(prio, name) == 0)
+ count++;
+ VIR_FREE(name);
+#endif /* HAVE_SYSLOG_H */
+ } else if (STREQLEN(cur, "file", 4)) {
+ cur += 4;
+ if (*cur != ':')
+ goto cleanup;
+ cur++;
+ str = cur;
+ while ((*cur != 0) && (!IS_SPACE(cur)))
+ cur++;
+ if (str == cur)
+ goto cleanup;
+ name = strndup(str, cur - str);
+ if (name == NULL)
+ goto cleanup;
+ if (virFileAbsPath(name, &abspath) < 0) {
+ VIR_FREE(name);
+ return -1; /* skip warning here because setting was fine */
+ }
+ if (virLogAddOutputToFile(prio, abspath) == 0)
+ count++;
+ VIR_FREE(name);
+ VIR_FREE(abspath);
+ } else if (STREQLEN(cur, "journald", 8)) {
+ cur += 8;
+#if USE_JOURNALD
+ if (virLogAddOutputToJournald(prio) == 0)
+ count++;
+#endif /* USE_JOURNALD */
+ } else {
+ goto cleanup;
+ }
+ virSkipSpaces(&cur);
+ }
+ ret = count;
+cleanup:
+ if (ret == -1)
+ VIR_WARN("Ignoring invalid log output setting.");
+ return ret;
+}
+
+
+/**
+ * virLogParseFilters:
+ * @filters: string defining a (set of) filter(s)
+ *
+ * The format for a filter is:
+ * x:name
+ * where name is a match string
+ * the x prefix is the minimal level where the messages should be logged
+ * 1: DEBUG
+ * 2: INFO
+ * 3: WARNING
+ * 4: ERROR
+ *
+ * Multiple filter can be defined in a single @filters, they just need to be
+ * separated by spaces.
+ *
+ * Returns the number of filter parsed and installed or -1 in case of error
+ */
+int
+virLogParseFilters(const char *filters)
+{
+ const char *cur = filters, *str;
+ char *name;
+ virLogPriority prio;
+ int ret = -1;
+ int count = 0;
+
+ if (cur == NULL)
+ return -1;
+
+ virSkipSpaces(&cur);
+ while (*cur != 0) {
+ unsigned int flags = 0;
+ prio= virParseNumber(&cur);
+ if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
+ goto cleanup;
+ if (*cur != ':')
+ goto cleanup;
+ cur++;
+ if (*cur == '+') {
+ flags |= VIR_LOG_STACK_TRACE;
+ cur++;
+ }
+ str = cur;
+ while ((*cur != 0) && (!IS_SPACE(cur)))
+ cur++;
+ if (str == cur)
+ goto cleanup;
+ name = strndup(str, cur - str);
+ if (name == NULL)
+ goto cleanup;
+ if (virLogDefineFilter(name, prio, flags) >= 0)
+ count++;
+ VIR_FREE(name);
+ virSkipSpaces(&cur);
+ }
+ ret = count;
+cleanup:
+ if (ret == -1)
+ VIR_WARN("Ignoring invalid log filter setting.");
+ return ret;
+}
+
+
+/**
+ * virLogGetDefaultPriority:
+ *
+ * Returns the current logging priority level.
+ */
+virLogPriority
+virLogGetDefaultPriority(void)
+{
+ return virLogDefaultPriority;
+}
+
+
+/**
+ * virLogGetFilters:
+ *
+ * Returns a string listing the current filters, in the format originally
+ * specified in the config file or environment. Caller must free the
+ * result.
+ */
+char *
+virLogGetFilters(void)
+{
+ int i;
+ virBuffer filterbuf = VIR_BUFFER_INITIALIZER;
+
+ virLogLock();
+ for (i = 0; i < virLogNbFilters; i++) {
+ const char *sep = ":";
+ if (virLogFilters[i].flags & VIR_LOG_STACK_TRACE)
+ sep = ":+";
+ virBufferAsprintf(&filterbuf, "%d%s%s ",
+ virLogFilters[i].priority,
+ sep,
+ virLogFilters[i].match);
+ }
+ virLogUnlock();
+
+ if (virBufferError(&filterbuf)) {
+ virBufferFreeAndReset(&filterbuf);
+ return NULL;
+ }
+
+ return virBufferContentAndReset(&filterbuf);
+}
+
+
+/**
+ * virLogGetOutputs:
+ *
+ * Returns a string listing the current outputs, in the format originally
+ * specified in the config file or environment. Caller must free the
+ * result.
+ */
+char *
+virLogGetOutputs(void)
+{
+ int i;
+ virBuffer outputbuf = VIR_BUFFER_INITIALIZER;
+
+ virLogLock();
+ for (i = 0; i < virLogNbOutputs; i++) {
+ virLogDestination dest = virLogOutputs[i].dest;
+ if (i)
+ virBufferAsprintf(&outputbuf, " ");
+ switch (dest) {
+ case VIR_LOG_TO_SYSLOG:
+ case VIR_LOG_TO_FILE:
+ virBufferAsprintf(&outputbuf, "%d:%s:%s",
+ virLogOutputs[i].priority,
+ virLogOutputString(dest),
+ virLogOutputs[i].name);
+ break;
+ default:
+ virBufferAsprintf(&outputbuf, "%d:%s",
+ virLogOutputs[i].priority,
+ virLogOutputString(dest));
+ }
+ }
+ virLogUnlock();
+
+ if (virBufferError(&outputbuf)) {
+ virBufferFreeAndReset(&outputbuf);
+ return NULL;
+ }
+
+ return virBufferContentAndReset(&outputbuf);
+}
+
+
+/**
+ * virLogGetNbFilters:
+ *
+ * Returns the current number of defined log filters.
+ */
+int
+virLogGetNbFilters(void)
+{
+ return virLogNbFilters;
+}
+
+
+/**
+ * virLogGetNbOutputs:
+ *
+ * Returns the current number of defined log outputs.
+ */
+int
+virLogGetNbOutputs(void)
+{
+ return virLogNbOutputs;
+}
+
+
+/**
+ * virLogParseDefaultPriority:
+ * @priority: string defining the desired logging level
+ *
+ * Parses and sets the default log priority level. It can take a string or
+ * number corresponding to the following levels:
+ * 1: DEBUG
+ * 2: INFO
+ * 3: WARNING
+ * 4: ERROR
+ *
+ * Returns the parsed log level or -1 on error.
+ */
+int
+virLogParseDefaultPriority(const char *priority)
+{
+ int ret = -1;
+
+ if (STREQ(priority, "1") || STREQ(priority, "debug"))
+ ret = virLogSetDefaultPriority(VIR_LOG_DEBUG);
+ else if (STREQ(priority, "2") || STREQ(priority, "info"))
+ ret = virLogSetDefaultPriority(VIR_LOG_INFO);
+ else if (STREQ(priority, "3") || STREQ(priority, "warning"))
+ ret = virLogSetDefaultPriority(VIR_LOG_WARN);
+ else if (STREQ(priority, "4") || STREQ(priority, "error"))
+ ret = virLogSetDefaultPriority(VIR_LOG_ERROR);
+ else
+ VIR_WARN("Ignoring invalid log level setting");
+
+ return ret;
+}
+
+
+/**
+ * virLogSetFromEnv:
+ *
+ * Sets virLogDefaultPriority, virLogFilters and virLogOutputs based on
+ * environment variables.
+ */
+void
+virLogSetFromEnv(void)
+{
+ char *debugEnv;
+
+ debugEnv = getenv("LIBVIRT_DEBUG");
+ if (debugEnv && *debugEnv)
+ virLogParseDefaultPriority(debugEnv);
+ debugEnv = getenv("LIBVIRT_LOG_FILTERS");
+ if (debugEnv && *debugEnv)
+ virLogParseFilters(debugEnv);
+ debugEnv = getenv("LIBVIRT_LOG_OUTPUTS");
+ if (debugEnv && *debugEnv)
+ virLogParseOutputs(debugEnv);
+}
--- /dev/null
+/*
+ * virlog.h: internal logging and debugging
+ *
+ * Copyright (C) 2006-2008, 2011-2012 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __VIRTLOG_H_
+# define __VIRTLOG_H_
+
+# include "internal.h"
+# include "virbuffer.h"
+
+/*
+ * To be made public
+ */
+typedef enum {
+ VIR_LOG_DEBUG = 1,
+ VIR_LOG_INFO,
+ VIR_LOG_WARN,
+ VIR_LOG_ERROR,
+} virLogPriority;
+
+# define VIR_LOG_DEFAULT VIR_LOG_WARN
+
+typedef enum {
+ VIR_LOG_TO_STDERR = 1,
+ VIR_LOG_TO_SYSLOG,
+ VIR_LOG_TO_FILE,
+ VIR_LOG_TO_JOURNALD,
+} virLogDestination;
+
+typedef enum {
+ VIR_LOG_FROM_FILE,
+ VIR_LOG_FROM_ERROR,
+ VIR_LOG_FROM_AUDIT,
+ VIR_LOG_FROM_TRACE,
+ VIR_LOG_FROM_LIBRARY,
+
+ VIR_LOG_FROM_LAST,
+} virLogSource;
+
+/*
+ * If configured with --enable-debug=yes then library calls
+ * are printed to stderr for debugging or to an appropriate channel
+ * defined at runtime from the libvirt daemon configuration file
+ */
+# ifdef ENABLE_DEBUG
+# define VIR_DEBUG_INT(src, filename, linenr, funcname, ...) \
+ virLogMessage(src, VIR_LOG_DEBUG, filename, linenr, funcname, NULL, __VA_ARGS__)
+# else
+/**
+ * virLogEatParams:
+ *
+ * Do nothing but eat parameters.
+ */
+static inline void virLogEatParams(virLogSource unused, ...)
+{
+ /* Silence gcc */
+ unused = unused;
+}
+# define VIR_DEBUG_INT(src, filename, linenr, funcname, ...) \
+ virLogEatParams(src, filename, linenr, funcname, __VA_ARGS__)
+# endif /* !ENABLE_DEBUG */
+
+# define VIR_INFO_INT(src, filename, linenr, funcname, ...) \
+ virLogMessage(src, VIR_LOG_INFO, filename, linenr, funcname, NULL, __VA_ARGS__)
+# define VIR_WARN_INT(src, filename, linenr, funcname, ...) \
+ virLogMessage(src, VIR_LOG_WARN, filename, linenr, funcname, NULL, __VA_ARGS__)
+# define VIR_ERROR_INT(src, filename, linenr, funcname, ...) \
+ virLogMessage(src, VIR_LOG_ERROR, filename, linenr, funcname, NULL, __VA_ARGS__)
+
+# define VIR_DEBUG(...) \
+ VIR_DEBUG_INT(VIR_LOG_FROM_FILE, __FILE__, __LINE__, __func__, __VA_ARGS__)
+# define VIR_INFO(...) \
+ VIR_INFO_INT(VIR_LOG_FROM_FILE, __FILE__, __LINE__, __func__, __VA_ARGS__)
+# define VIR_WARN(...) \
+ VIR_WARN_INT(VIR_LOG_FROM_FILE, __FILE__, __LINE__, __func__, __VA_ARGS__)
+# define VIR_ERROR(...) \
+ VIR_ERROR_INT(VIR_LOG_FROM_FILE, __FILE__, __LINE__, __func__, __VA_ARGS__)
+
+
+struct _virLogMetadata {
+ const char *key;
+ const char *s; /* String value, or NULL to use "i" */
+ int i;
+};
+
+typedef struct _virLogMetadata virLogMetadata;
+typedef struct _virLogMetadata *virLogMetadataPtr;
+
+/**
+ * virLogOutputFunc:
+ * @src: the src for the message
+ * @priority: the priority for the message
+ * @filename: file where the message was emitted
+ * @linenr: line where the message was emitted
+ * @funcname: the function emitting the message
+ * @timestamp: zero terminated string with timestamp of the message
+ * @metadata: NULL or metadata array, terminated by an item with NULL key
+ * @flags: flags associated with the message
+ * @rawstr: the unformatted message to log, zero terminated
+ * @str: the message to log, preformatted and zero terminated
+ * @data: extra output logging data
+ *
+ * Callback function used to output messages
+ */
+typedef void (*virLogOutputFunc) (virLogSource src,
+ virLogPriority priority,
+ const char *filename,
+ int linenr,
+ const char *funcname,
+ const char *timestamp,
+ virLogMetadataPtr metadata,
+ unsigned int flags,
+ const char *rawstr,
+ const char *str,
+ void *data);
+
+/**
+ * virLogCloseFunc:
+ * @data: extra output logging data
+ *
+ * Callback function used to close a log output
+ */
+typedef void (*virLogCloseFunc) (void *data);
+
+typedef enum {
+ VIR_LOG_STACK_TRACE = (1 << 0),
+} virLogFlags;
+
+extern int virLogGetNbFilters(void);
+extern int virLogGetNbOutputs(void);
+extern char *virLogGetFilters(void);
+extern char *virLogGetOutputs(void);
+extern virLogPriority virLogGetDefaultPriority(void);
+extern int virLogSetDefaultPriority(virLogPriority priority);
+extern void virLogSetFromEnv(void);
+extern int virLogDefineFilter(const char *match,
+ virLogPriority priority,
+ unsigned int flags);
+extern int virLogDefineOutput(virLogOutputFunc f,
+ virLogCloseFunc c,
+ void *data,
+ virLogPriority priority,
+ virLogDestination dest,
+ const char *name,
+ unsigned int flags);
+
+/*
+ * Internal logging API
+ */
+
+extern void virLogLock(void);
+extern void virLogUnlock(void);
+extern int virLogReset(void);
+extern int virLogParseDefaultPriority(const char *priority);
+extern int virLogParseFilters(const char *filters);
+extern int virLogParseOutputs(const char *output);
+extern void virLogMessage(virLogSource src,
+ virLogPriority priority,
+ const char *filename,
+ int linenr,
+ const char *funcname,
+ virLogMetadataPtr metadata,
+ const char *fmt, ...) ATTRIBUTE_FMT_PRINTF(7, 8);
+extern void virLogVMessage(virLogSource src,
+ virLogPriority priority,
+ const char *filename,
+ int linenr,
+ const char *funcname,
+ virLogMetadataPtr metadata,
+ const char *fmt,
+ va_list vargs) ATTRIBUTE_FMT_PRINTF(7, 0);
+extern int virLogSetBufferSize(int size);
+extern void virLogEmergencyDumpAll(int signum);
+#endif
#include "vircommand.h"
#include "memory.h"
#include "pci.h"
-#include "logging.h"
+#include "virlog.h"
#include <sys/ioctl.h>
#include <net/if.h>
# endif
# include "memory.h"
-# include "logging.h"
+# include "virlog.h"
# include "uuid.h"
# include "virfile.h"
# include "virnetlink.h"
#include "virfile.h"
#include "virterror_internal.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "util.h"
#include <sys/ioctl.h>
#include "virnetdevveth.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "vircommand.h"
#include "virterror_internal.h"
# include "virnetlink.h"
# include "virfile.h"
-# include "logging.h"
+# include "virlog.h"
# include "virnetdev.h"
# define MICROSEC_PER_SEC (1000 * 1000)
#include <sys/socket.h>
#include "virnetlink.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "threads.h"
#include "virmacaddr.h"
#include "datatypes.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#define VIR_FROM_THIS VIR_FROM_NONE
#include "memory.h"
#include "viratomic.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#define VIR_FROM_THIS VIR_FROM_NONE
#include "memory.h"
#include "util.h"
#include "intprops.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "c-ctype.h"
#include "areadlink.h"
#include "virprocess.h"
#include "virterror_internal.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "util.h"
#define VIR_FROM_THIS VIR_FROM_NONE
#include "count-one-bits.h"
#include "util.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#define VIR_FROM_THIS VIR_FROM_NONE
#include "virterror_internal.h"
#include "datatypes.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "threads.h"
#include "util.h"
#include <unistd.h>
#include "virusb.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
#include "util.h"
#include "virterror_internal.h"
#include "internal.h"
#include "memory.h"
#include "util.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "vbox_MSCOMGlue.h"
#include "internal.h"
#include "memory.h"
#include "util.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#define VIR_FROM_THIS VIR_FROM_VBOX
#include "internal.h"
#include "datatypes.h"
-#include "logging.h"
+#include "virlog.h"
#include "vbox_driver.h"
#include "vbox_glue.h"
#include "virterror_internal.h"
#include "uuid.h"
#include "memory.h"
#include "nodeinfo.h"
-#include "logging.h"
+#include "virlog.h"
#include "vbox_driver.h"
#include "configmake.h"
#include "virfile.h"
#include "virterror_internal.h"
#include "virconf.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "vmx.h"
#include "viruri.h"
#include <xen/dom0_ops.h>
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "datatypes.h"
#include "xen_driver.h"
#include <xen/sched.h>
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "datatypes.h"
#include "driver.h"
#include "util.h"
#include "domain_conf.h"
#include "xen_inotify.h"
#include "xend_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "virfile.h"
#include <errno.h>
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "datatypes.h"
#include "xend_internal.h"
#include "driver.h"
#include "uuid.h"
#include "util.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "count-one-bits.h"
#define VIR_FROM_THIS VIR_FROM_XENXM
#include "datatypes.h"
#include "driver.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "uuid.h"
#include "xen_driver.h"
#include "xs_internal.h"
#include "uuid.h"
#include "memory.h"
#include "virbuffer.h"
-#include "logging.h"
+#include "virlog.h"
#include "viruri.h"
#include "xenapi_driver_private.h"
#include "xenapi_utils.h"
#include "memory.h"
#include "verify.h"
#include "uuid.h"
-#include "logging.h"
+#include "virlog.h"
#include "count-one-bits.h"
#include "xenxs_private.h"
#include "xen_sxpr.h"
#include "testutils.h"
#include "internal.h"
#include "threads.h"
-#include "logging.h"
+#include "virlog.h"
#include "util.h"
#include "vireventpoll.h"
#include "util.h"
#include "c-ctype.h"
#include "virterror_internal.h"
-#include "logging.h"
+#include "virlog.h"
#include "virconf.h"
#define VIR_FROM_THIS VIR_FROM_NONE
#include "rpc/virnetsocket.h"
#include "memory.h"
#include "util.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#define VIR_FROM_THIS VIR_FROM_NONE
#include "testutils.h"
#include "memory.h"
#include "util.h"
-#include "logging.h"
+#include "virlog.h"
#include "virterror_internal.h"
#include "security/security_manager.h"
#include "virsocketaddr.h"
#include "testutils.h"
-#include "logging.h"
+#include "virlog.h"
#include "memory.h"
static void testQuietError(void *userData ATTRIBUTE_UNUSED,
#include "threads.h"
#include "virterror_internal.h"
#include "virbuffer.h"
-#include "logging.h"
+#include "virlog.h"
#include "vircommand.h"
#include "virrandom.h"
#include "dirname.h"
#include "util.h"
#include "virterror_internal.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virauthconfig.h"
#include "util.h"
#include "virterror_internal.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "driver.h"
#define VIR_FROM_THIS VIR_FROM_NONE
#include "testutils.h"
#include "memory.h"
#include "util.h"
-#include "logging.h"
+#include "virlog.h"
#define testError(...) \
#include "util.h"
#include "virterror_internal.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virkeyfile.h"
#include "util.h"
#include "virterror_internal.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virlockspace.h"
#include "util.h"
#include "virterror_internal.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "rpc/virnetmessage.h"
#include "util.h"
#include "virterror_internal.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#include "rpc/virnetsocket.h"
#include "util.h"
#include "virterror_internal.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virfile.h"
#include "vircommand.h"
#include "virsocketaddr.h"
#include "util.h"
#include "virterror_internal.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virstring.h"
#include "util.h"
#include "virterror_internal.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "virtime.h"
#include "util.h"
#include "virterror_internal.h"
#include "memory.h"
-#include "logging.h"
+#include "virlog.h"
#include "viruri.h"
# include "internal.h"
# include "console.h"
-# include "logging.h"
+# include "virlog.h"
# include "util.h"
# include "virfile.h"
# include "memory.h"